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
})
]