Skip to content

Commit c6b6dfa

Browse files
committed
strokeWidth as a channel, on all marks
closes #311
1 parent 5670bbf commit c6b6dfa

File tree

10 files changed

+80
-29
lines changed

10 files changed

+80
-29
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,6 @@ All marks support the following style options:
459459
* **fill** - fill color
460460
* **fillOpacity** - fill opacity (a number between 0 and 1)
461461
* **stroke** - stroke color
462-
* **strokeWidth** - stroke width (in pixels)
463462
* **strokeOpacity** - stroke opacity (a number between 0 and 1)
464463
* **strokeLinejoin** - how to join lines (*bevel*, *miter*, *miter-clip*, or *round*)
465464
* **strokeLinecap** - how to cap lines (*butt*, *round*, or *square*)
@@ -474,6 +473,7 @@ All marks support the following optional channels:
474473
* **fillOpacity** - a fill opacity; bound to the *opacity* scale
475474
* **stroke** - a stroke color; bound to the *color* scale
476475
* **strokeOpacity** - a stroke opacity; bound to the *opacity* scale
476+
* **strokeWidth** - stroke width (in pixels)
477477
* **title** - a tooltip (a string of text, possibly with newlines)
478478

479479
The **fill**, **fillOpacity**, **stroke**, and **strokeOpacity** options can be specified as either channels or constants. When the fill or stroke is specified as a function or array, it is interpreted as a channel; when the fill or stroke is specified as a string, it is interpreted as a constant if a valid CSS color and otherwise it is interpreted as a column name for a channel. Similarly when the fill or stroke opacity is specified as a number, it is interpreted as a constant; otherwise it is interpeted as a channel. When the radius is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel.

