diff --git a/src/marks/tip.js b/src/marks/tip.js index f17f3bbc09..3fd9853688 100644 --- a/src/marks/tip.js +++ b/src/marks/tip.js @@ -127,6 +127,11 @@ export class Tip extends Mark { format = formatChannels; } + // Format the tip text, skipping any nulls. + const T = new Array(index.length); + for (const i of index) T[i] = format.call(mark, i, index, sources, scales, values); + index = index.filter((i) => T[i] != null); + // We don’t call applyChannelStyles because we only use the channels to // derive the content of the tip, not its aesthetics. const g = create("svg:g", context) @@ -150,7 +155,7 @@ export class Tip extends Mark { this.setAttribute("fill-opacity", 1); this.setAttribute("stroke", "none"); // iteratively render each channel value - const lines = format.call(mark, i, index, sources, scales, values); + const lines = T[i]; if (typeof lines === "string") { for (const line of mark.splitLines(lines)) { renderLine(that, {value: mark.clipLine(line)}); diff --git a/test/output/tipDispatch.svg b/test/output/tipDispatch.svg new file mode 100644 index 0000000000..b0d1e210a7 --- /dev/null +++ b/test/output/tipDispatch.svg @@ -0,0 +1,406 @@ + + + + + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + ↑ culmen_depth_mm + + + + 35 + 40 + 45 + 50 + 55 + + + culmen_length_mm → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ​Torgersen + + + \ No newline at end of file diff --git a/test/output/tipNull.svg b/test/output/tipNull.svg new file mode 100644 index 0000000000..7d3a3d8765 --- /dev/null +++ b/test/output/tipNull.svg @@ -0,0 +1,401 @@ + + + + + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + ↑ culmen_depth_mm + + + + 35 + 40 + 45 + 50 + 55 + + + culmen_length_mm → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/plot-snapshot.js b/test/plot-snapshot.js index 05325e1ea7..e4ab7b8221 100644 --- a/test/plot-snapshot.js +++ b/test/plot-snapshot.js @@ -10,6 +10,7 @@ export function test(plot) { const name = plot.name; it(name, async () => { const root = await (name.startsWith("warn") ? assert.warnsAsync : assert.doesNotWarnAsync)(plot); + if ("ready" in root) await root.ready; const ext = root.tagName === "svg" ? "svg" : "html"; for (const svg of root.tagName === "svg" ? [root] : root.querySelectorAll("svg")) { svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://www.w3.org/2000/svg"); diff --git a/test/plots/tip.ts b/test/plots/tip.ts index 75a8c34ccf..6eb44e3468 100644 --- a/test/plots/tip.ts +++ b/test/plots/tip.ts @@ -281,3 +281,47 @@ test(async function tipColorLiteral() { ] }); }); + +test(async function tipDispatch() { + const penguins = await d3.csv("data/penguins.csv", d3.autoType); + const plot = Plot.plot({ + marks: [ + Plot.dot(penguins, { + x: "culmen_length_mm", + y: "culmen_depth_mm", + title: "island", + tip: true + }) + ] + }); + plot.dispatchEvent( + new PointerEvent("pointermove", { + pointerType: "mouse", + clientX: 200, + clientY: 200 + }) + ); + return Object.assign(plot, {ready: new Promise((resolve) => setTimeout(resolve, 100))}); // postrender +}); + +test(async function tipNull() { + const penguins = await d3.csv("data/penguins.csv", d3.autoType); + const plot = Plot.plot({ + marks: [ + Plot.dot(penguins, { + x: "culmen_length_mm", + y: "culmen_depth_mm", + title: (d) => (d.island === "Torgersen" ? null : d.island), + tip: true + }) + ] + }); + plot.dispatchEvent( + new PointerEvent("pointermove", { + pointerType: "mouse", + clientX: 200, + clientY: 200 + }) + ); + return plot; +});