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 @@ +
+
+ + + H1 + + H2 + + H3 + + H4 +
+ + + + 2014 + + + 2015 + + + 2016 + + + 2017 + + + 2018 + + + 2019 + + + 2020 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + 0 + 1 + 2 + 3 + 4 + + + + rate (%) ↑ + + + + + + + + + + + + + + + + 2016 + 2018 + 2020 + 2022 + 2024 + 2026 + 2028 + 2030 + + + + about → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ 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 @@ + + + + + a + + + b + + + + f + + + + + + + + + + + + + + + + + + 0 + 2 + 4 + 6 + + + 0 + 2 + 4 + 6 + + + + ↑ y + + + + + + + + + + + + + 0 + 20 + 40 + 60 + 80 + + + + x → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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} + ) + ] + }); +}