Skip to main content

Function: nearestHover()

nearestHover<R>(root, store, o): NearestHoverHandle

Defined in: packages/sdvplot/src/interact/nearest.ts:90

Hover the NEAREST mark of a d3-drawn (or any non-Plot) figure, within a radius, rather than the element under the pointer: sparse or small marks stay easy to hit. "xy" finds it with a Delaunay triangulation (Delaunay.find, as blazing-the-nets' hex chart does within 18 px); "x" / "y" bisect the points sorted along that axis (a 1-D Voronoi, as its distance bars do). The pointer writes hover: [id], once per distinct mark; beyond radius, inside the padding margin, on pointerleave / pointercancel or with no points, it writes hover: []. label shows a tooltip at the mark, not at the pointer. Link the same figure with hover: false in linkSelection so this is its only hover writer while highlight still follows the store. The pointer listeners capture, so a handler registered earlier on the svg that stops the event (Plot's tip on pointerdown) cannot hide it. A Plot figure hovers through its own tip instead (linkSelection's hover: { id }). Throws InputError on a negative radius or padding or an unknown dimension, in Node too, and when root is not an <svg>. Returns a HANDLE, not a teardown function, because it has more to do than tear down: update re-targets it and destroy removes it (linkSelection and linkCursor, whose teardown is all they have, return a function). A no-op handle without a DOM.

Type Parameters​

R​

R

Parameters​

root​

Element

store​

SelectionStore<R>

o​

NearestHoverOptions

Returns​

NearestHoverHandle

Example​

import { createSelection } from "@sportsdataverse/sdvplot";
import { linkSelection, nearestHover } from "@sportsdataverse/sdvplot/interact";
import * as d3 from "d3";

const rows = [
{ team: "KC", wins: 15, net_epa: 0.063 },
{ team: "BUF", wins: 13, net_epa: 0.19 },
{ team: "MIA", wins: 8, net_epa: -0.019 },
{ team: "LV", wins: 4, net_epa: -0.146 },
];
const x = d3.scaleLinear([0, 17], [30, 410]);
const y = d3.scaleLinear([-0.2, 0.2], [190, 10]);
const svg = d3.create("svg").attr("viewBox", "0 0 440 200").attr("width", 440);
svg
.selectAll("circle")
.data(rows)
.join("circle")
.attr("data-sdv-id", (d) => d.team) // the d3 way to stamp link ids
.attr("cx", (d) => x(d.wins))
.attr("cy", (d) => y(d.net_epa))
.attr("r", 5)
.attr("fill", "currentColor");
const node = svg.node() as SVGSVGElement;
const store = createSelection();
linkSelection(store, { figure: node, hover: false }); // highlight follows the store; nearestHover writes hover
nearestHover(node, store, {
points: rows.map((d) => ({ x: x(d.wins), y: y(d.net_epa), id: d.team })),
radius: 18,
label: (team) => ({ lines: [team, `net EPA/play ${rows.find((d) => d.team === team)?.net_epa}`] }),
});
node; // hover near a dot: within 18 px it lights and its tooltip shows