diff --git a/README.md b/README.md index a397cdbeac..e41d3b1427 100644 --- a/README.md +++ b/README.md @@ -474,9 +474,10 @@ All marks support the following optional channels: * **fillOpacity** - a fill opacity; bound to the *opacity* scale * **stroke** - a stroke color; bound to the *color* scale * **strokeOpacity** - a stroke opacity; bound to the *opacity* scale +* **strokeWidth** - a stroke width (in pixels) * **title** - a tooltip (a string of text, possibly with newlines) -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. +The **fill**, **fillOpacity**, **stroke**, **strokeWidth**, 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 or the stroke width is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. When the radius is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. The rectangular marks ([bar](#bar), [cell](#cell), and [rect](#rect)) support insets and rounded corner constant options: diff --git a/src/style.js b/src/style.js index e71aba7f0b..acf26c2251 100644 --- a/src/style.js +++ b/src/style.js @@ -58,6 +58,8 @@ export function styles( if (strokeMiterlimit === undefined) strokeMiterlimit = defaultStrokeMiterlimit; } + const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth); + // Some marks don’t support fill (e.g., tick and rule). if (defaultFill !== null) { mark.fill = impliedString(cfill, "currentColor"); @@ -65,7 +67,7 @@ export function styles( } mark.stroke = impliedString(cstroke, "none"); - mark.strokeWidth = impliedNumber(strokeWidth, 1); + mark.strokeWidth = impliedNumber(cstrokeWidth, 1); mark.strokeOpacity = impliedNumber(cstrokeOpacity, 1); mark.strokeLinejoin = impliedString(strokeLinejoin, "miter"); mark.strokeLinecap = impliedString(strokeLinecap, "butt"); @@ -80,23 +82,26 @@ export function styles( {name: "fill", value: vfill, scale: "color", optional: true}, {name: "fillOpacity", value: vfillOpacity, scale: "opacity", optional: true}, {name: "stroke", value: vstroke, scale: "color", optional: true}, - {name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true} + {name: "strokeOpacity", value: vstrokeOpacity, scale: "opacity", optional: true}, + {name: "strokeWidth", value: vstrokeWidth, optional: true} ]; } -export function applyChannelStyles(selection, {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) { +export function applyChannelStyles(selection, {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}) { applyAttr(selection, "fill", F && (i => F[i])); applyAttr(selection, "fill-opacity", FO && (i => FO[i])); applyAttr(selection, "stroke", S && (i => S[i])); applyAttr(selection, "stroke-opacity", SO && (i => SO[i])); + applyAttr(selection, "stroke-width", SW && (i => SW[i])); title(L)(selection); } -export function applyGroupedChannelStyles(selection, {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) { +export function applyGroupedChannelStyles(selection, {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}) { applyAttr(selection, "fill", F && (([i]) => F[i])); applyAttr(selection, "fill-opacity", FO && (([i]) => FO[i])); applyAttr(selection, "stroke", S && (([i]) => S[i])); applyAttr(selection, "stroke-opacity", SO && (([i]) => SO[i])); + applyAttr(selection, "stroke-width", SW && (i => SW[i])); titleGroup(L)(selection); } @@ -141,8 +146,8 @@ export function impliedNumber(value, impliedValue) { if ((value = number(value)) !== impliedValue) return value; } -export function filterStyles(index, {fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) { - return filter(index, F, FO, S, SO); +export function filterStyles(index, {fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO, strokeWidth: SW}) { + return filter(index, F, FO, S, SO, SW); } function none(color) {