Skip to content

Commit 65ebe0c

Browse files
mbostockFil
andauthored
better fontSize disambiguation (#679)
* better fontSize disambiguation * Update src/marks/text.js Co-authored-by: Philippe Rivière <fil@rezo.net> Co-authored-by: Philippe Rivière <fil@rezo.net>
1 parent 60a54ca commit 65ebe0c

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

src/marks/text.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ export class Text extends Mark {
2525
rotate
2626
} = options;
2727
const [vrotate, crotate] = maybeNumberChannel(rotate, 0);
28-
const [vfontSize, cfontSize] = maybeNumberChannel(fontSize);
28+
const [vfontSize, cfontSize] = maybeFontSizeChannel(fontSize);
2929
super(
3030
data,
3131
[
3232
{name: "x", value: x, scale: "x", optional: true},
3333
{name: "y", value: y, scale: "y", optional: true},
34-
{name: "fontSize", value: numberChannel(vfontSize), optional: true},
34+
{name: "fontSize", value: vfontSize, optional: true},
3535
{name: "rotate", value: numberChannel(vrotate), optional: true},
3636
{name: "text", value: text, filter: nonempty}
3737
],
@@ -105,3 +105,39 @@ function applyDirectTextStyles(selection, mark) {
105105
applyAttr(selection, "dx", mark.dx);
106106
applyAttr(selection, "dy", mark.dy);
107107
}
108+
109+
// https://developer.mozilla.org/en-US/docs/Web/CSS/font-size
110+
const fontSizes = new Set([
111+
// global keywords
112+
"inherit",
113+
"initial",
114+
"revert",
115+
"unset",
116+
// absolute keywords
117+
"xx-small",
118+
"x-small",
119+
"small",
120+
"medium",
121+
"large",
122+
"x-large",
123+
"xx-large",
124+
"xxx-large",
125+
// relative keywords
126+
"larger",
127+
"smaller"
128+
]);
129+
130+
// The font size may be expressed as a constant in the following forms:
131+
// - number in pixels
132+
// - string keyword: see above
133+
// - string <length>: e.g., "12px"
134+
// - string <percentage>: e.g., "80%"
135+
// Anything else is assumed to be a channel definition.
136+
function maybeFontSizeChannel(fontSize) {
137+
if (fontSize == null || typeof fontSize === "number") return [undefined, fontSize];
138+
if (typeof fontSize !== "string") return [fontSize, undefined];
139+
fontSize = fontSize.trim().toLowerCase();
140+
return fontSizes.has(fontSize) || /^[+-]?\d*\.?\d+(e[+-]?\d+)?(\w*|%)$/.test(fontSize)
141+
? [undefined, fontSize]
142+
: [fontSize, undefined];
143+
}

test/marks/text-test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,21 @@ it("text(data, {stroke}) has a default strokeLinejoin of round", () => {
5656
assert.strictEqual(text.stroke, "red");
5757
assert.strictEqual(text.strokeLinejoin, "round");
5858
});
59+
60+
it("text(data, {fontSize}) allows fontSize to be a number, length, keyword, or percentage", () => {
61+
assert.strictEqual(Plot.text(undefined, {fontSize: 42}).fontSize, 42);
62+
assert.strictEqual(Plot.text(undefined, {fontSize: "42"}).fontSize, "42");
63+
assert.strictEqual(Plot.text(undefined, {fontSize: "42px"}).fontSize, "42px");
64+
assert.strictEqual(Plot.text(undefined, {fontSize: "42pt"}).fontSize, "42pt");
65+
assert.strictEqual(Plot.text(undefined, {fontSize: " 42pt"}).fontSize, "42pt");
66+
assert.strictEqual(Plot.text(undefined, {fontSize: " 42pt "}).fontSize, "42pt");
67+
assert.strictEqual(Plot.text(undefined, {fontSize: " 50% "}).fontSize, "50%");
68+
assert.strictEqual(Plot.text(undefined, {fontSize: " Larger "}).fontSize, "larger");
69+
assert.strictEqual(Plot.text(undefined, {fontSize: "unset"}).fontSize, "unset");
70+
});
71+
72+
it("text(data, {fontSize}) allows fontSize to be a channel", () => {
73+
const text = Plot.text(undefined, {fontSize: "x"});
74+
assert.strictEqual(text.fontSize, undefined);
75+
assert.strictEqual(text.channels.find(c => c.name === "fontSize").value, "x");
76+
});

0 commit comments

Comments
 (0)