diff --git a/README.md b/README.md index 5bcaf9f771..49ecf1e390 100644 --- a/README.md +++ b/README.md @@ -1087,6 +1087,7 @@ The following text-specific constant options are also supported: * **fontVariant** - the [font variant](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant); defaults to normal * **fontWeight** - the [font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight); defaults to normal * **rotate** - the rotation angle in degrees clockwise; defaults to 0 +* **halo** - adds a white halo beneath each text, with a 4px white stroke For text marks, the **dx** and **dy** options can be specified either as numbers representing pixels or as a string including units. For example, `"1em"` shifts the text by one [em](https://en.wikipedia.org/wiki/Em_(typography)), which is proportional to the **fontSize**. The **fontSize** and **rotate** options can be specified as either channels or constants. When fontSize or rotate is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. diff --git a/src/marks/text.js b/src/marks/text.js index 5b1fc41703..3723f90874 100644 --- a/src/marks/text.js +++ b/src/marks/text.js @@ -20,6 +20,7 @@ export class Text extends Mark { fontStyle, fontVariant, fontWeight, + halo, dx, dy = "0.32em", rotate @@ -47,11 +48,12 @@ export class Text extends Mark { this.fontWeight = string(fontWeight); this.dx = string(dx); this.dy = string(dy); + this.halo = !!halo; } render(index, {x, y}, channels, dimensions) { const {x: X, y: Y, rotate: R, text: T, fontSize: FS} = channels; const {width, height, marginTop, marginRight, marginBottom, marginLeft} = dimensions; - const {rotate} = this; + const {rotate, halo} = this; const cx = (marginLeft + width - marginRight) / 2; const cy = (marginTop + height - marginBottom) / 2; return create("svg:g") @@ -73,6 +75,11 @@ export class Text extends Mark { .call(applyAttr, "font-size", FS && (i => FS[i])) .call(applyText, T) .call(applyChannelStyles, this, channels)) + .call(!halo ? () => {} : g => g.selectAll("text") + .call(text => text.clone(true)) + .attr("stroke-width", 4) + .attr("fill", "none") + .attr("stroke", "white")) .node(); } } diff --git a/test/output/metroInequalityChange.svg b/test/output/metroInequalityChange.svg index f6fe6f40c9..e9ce00ce6c 100644 --- a/test/output/metroInequalityChange.svg +++ b/test/output/metroInequalityChange.svg @@ -333,5 +333,5 @@ - New YorkChicagoHoustonWashington, D.C.San FranciscoSan JoseFairfield, Conn.Binghamton, N.Y. + New YorkNew YorkChicagoChicagoHoustonHoustonWashington, D.C.Washington, D.C.San FranciscoSan FranciscoSan JoseSan JoseFairfield, Conn.Fairfield, Conn.Binghamton, N.Y.Binghamton, N.Y. \ No newline at end of file diff --git a/test/plots/metro-inequality-change.js b/test/plots/metro-inequality-change.js index 7f7afc2a75..f4e5def1a0 100644 --- a/test/plots/metro-inequality-change.js +++ b/test/plots/metro-inequality-change.js @@ -31,6 +31,7 @@ export default async function() { x: "POP_2015", y: "R90_10_2015", text: d => d.highlight && d.nyt_display, + halo: true, dy: -6 }) ]