src/marks/area.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ export class Area extends Mark {
2121
fillOpacity,
2222
stroke,
2323
strokeOpacity,
24+
strokeWidth,
2425
curve,
2526
tension,
2627
...options
2728
} = {}
2829
) {
2930
const [vstroke, cstroke] = maybeColor(stroke, "none");
3031
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
32+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
3133
const [vfill, cfill] = maybeColor(fill, cstroke === "none" ? "currentColor" : "none");
3234
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
3335
if (z === undefined && vfill != null) z = vfill;
@@ -44,7 +46,8 @@ export class Area extends Mark {
4446
{name: "fill", value: vfill, scale: "color", optional: true},
4547
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
4648
{name: "stroke", value: vstroke, scale: "color", optional: true},
47-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
49+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
50+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
4851
],
4952
options
5053
);
@@ -53,12 +56,13 @@ export class Area extends Mark {
5356
fill: cfill,
5457
fillOpacity: cfillOpacity,
5558
stroke: cstroke,
59+
strokeWidth: cstrokeWidth,
5660
strokeMiterlimit: cstroke === "none" ? undefined : 1,
5761
strokeOpacity: cstrokeOpacity,
5862
...options
5963
});
6064
}
61-
render(I, {x, y}, {x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) {
65+
render(I, {x, y}, {x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}) {
6266
return create("svg:g")
6367
.call(applyIndirectStyles, this)
6468
.call(applyTransform, x, y)
@@ -70,6 +74,7 @@ export class Area extends Mark {
7074
.call(applyAttr, "fill-opacity", FO && (([i]) => FO[i]))
7175
.call(applyAttr, "stroke", S && (([i]) => S[i]))
7276
.call(applyAttr, "stroke-opacity", SO && (([i]) => SO[i]))
77+
.call(applyAttr, "stroke-width", SW && (([i]) => SW[i]))
7378
.attr("d", shapeArea()
7479
.curve(this.curve)
7580
.defined(i => defined(X1[i]) && defined(Y1[i]) && defined(X2[i]) && defined(Y2[i]))

src/marks/bar.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class AbstractBar extends Mark {
1414
fillOpacity,
1515
stroke,
1616
strokeOpacity,
17+
strokeWidth,
1718
inset = 0,
1819
insetTop = inset,
1920
insetRight = inset,
@@ -26,6 +27,7 @@ export class AbstractBar extends Mark {
2627
) {
2728
const [vstroke, cstroke] = maybeColor(stroke, "none");
2829
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
30+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
2931
const [vfill, cfill] = maybeColor(fill, cstroke === "none" ? "currentColor" : "none");
3032
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
3133
super(
@@ -36,7 +38,8 @@ export class AbstractBar extends Mark {
3638
{name: "fill", value: vfill, scale: "color", optional: true},
3739
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
3840
{name: "stroke", value: vstroke, scale: "color", optional: true},
39-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
41+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
42+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
4043
],
4144
options
4245
);
@@ -45,6 +48,7 @@ export class AbstractBar extends Mark {
4548
fillOpacity: cfillOpacity,
4649
stroke: cstroke,
4750
strokeOpacity: cstrokeOpacity,
51+
strokeWidth: cstrokeWidth,
4852
...options
4953
});
5054
this.insetTop = number(insetTop);
@@ -56,8 +60,8 @@ export class AbstractBar extends Mark {
5660
}
5761
render(I, scales, channels, dimensions) {
5862
const {rx, ry} = this;
59-
const {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO} = channels;
60-
const index = filter(I, ...this._positions(channels), F, FO, S, SO);
63+
const {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW} = channels;
64+
const index = filter(I, ...this._positions(channels), F, FO, S, SO, SW);
6165
return create("svg:g")
6266
.call(applyIndirectStyles, this)
6367
.call(this._transform, scales)
@@ -73,6 +77,7 @@ export class AbstractBar extends Mark {
7377
.call(applyAttr, "fill-opacity", FO && (i => FO[i]))
7478
.call(applyAttr, "stroke", S && (i => S[i]))
7579
.call(applyAttr, "stroke-opacity", SO && (i => SO[i]))
80+
.call(applyAttr, "stroke-width", SW && (i => SW[i]))
7681
.call(applyAttr, "rx", rx)
7782
.call(applyAttr, "ry", ry)
7883
.call(title(L)))

src/marks/dot.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class Dot extends Mark {
1515
fillOpacity,
1616
stroke,
1717
strokeOpacity,
18+
strokeWidth,
1819
...options
1920
} = {}
2021
) {
@@ -23,6 +24,7 @@ export class Dot extends Mark {
2324
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
2425
const [vstroke, cstroke] = maybeColor(stroke, cfill === "none" ? "currentColor" : "none");
2526
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
27+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
2628
super(
2729
data,
2830
[
@@ -33,7 +35,8 @@ export class Dot extends Mark {
3335
{name: "fill", value: vfill, scale: "color", optional: true},
3436
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
3537
{name: "stroke", value: vstroke, scale: "color", optional: true},
36-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
38+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
39+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
3740
],
3841
options
3942
);
@@ -43,17 +46,17 @@ export class Dot extends Mark {
4346
fillOpacity: cfillOpacity,
4447
stroke: cstroke,
4548
strokeOpacity: cstrokeOpacity,
46-
strokeWidth: cstroke === "none" ? undefined : 1.5,
49+
strokeWidth: cstrokeWidth === undefined ? cstroke === "none" ? undefined : 1.5 : cstrokeWidth,
4750
...options
4851
});
4952
}
5053
render(
5154
I,
5255
{x, y},
53-
{x: X, y: Y, r: R, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO},
56+
{x: X, y: Y, r: R, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW},
5457
{width, height, marginTop, marginRight, marginBottom, marginLeft}
5558
) {
56-
let index = filter(I, X, Y, F, FO, S, SO);
59+
let index = filter(I, X, Y, F, FO, S, SO, SW);
5760
if (R) index = index.filter(i => positive(R[i]));
5861
return create("svg:g")
5962
.call(applyIndirectStyles, this)
@@ -69,6 +72,7 @@ export class Dot extends Mark {
6972
.call(applyAttr, "fill-opacity", FO && (i => FO[i]))
7073
.call(applyAttr, "stroke", S && (i => S[i]))
7174
.call(applyAttr, "stroke-opacity", SO && (i => SO[i]))
75+
.call(applyAttr, "stroke-width", SW && (i => SW[i]))
7276
.call(title(L)))
7377
.node();
7478
}

src/marks/line.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class Line extends Mark {
1818
fillOpacity,
1919
stroke,
2020
strokeOpacity,
21+
strokeWidth,
2122
curve,
2223
tension,
2324
...options
@@ -27,6 +28,7 @@ export class Line extends Mark {
2728
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
2829
const [vstroke, cstroke] = maybeColor(stroke, "currentColor");
2930
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
31+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
3032
if (z === undefined && vstroke != null) z = vstroke;
3133
if (z === undefined && vfill != null) z = vfill;
3234
super(
@@ -39,7 +41,8 @@ export class Line extends Mark {
3941
{name: "fill", value: vfill, scale: "color", optional: true},
4042
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
4143
{name: "stroke", value: vstroke, scale: "color", optional: true},
42-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
44+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
45+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
4346
],
4447
options
4548
);
@@ -50,11 +53,11 @@ export class Line extends Mark {
5053
stroke: cstroke,
5154
strokeMiterlimit: cstroke === "none" ? undefined : 1,
5255
strokeOpacity: cstrokeOpacity,
53-
strokeWidth: cstroke === "none" ? undefined : 1.5,
56+
strokeWidth: cstrokeWidth === undefined ? cstroke === "none" ? undefined : 1.5 : cstrokeWidth,
5457
...options
5558
});
5659
}
57-
render(I, {x, y}, {x: X, y: Y, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) {
60+
render(I, {x, y}, {x: X, y: Y, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}) {
5861
return create("svg:g")
5962
.call(applyIndirectStyles, this)
6063
.call(applyTransform, x, y, 0.5, 0.5)
@@ -66,6 +69,7 @@ export class Line extends Mark {
6669
.call(applyAttr, "fill-opacity", FO && (([i]) => FO[i]))
6770
.call(applyAttr, "stroke", S && (([i]) => S[i]))
6871
.call(applyAttr, "stroke-opacity", SO && (([i]) => SO[i]))
72+
.call(applyAttr, "stroke-width", SW && (([i]) => SW[i]))
6973
.attr("d", shapeLine()
7074
.curve(this.curve)
7175
.defined(i => defined(X[i]) && defined(Y[i]))

src/marks/link.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class Link extends Mark {
1717
fillOpacity,
1818
stroke,
1919
strokeOpacity,
20+
strokeWidth,
2021
curve,
2122
...options
2223
} = {}
@@ -25,6 +26,7 @@ export class Link extends Mark {
2526
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
2627
const [vstroke, cstroke] = maybeColor(stroke, "currentColor");
2728
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
29+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
2830
super(
2931
data,
3032
[
@@ -36,7 +38,8 @@ export class Link extends Mark {
3638
{name: "fill", value: vfill, scale: "color", optional: true},
3739
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
3840
{name: "stroke", value: vstroke, scale: "color", optional: true},
39-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
41+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
42+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
4043
],
4144
options
4245
);
@@ -47,15 +50,16 @@ export class Link extends Mark {
4750
stroke: cstroke,
4851
strokeMiterlimit: cstroke === "none" ? undefined : 1,
4952
strokeOpacity: cstrokeOpacity,
53+
strokeWidth: cstrokeWidth,
5054
...options
5155
});
5256
}
5357
render(
5458
I,
5559
{x, y},
56-
{x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, title: L, stroke: S, strokeOpacity: SO}
60+
{x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, title: L, stroke: S, strokeOpacity: SO, strokeWidth: SW}
5761
) {
58-
const index = filter(I, X1, Y1, X2, Y2, S, SO);
62+
const index = filter(I, X1, Y1, X2, Y2, S, SO, SW);
5963
return create("svg:g")
6064
.call(applyIndirectStyles, this)
6165
.call(applyTransform, x, y, 0.5, 0.5)
@@ -74,6 +78,7 @@ export class Link extends Mark {
7478
})
7579
.call(applyAttr, "stroke", S && (i => S[i]))
7680
.call(applyAttr, "stroke-opacity", SO && (i => SO[i]))
81+
.call(applyAttr, "stroke-width", SW && (i => SW[i]))
7782
.call(title(L)))
7883
.node();
7984
}

src/marks/rect.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class Rect extends Mark {
1717
fillOpacity,
1818
stroke,
1919
strokeOpacity,
20+
strokeWidth,
2021
inset = 0,
2122
insetTop = inset,
2223
insetRight = inset,
@@ -29,6 +30,7 @@ export class Rect extends Mark {
2930
) {
3031
const [vstroke, cstroke] = maybeColor(stroke, "none");
3132
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
33+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
3234
const [vfill, cfill] = maybeColor(fill, cstroke === "none" ? "currentColor" : "none");
3335
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
3436
super(
@@ -42,7 +44,8 @@ export class Rect extends Mark {
4244
{name: "fill", value: vfill, scale: "color", optional: true},
4345
{name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true},
4446
{name: "stroke", value: vstroke, scale: "color", optional: true},
45-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
47+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
48+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
4649
],
4750
options
4851
);
@@ -51,6 +54,7 @@ export class Rect extends Mark {
5154
fillOpacity: cfillOpacity,
5255
stroke: cstroke,
5356
strokeOpacity: cstrokeOpacity,
57+
strokeWidth: cstrokeWidth,
5458
...options
5559
});
5660
this.insetTop = number(insetTop);
@@ -63,10 +67,10 @@ export class Rect extends Mark {
6367
render(
6468
I,
6569
{x, y},
66-
{x1: X1, y1: Y1, x2: X2, y2: Y2, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}
70+
{x1: X1, y1: Y1, x2: X2, y2: Y2, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}
6771
) {
6872
const {rx, ry} = this;
69-
const index = filter(I, X1, Y2, X2, Y2, F, FO, S, SO);
73+
const index = filter(I, X1, Y2, X2, Y2, F, FO, S, SO, SW);
7074
return create("svg:g")
7175
.call(applyIndirectStyles, this)
7276
.call(applyTransform, x, y)
@@ -82,6 +86,7 @@ export class Rect extends Mark {
8286
.call(applyAttr, "fill-opacity", FO && (i => FO[i]))
8387
.call(applyAttr, "stroke", S && (i => S[i]))
8488
.call(applyAttr, "stroke-opacity", SO && (i => SO[i]))
89+
.call(applyAttr, "stroke-width", SW && (i => SW[i]))
8590
.call(applyAttr, "rx", rx)
8691
.call(applyAttr, "ry", ry)
8792
.call(title(L)))

src/marks/rule.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export class RuleX extends Mark {
1313
title,
1414
stroke,
1515
strokeOpacity,
16+
strokeWidth,
1617
inset = 0,
1718
insetTop = inset,
1819
insetBottom = inset,
@@ -21,6 +22,7 @@ export class RuleX extends Mark {
2122
) {
2223
const [vstroke, cstroke] = maybeColor(stroke, "currentColor");
2324
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
25+
const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
2426
super(
2527
data,
2628
[
@@ -29,21 +31,27 @@ export class RuleX extends Mark {
2931
{name: "y2", value: y2, scale: "y", optional: true},
3032
{name: "title", value: title, optional: true},
3133
{name: "stroke", value: vstroke, scale: "color", optional: true},
32-
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}
34+
{name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true},
35+
{name: "strokeWidth", value: vstrokeWidth, optional: true}
3336
],
3437
options
3538
);
36-
Style(this, {stroke: cstroke, strokeOpacity: cstrokeOpacity, ...options});
39+
Style(this, {
40+
stroke: cstroke,
41+
strokeOpacity: cstrokeOpacity,
42+
strokeWidth: cstrokeWidth,
43+
...options
44+
});
3745
this.insetTop = number(insetTop);
3846
this.insetBottom = number(insetBottom);
3947
}
4048
render(
4149
I,
4250
{x, y},
43-
{x: X, y1: Y1, y2: Y2, title: L, stroke: S, strokeOpacity: SO},
51+
{x: X, y1: Y1, y2: Y2, title: L, stroke: S, strokeOpacity: SO, strokeWidth: SW},
4452
{width, height, marginTop, marginRight, marginLeft, marginBottom}
4553
) {
46-
const index = filter(I, X, Y1, Y2, S);
54+
const index = filter(I, X, Y1, Y2, S, SO, SW);
4755
return create("svg:g")
4856
.call(applyIndirectStyles, this)
4957
.call(applyTransform, X && x, null, 0.5, 0)
@@ -57,6 +65,7 @@ export class RuleX extends Mark {
5765
.attr("y2", Y2 ? (y.bandwidth ? i => Y2[i] + y.bandwidth() - this.insetBottom : i => Y2[i] - this.insetBottom) : height - marginBottom - this.insetBottom)
5866
.call(applyAttr, "stroke", S && (i => S[i]))
5967
.call(applyAttr, "stroke-opacity", SO && (i => SO[i]))
68+
.call(applyAttr, "stroke-width", SW && (i => SW[i]))
6069
.call(title(L)))
6170
.node();
6271
}

0 commit comments

Comments
 (0)