v0.4.0

API · Chart

Chart API

On this page

ChartGPU.create(container, options, context?)

TypeScript
import { ChartGPU } from '@chartgpu/chartgpu';

const container = document.getElementById('chart')!;
const chart = await ChartGPU.create(container, {
  series: [{ type: 'line', data: [[0, 1], [1, 3], [2, 2]] }],
});
  • container
    mount target (ChartGPU owns a canvas inside it)
  • options
    configuration (see Options & series)
    • Create-only options: antialias is applied at create (MSAA pipelines / texture manager). devicePixelRatio is a create-time policy: an explicit finite value freezes buffer + text-overlay DPR for the chart lifetime; when omitted, each resize() re-reads live window.devicePixelRatio. Buffer size uses layout clientWidth/clientHeight (not visual getBoundingClientRect() under CSS zoom). setOption cannot change either — dispose and recreate instead.
  • context?
    optional shared WebGPU { adapter, device, pipelineCache? }

Sharing GPU resources (optional)

Shared GPUDevice

TypeScript
const adapter = await navigator.gpu.requestAdapter({ powerPreference: 'high-performance' });
const device = await adapter.requestDevice();
const chart1 = await ChartGPU.create(container1, opts1, { adapter, device });
const chart2 = await ChartGPU.create(container2, opts2, { adapter, device });
  • If you inject { adapter, device }, charts do not call device.destroy() on dispose() (you own the device).
  • If you don’t inject, ChartGPU creates and destroys its own device.
  • Charts created with an injected device can emit 'deviceLost'; on loss, recreate device + charts.

Pipeline cache (PipelineCache)

Share a cache to dedupe shader/pipeline creation across charts on the same device.

TypeScript
import { createPipelineCache } from '@chartgpu/chartgpu';

const pipelineCache = createPipelineCache(device);
await ChartGPU.create(a, optsA, { adapter, device, pipelineCache });
await ChartGPU.create(b, optsB, { adapter, device, pipelineCache });
  • Cache is scoped to a single GPUDevice (mixing devices throws).

ChartGPUInstance

Returned by ChartGPU.create(...).

See ChartGPU.ts for the full interface and lifecycle behavior.

Properties (essential):

  • options: Readonly<ChartGPUOptions>: the last user-provided options object (unresolved).
  • disposed: boolean

Common methods:

  • setOption(...)
    update options and schedule a render.
    • Series identity: Prefer immutable series configs. When the same series element objects are re-passed (axes-only y/x range ticks), ChartGPU may reuse the previous resolved series array without re-scanning each series. To change data, color, visibility, or style, pass new series element objects (or a new series array). See Options & series — series array identity reuse.
  • appendData(seriesIndex, newPoints, options?)
    streaming append for cartesian series.
    • Formats
      CartesianSeriesData (DataPoint[], XYArraysData, InterleavedXYData, band/errorBar payloads) or OHLCDataPoint[]
    • Optional { maxPoints } (per call, not sticky series state — omit later for unbounded growth):
      • If a single batch is ≥ maxPoints, keep only that batch’s tail (strict replace; prior points discarded).
      • Otherwise fixed-capacity ring: fill up to maxPoints, then overwrite oldest slots (GPU modular writes — O(append), no full retained-window rewrite). Peak retained length / GPU reservation = maxPoints.
      • Prefer over sliding-window full setOption for high-rate streaming (fixed-capacity ring; not sticky series construction state).
      • When both maxPoints is set and tooltip.show === false, ChartGPU’s hit-test columnar store is not updated on append (dual-store relief); coordinator/GPU still apply the ring.
    • Device storage cap (unbounded append)
      series buffers are storage-bound. When growth would exceed min(maxBufferSize, maxStorageBufferBindingSize) (often 128 MiB ≈ 16.7M xy points on Chrome/Metal), ChartGPU auto-windows to that point budget (same ring policy as maxPoints) so the x-domain stays in sync with GPU-resident data. The hit-test store (when tooltips are on) applies the same effective window — GPU and interaction history retain one chronological window. Without this, the axis could keep expanding while the series stopped short of the right edge. Pass an explicit { maxPoints } when you want a smaller sliding window (still hard-clamped by the device budget).
    • Not for heatmap / surface3d / pie — use the dedicated update APIs below (or full setOption).
    • Types
  • updateHeatmap(seriesIndex, update)
    2D only — streaming / partial update for type: 'heatmap' (replaceZ / appendColumns+scrollX / appendRows+scrollY). Not cartesian appendData. See Options & series.
  • updateSurface3D(seriesIndex, update)
    3D only — partial update for surface3d (replaceY / appendColumns / appendRows). No-op on 2D. See 3D charts.
  • setCamera(partial)
    / getCamera() / resetCamera(): 3D only camera pose APIs. No-op / null on 2D charts. See 3D charts.
  • resize(), dispose()
  • on(...), off(...): events (see Interaction)
  • hitTest(e)
    pointer hit-test (coordinates + optional match)
  • setInteractionX(...)
    / setCrosshairX(...)
  • getZoomRange()
    / setZoomRange(...)
  • getPerformanceMetrics()
    / getPerformanceCapabilities() / onPerformanceUpdate(...)
  • getRenderMode()
    / setRenderMode(...) / needsRender() / renderFrame()

Data upload and scale/bounds derivation occur during createRenderCoordinator.ts RenderCoordinator.render() (not during setOption(...) itself).

External Render Mode

Set renderMode: 'external' to run ChartGPU inside your own render loop.

TypeScript
const chart = await ChartGPU.create(container, { renderMode: 'external', series: [...] });
function loop() {
  if (chart.needsRender()) chart.renderFrame();
  requestAnimationFrame(loop);
}
loop();

GPU submit timing

renderFrame() encodes the frame but defers device.queue.submit to a queueMicrotask. Multi-chart dashboards that share one GPUDevice and call renderFrame() on every surface in the same JS turn therefore collapse into a single batched submit (shared-device multi-chart present).

If you need GPU work on the queue before onSubmittedWorkDone() (or any immediate post-submit fence), drain the microtask first:

TypeScript
chart.renderFrame();
await Promise.resolve(); // flush batched submit
await device.queue.onSubmittedWorkDone();

dispose() flushes any pending batched submit for that chart’s device before destroying textures/buffers.

Example: examples/external-render-mode/.

Chart sync (connectCharts)

Sync crosshair/tooltip between charts (default) and optionally sync zoom.

  • Zoom sync only has effect when all connected charts have data zoom enabled.
TypeScript
import { connectCharts } from '@chartgpu/chartgpu';
const disconnect = connectCharts([chartA, chartB], { syncZoom: true });

API reference for the linked @chartgpu/chartgpu package (v0.4.0). Source on GitHub.