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 @@
+
\ 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 @@
+
\ 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;
+});