Canvas and WebGL scatter
Choose a scatter renderer explicitly while retaining SVG axes, linked selection, keyboard navigation and exact table access.
Choose a renderer
ScatterPlot accepts renderer="svg", renderer="canvas" or renderer="webgl". SVG remains the ScatterPlot default; other charts do not expose accelerated renderer selection. Canvas draws circles through Canvas2D, and WebGL uses a vertex buffer and point-sprite shaders.
import { ScatterPlot, type ScatterRendererState } from '@quartile/react';
function reportRenderer(state: ScatterRendererState) {
console.log(state.requested, state.active, state.reason);
}
<ScatterPlot data={measurements} x="latency" y="cost" color="region"
label="id" renderer="webgl" onRendererChange={reportRenderer}
aria-label="Cost against latency" />;Try each mode in the live scatter playground or the worker explorer. There is no automatic row-count threshold or universal million-row guarantee.
What stays consistent
Each mode shares the same quantitative axes, bubble sizing, radius-based draw order, series colors and distance-to-circle picking. Negative and zero coordinates remain valid; missing and nonfinite coordinates are omitted. Theme tokens, container size and device pixel ratio update the raster surface. Axes, grid and the focus indicator remain SVG; tooltips remain HTML.
The plot is one keyboard stop. Arrows navigate in x/y order, Home and End reach the first and last point, Enter or Space selects, and Shift extends the selection. The focused point and summary remain available to assistive technology. Selecting a point preserves the chart's unselected points through source-excluding selection.
Exact data with bounded DOM
Above 200 visible scatter points, a View data table button opens pages of 50 rows. Every plotted value remains reachable with previous/next controls, in keyboard order and using the configured formatters. The chart does not build a hidden DOM row for every point. view="table" opens the table directly; smaller plots keep the hidden-table behavior.
This table lists exact plotted fields. It does not sample or aggregate values, and its total row count describes the plotted result. If the application queries only the first 2,000 matching records, the table contains those records, not the entire source.
Detect and understand fallback
A WebGL initialization, shader, point-size or context failure replaces the surface with Canvas. If Canvas fails or is unavailable, the chart falls back to SVG. Context loss follows the same sequence. The downgrade remains until the renderer prop changes or the chart remounts.
onRendererChange reports the requested mode, the active mode and an optional reason. Record active in measurements; requesting WebGL does not establish that the device used it. The callback describes renderer status, not GPU completion or paint duration. The marks layer also exposes data-renderer and data-fallback-reason.
Owned contexts, buffers, programs, listeners and observers are released on replacement or unmount. Server rendering creates no browser contexts. Raster rendering has no animation loop, including under reduced motion.
Measure the remaining work
- Accelerated rendering currently covers ScatterPlot and bubbles only.
- There is no GPU filtering, worker renderer, automatic downsampling or image export API.
- Raster points have no individual DOM nodes for per-point customization.
- GPU limits, context quotas and software rendering vary across devices.
Read Arrow and worker queries to pass bounded query results to a chart, and Performance to distinguish source records, matched rows, plotted marks, query receipt and browser paint. Reproduce the browser correctness fixture for actual pixels, DPR changes, theme, interaction and forced context loss.