Charts · Interaction
Tooltips, zoom, brush, fullscreen
Interaction is where a chart stops being a picture. LUC owns the tooltip surface, the crosshair, the zoom behaviour and the fullscreen research view, so none of them is left to an engine default.
Tooltip modes
Axis tooltips for time series, item tooltips for marks, and an explicit off switch.
Axis tooltip
One date header, one aligned row per visible series.
Item tooltip
Used where there is no shared x: bars, scatter, heatmap, flow.
Zoom and brush
Wheel zoom is opt-in per chart; brush selection is opt-in and stays a research affordance.
Zoom inside
Wheel to zoom, drag to pan. Scroll hijacking is limited to the plot itself.
Brush
Drag inside the plot to select a subrange; the toolbar clears it.
Scale
Linear or logarithmic is a presentation choice over the same values: the axis maps them, the data never changes, and a range change never re-scales the chart silently.
Long-horizon price
Log is the declared default for a series spanning four orders of magnitude; the reader may switch to Linear and the choice sticks.
Signed measurement
A drawdown is linear-only: a log axis over a value that reaches zero would be a broken chart, so the renderer offers no control at all.
Fullscreen research view
The fullscreen button on every panel above opens a real workspace, not a stretched div. Escape exits; focus returns to the trigger. The selected scale, range and series travel with it.
Fullscreen research
Title, latest readout, range, legend, export and a chart that fills the remaining height.
Deferred
One interaction that did not ship this round.
Pinned inspection
Click-to-pin a tooltip for comparison belongs with the research workspace work: it needs a visible pin affordance, an unpin gesture, and a decision about what happens when the pinned x scrolls out of view. The transient tooltip already covers reading a single value.
Usage
<LineChart interaction={{ zoom: "inside", pan: true }} … />
<LineChart interaction={{ brush: true }} … />
<LineChart tooltip={{ mode: "item" }} … />
// Fullscreen is a wrapper: give it the same render function you use inline.
<ChartPanel
ranges={["1m", "3m", "1y", "all"]}
defaultRange="1y"
render={({ range, height }) => <LineChart data={windowForRange(rows, range)} height={height} … />}
/>