API · Interaction
Interaction
On this page
Event handling
Chart instances expose on() and off() methods for subscribing to user interaction events. See ChartGPU.ts for the implementation.
on(eventName, callback)voidregisters a callback for the specified event name. Callbacks are stored in a closure and persist until explicitly removed viaoff()or until the instance is disposed.off(eventName, callback)voidremoves a previously registered callback. Safe to call even if the callback was never registered or was already removed.
Supported events
'click'fires on tap/click gestures (mouse left-click, touch tap, pen tap). When you register a click listener viaon('click', ...), it fires whenever a click occurs on the canvas, even if not on a chart item. For clicks not on a chart item, the callback receivesseriesIndex: null,dataIndex: null,value: null, andseriesName: null, but includes the originalPointerEventasevent.'mouseover'fires when the pointer enters a chart item (or transitions from one chart item to another). Chart items include cartesian hits (points/bars) and pie slices. Only fires when listeners are registered (on('mouseover', ...)oron('mouseout', ...)).'mouseout'fires when the pointer leaves a chart item (or transitions from one chart item to another). Chart items include cartesian hits (points/bars) and pie slices. Only fires when listeners are registered (on('mouseover', ...)oron('mouseout', ...)).'crosshairMove'fires when the chart's "interaction x" changes (domain units). This includes pointer movement inside the plot area, pointer leaving the plot area (emitsx: null), programmatic calls tosetInteractionX(...)/setCrosshairX(...), and updates received viaconnectCharts(...)sync. SeeChartGPU.tsandcreateRenderCoordinator.ts.'zoomRangeChange'fires when the chart’s percent-space zoom window changes (([0, 100])). This includes inside-zoom gestures, slider updates, programmatic calls tosetZoomRange(...), auto-scroll adjustments from streaming withautoScroll: true, and updates received viaconnectCharts(..., { syncZoom: true }).'dataAppend'fires synchronously afterappendData()completes internal processing. Only fires forappendData()calls (notsetOption()updates). Provides metadata about the appended data: series index, point count, and x-extent of the newly appended points.
Event callback payload
For 'click' | 'mouseover' | 'mouseout', callbacks receive a ChartGPUEventPayload object with:
seriesIndexnumber | nullzero-based series index, ornullif not on a chart itemdataIndexnumber | nullzero-based item index within the series (for cartesian series: data point index; for pie series: slice index), ornullif not on a chart itemvaluereadonly [number, number] | nullitem value tuple.- For cartesian series, this is the data point coordinates
[x, y](domain units). - For pie series, this is
[0, sliceValue](pie is non-cartesian; the y-slot contains the numeric slice value). SeeChartGPU.ts.
- For cartesian series, this is the data point coordinates
seriesNamestring | nullseries name fromseries[i].name(trimmed), ornullif not on a chart item or name is empty. Note: for pie slices this is still the seriesname(slicenameis not included in event payload).eventPointerEventthe original browserPointerEventfor access to client coordinates, timestamps, etc.
Series visibility and hit-testing
- When a series is hidden (via
visible: falseor legend toggle), it does not participate in hit-testing for hovering, tooltips, or click events. - Hit-testing functions handle visibility filtering internally and always return correct series indices (relative to the original series array, not filtered arrays).
- This means:
- Hovering over visible series works correctly regardless of other series being hidden
- Tooltips display the correct series name and index
- Click events report the correct series index
- Multi-series interactions (axis-trigger tooltips, crosshair sync) only include visible series
For 'crosshairMove', callbacks receive a ChartGPUCrosshairMovePayload object with:
xnumber | nullcurrent interaction x in domain units (nullclears/hides crosshair + tooltip)source?unknownoptional token identifying the origin of the update (useful for sync loop prevention; passed throughsetInteractionX(...)/setCrosshairX(...)and forwarded byconnectCharts(...))
For 'zoomRangeChange', callbacks receive a ChartGPUZoomRangeChangePayload object with:
startnumberzoom window start in percent space ([0, 100])endnumberzoom window end in percent space ([0, 100])sourceKind?'user' | 'auto-scroll' | 'api'optional string categorizing the origin of the zoom change:'auto-scroll'internal adjustment from streaming data append withautoScroll: true'api'programmatic call tosetZoomRange(...)'user'reserved for future use (user gestures like inside-zoom, slider drag); not currently emittedundefinedmay occur for internal changes not explicitly categorized (e.g., constraint clamping duringsetOptions); do not assume all changes are tagged
source?unknownoptional token identifying the origin of the update (useful for sync loop prevention; forwarded byconnectCharts(..., { syncZoom: true }))
For 'dataAppend', callbacks receive a ChartGPUDataAppendPayload object with:
seriesIndexnumberzero-based series index for the series that received new datacountnumbernumber of points appended (always > 0)xExtent{ min: number; max: number }x-value range of the appended points only (domain units). Computed from the appended points based on data format:- Interleaved arrays(
InterleavedXYData): x values are at even indices (data[0],data[2],data[4], ...) XYArrays(XYArraysData): x values come from thexarray- DataPoint arrays(
DataPoint[]): x values extracted from[x, y]tuples or{ x, y }objects - OHLC arrays(
OHLCDataPoint[]): x values extracted from timestamp field
Performance note: The xExtent computation is skipped entirely when no dataAppend listeners are registered, ensuring zero overhead for applications that don't use this event.
Behavioral notes
- Click events fire when you have registered a click listener via
on('click', ...). For clicks not on a chart item, point-related fields (seriesIndex,dataIndex,value,seriesName) arenull, buteventalways contains the originalPointerEvent. - Hover events (
mouseover/mouseout) only fire when at least one hover listener is registered. They fire on transitions:mouseoverwhen entering a chart item (or moving between items),mouseoutwhen leaving a chart item (or moving between items). - Crosshair move events (
crosshairMove) fire on interaction-x changes. When the pointer leaves the plot area, the chart clears interaction-x tonullso synced charts do not "stick". - Data append events (
dataAppend) fire synchronously afterappendData()completes. These events only fire for streaming appends viaappendData(), not for full data updates viasetOption(). The event computation (includingxExtentcalculation) is only performed when listeners are registered, ensuring zero overhead when unused. Use this event to track real-time data ingestion or coordinate with external systems. - Event payload objects should be treated as ephemeral (read values inside the callback; if you need to persist them, copy the primitive fields you care about rather than storing the payload object itself).
- All event listeners are automatically cleaned up when
dispose()is called. No manual cleanup required.
Right-click / context menu interactions
ChartGPU does not emit a built-in 'contextmenu' event. Consumers implement right-click interactions directly using DOM events and ChartGPUInstance.hitTest(...).
- Use the DOM
contextmenuevent on the chart canvas (or container). - Call
chart.hitTest(e)(accepts aMouseEvent) to get plot coordinates (gridX/gridY) and an optionalmatchfor snap-to-data behavior.
Example:
const canvas = container.querySelector('canvas')!;
canvas.addEventListener('contextmenu', (e) => {
e.preventDefault();
const hit = chart.hitTest(e);
// hit.isInGrid, hit.gridX/hit.gridY (CSS px), and hit.match (optional)
});
For a ready-made main-thread helper that wires contextmenu + hitTest(...) into an annotation authoring UI (with undo/redo + JSON export), see createAnnotationAuthoring(...) and examples/annotation-authoring/. Full documentation available in the Annotations API.
Zoom and Pan APIs
See ChartGPUInstance for zoom-related methods:
getZoomRange(): { start: number; end: number } | nullsetZoomRange(start: number, end: number, source?: unknown): void
For data zoom configuration, see Data Zoom Configuration.
API reference for the linked @chartgpu/chartgpu package (v0.4.0). Source on GitHub.