diff --git a/src/interactions/pointer.js b/src/interactions/pointer.js
index 5ca1f858a5..c92addcff7 100644
--- a/src/interactions/pointer.js
+++ b/src/interactions/pointer.js
@@ -130,18 +130,29 @@ function pointerK(kx, ky, {x, y, px, py, maxRadius = 40, channels, render, ...op
return r;
}
+ // Select the closest point to the mouse in the current facet; for
+ // pointerX or pointerY, the orthogonal component of the distance is
+ // squashed, selecting primarily on the dominant dimension. Across facets,
+ // use unsquashed distance to determine the winner.
function pointermove(event) {
if (state.sticky || (event.pointerType === "mouse" && event.buttons === 1)) return; // dragging
let [xp, yp] = pointof(event);
(xp -= tx), (yp -= ty); // correct for facets and band scales
+ const kpx = xp < dimensions.marginLeft || xp > dimensions.width - dimensions.marginRight ? 1 : kx;
+ const kpy = yp < dimensions.marginTop || yp > dimensions.height - dimensions.marginBottom ? 1 : ky;
let ii = null;
let ri = maxRadius * maxRadius;
for (const j of index) {
- const dx = kx * (px(j) - xp);
- const dy = ky * (py(j) - yp);
+ const dx = kpx * (px(j) - xp);
+ const dy = kpy * (py(j) - yp);
const rj = dx * dx + dy * dy;
if (rj <= ri) (ii = j), (ri = rj);
}
+ if (ii != null && (kx !== 1 || ky !== 1)) {
+ const dx = px(ii) - xp;
+ const dy = py(ii) - yp;
+ ri = dx * dx + dy * dy;
+ }
update(ii, ri);
}
diff --git a/test/output/liborProjectionsFacet.html b/test/output/liborProjectionsFacet.html
new file mode 100644
index 0000000000..1469444943
--- /dev/null
+++ b/test/output/liborProjectionsFacet.html
@@ -0,0 +1,392 @@
+
+
+ H1H2H3H4
+
+
\ No newline at end of file
diff --git a/test/output/tipFacetX.svg b/test/output/tipFacetX.svg
new file mode 100644
index 0000000000..2625017782
--- /dev/null
+++ b/test/output/tipFacetX.svg
@@ -0,0 +1,201 @@
+
\ No newline at end of file
diff --git a/test/plots/libor-projections.ts b/test/plots/libor-projections.ts
index 78001de3e6..ea8f24a512 100644
--- a/test/plots/libor-projections.ts
+++ b/test/plots/libor-projections.ts
@@ -24,3 +24,23 @@ export async function liborProjections() {
y: {grid: true, line: true}
});
}
+
+export async function liborProjectionsFacet() {
+ const libor = await d3.csv("data/libor-projections.csv", d3.autoType);
+ return Plot.plot({
+ fy: {tickFormat: "d"},
+ y: {percent: true, nice: true, grid: true, axis: "right", label: "rate (%)"},
+ color: {legend: true},
+ marks: [
+ Plot.frame(),
+ Plot.lineY(libor, {
+ markerStart: true,
+ fy: (d) => d.on.getFullYear(),
+ x: "about",
+ stroke: (d) => "H" + (1 + d3.utcMonth.count(d3.utcYear(d.on), d.on)) / 3,
+ y: "value",
+ tip: true
+ })
+ ]
+ });
+}
diff --git a/test/plots/tip.ts b/test/plots/tip.ts
index d2b1b78c0d..41bcaf5105 100644
--- a/test/plots/tip.ts
+++ b/test/plots/tip.ts
@@ -237,3 +237,22 @@ export async function tipTransform() {
marks: [Plot.dotX([0, 0.1, 0.3, 1], {fill: Plot.identity, r: 10, frameAnchor: "middle", tip: true})]
});
}
+
+export async function tipFacetX() {
+ const data = d3.range(100).map((i) => ({f: i > 60 || i % 2 ? "b" : "a", x: i, y: i / 10}));
+ return Plot.plot({
+ inset: 10,
+ y: {domain: [0, 7]},
+ marks: [
+ Plot.frame(),
+ Plot.dot(data, {fy: "f", x: "x", y: "y", tip: "x", fill: "f"}),
+ Plot.dot(
+ [
+ {f: "a", y: 3},
+ {f: "b", y: 1}
+ ],
+ {fy: "f", x: 90, y: "y", r: 30, fill: "f", fillOpacity: 0.1, stroke: "currentColor", strokeDasharray: 4}
+ )
+ ]
+ });
+}