Phoenix LiveView hook that snaps a rule and per-series markers to the nearest x of the data (spec/10 §13).
CrosshairHook never reads the chart's DOM: the server writes the mark's x pixels once,
as data-xs, and the hook finds the nearest one to the pointer by binary search, so the
same attributes serve a mark drawn as SVG and one the compiler sent to the canvas layer
(D-76). attrs/3 computes them from a realised Visualize.Chart.Frame; the hook draws
in an overlay it appends to document.body, so a LiveView patch of the chart never
removes it, and re-reads the arrays on updated(). The overlay is placed over the chart
itself — the container's first <svg> or <canvas> — not over the container, whose box
the page lays out (spec/10 §13.3, #507).
In a sync group (spec/10 §4.3, §13.4) the hook publishes the pointer's x in domain units
on the group's bus and draws every other member's hover at the nearest x of its own
data; attrs/3 adds the frame's data-vis-sync and data-vis-sync-x when the frame is
a group's (Visualize.Chart.Frame.sync_attrs/1).
Usage
<div id="chart" phx-hook="CrosshairHook" {@crosshair} data-crosshair-event="hover">
{Phoenix.HTML.raw(@svg)}
</div>
crosshair = Visualize.Hooks.Crosshair.attrs(applied.frame, applied.sources)
def handle_event("hover", %{"index" => index}, socket) do
{:noreply, assign(socket, hovered: index)}
endConfiguration
Data attributes on the container, from attrs/3 (spec/10 §13.2):
data-xs- the distinct x pixels, ascending, in plot coordinatesdata-ys- one array per series of the y pixel at each x,nullwhere absentdata-plot-left,top,width,heightof the plot area inside the chartdata-size-width,heightof the chart; absent, the chart element's own size. Over a canvas, the canvas'sdata-width/data-heightare this size, from the same frame
Set by the host:
data-crosshair-event- the event pushed with{index}when the nearest index changes; unset, nothing is pusheddata-crosshair-color- the rule's stroke and the default marker fill (default: "#666")data-crosshair-colors- a JSON array of one marker fill per series
Summary
Functions
@spec attrs(Visualize.Chart.Frame.t(), map()) :: %{required(String.t()) => String.t()}
As attrs/3 with no options: the first mark.
@spec attrs(Visualize.Chart.Frame.t(), map(), keyword()) :: %{ required(String.t()) => String.t() }
The data attributes of spec/10 §13.2 for one mark of the frame, computed once.
Options
:mark- the one-based position of the mark among the frame's marks (default1)
Raises ArgumentError for a :facet or :polar frame, or a mark without x and y
channels.
Returns the JavaScript source of CrosshairHook.