Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
ChartGPU
https://github.com/chartgpu/chartgpu
Admin
ChartGPU is a TypeScript charting library built on WebGPU for smooth, interactive
...
Tokens:
67,713
Snippets:
236
Trust Score:
7.5
Update:
1 month ago
Context
Skills
Chat
Benchmark
90.3
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# ChartGPU ChartGPU is a high-performance TypeScript charting library built on WebGPU for smooth, interactive rendering of large datasets. It can render 50+ million data points at 60 FPS, making it ideal for real-time dashboards, financial charting, scientific visualization, and any application requiring high-throughput data visualization. The library leverages GPU-accelerated rendering via WebGPU to offload computation from the CPU, enabling unprecedented performance for web-based charts. The library provides a declarative API with support for multiple series types including line, area, bar, scatter, pie, and candlestick charts. Key features include built-in zoom/pan interactions, auto-scrolling for streaming data, customizable annotations, theming support, and the ability to share GPU resources across multiple charts for efficient dashboard implementations. ChartGPU follows functional-first architecture and works in Chrome 113+, Edge 113+, Safari 18+, and Firefox (with WebGPU enabled). ## Installation ```bash npm install chartgpu ``` ## Creating a Basic Line Chart The `ChartGPU.create()` static method initializes a new chart instance with full WebGPU context management. It returns a Promise resolving to a `ChartGPUInstance` that provides methods for data updates, event handling, and lifecycle management. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, DataPoint } from 'chartgpu'; // Create sample sine wave data const createSineWave = (count: number): DataPoint[] => { const data: DataPoint[] = []; for (let i = 0; i < count; i++) { const x = (i / (count - 1)) * Math.PI * 2; const y = Math.sin(x); data.push([x, y]); } return data; }; async function createChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { // Grid margins (CSS px) for axis labels grid: { left: 70, right: 24, top: 24, bottom: 56 }, // Axis configuration xAxis: { type: 'value', min: 0, max: Math.PI * 2, name: 'Angle (rad)' }, yAxis: { type: 'value', min: -1.1, max: 1.1, name: 'Amplitude' }, // Color palette for series palette: ['#4a9eff', '#ff4ab0', '#40d17c'], // Animation settings animation: { duration: 600, easing: 'cubicOut' }, // Series definition series: [ { type: 'line', name: 'sin(x)', data: createSineWave(300), lineStyle: { width: 2, opacity: 1 }, // Add fill under line areaStyle: { opacity: 0.2 }, }, ], }; const chart = await ChartGPU.create(container, options); // Handle resize window.addEventListener('resize', () => chart.resize()); // Cleanup on page unload window.addEventListener('beforeunload', () => chart.dispose()); return chart; } createChart(); ``` ## Multi-Series Line Chart with Area Fill Create multiple series with different phases and styles. The `areaStyle` property enables fill under line series, creating a "filled line" effect. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, DataPoint } from 'chartgpu'; const createSineWave = (count: number, phase: number, amplitude: number): DataPoint[] => { const data: DataPoint[] = []; for (let i = 0; i < count; i++) { const t = i / (count - 1); const x = t * Math.PI * 2; const y = Math.sin(x + phase) * amplitude; data.push([x, y]); } return data; }; async function createMultiSeriesChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 56 }, xAxis: { type: 'value', min: 0, max: Math.PI * 2, name: 'Angle (rad)' }, yAxis: { type: 'value', min: -1.1, max: 1.1, name: 'Amplitude' }, palette: ['#4a9eff', '#ff4ab0', '#40d17c'], animation: { duration: 900, easing: 'cubicOut' }, series: [ { type: 'line', name: 'sin(x) (filled)', data: createSineWave(300, 0, 1), color: '#4a9eff', areaStyle: { opacity: 0.2 }, lineStyle: { width: 2, opacity: 1 }, }, { type: 'line', name: 'sin(x + π/3)', data: createSineWave(300, Math.PI / 3, 1), lineStyle: { width: 2, opacity: 1 }, }, { type: 'line', name: 'sin(x + 2π/3)', data: createSineWave(300, (2 * Math.PI) / 3, 1), lineStyle: { width: 2, opacity: 1 }, }, ], }; const chart = await ChartGPU.create(container, options); // Event handling chart.on('click', (payload) => console.log('Click:', payload)); chart.on('mouseover', (payload) => console.log('Hover:', payload)); chart.on('mouseout', (payload) => console.log('Mouse out:', payload)); return chart; } createMultiSeriesChart(); ``` ## Candlestick Chart (OHLC Financial Data) Render financial OHLC (open-high-low-close) candlestick data with customizable styling. Supports both 'classic' and 'hollow' candlestick styles with configurable up/down colors. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, OHLCDataPoint } from 'chartgpu'; // Generate synthetic OHLC data function generateOHLCData(numCandles: number, startPrice: number = 100): OHLCDataPoint[] { const data: OHLCDataPoint[] = []; const msPerSecond = 1000; const startTimestamp = Date.now() - numCandles * msPerSecond; let currentPrice = startPrice; for (let i = 0; i < numCandles; i++) { const timestamp = startTimestamp + i * msPerSecond; const openPrice = currentPrice; const volatility = 0.03; const trend = (Math.random() - 0.48) * 0.02; const change = openPrice * (trend + (Math.random() - 0.5) * volatility); const closePrice = openPrice + change; const highPrice = Math.max(openPrice, closePrice) * (1 + Math.random() * 0.015); const lowPrice = Math.min(openPrice, closePrice) * (1 - Math.random() * 0.015); // Tuple format: [timestamp, open, close, low, high] data.push([timestamp, openPrice, closePrice, lowPrice, highPrice]); currentPrice = closePrice; } return data; } async function createCandlestickChart() { const container = document.getElementById('chart')!; const ohlcData = generateOHLCData(60); // Calculate bounds let minPrice = Infinity, maxPrice = -Infinity; let minTime = Infinity, maxTime = -Infinity; for (const [timestamp, , , low, high] of ohlcData) { minTime = Math.min(minTime, timestamp); maxTime = Math.max(maxTime, timestamp); minPrice = Math.min(minPrice, low); maxPrice = Math.max(maxPrice, high); } const pricePadding = (maxPrice - minPrice) * 0.05; const timePadding = 1000; const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 56 }, xAxis: { type: 'value', min: minTime - timePadding, max: maxTime + timePadding, name: 'Time', }, yAxis: { type: 'value', min: minPrice - pricePadding, max: maxPrice + pricePadding, name: 'Price ($)', }, tooltip: { show: true, trigger: 'axis' }, animation: { duration: 600, easing: 'cubicOut' }, series: [ { type: 'candlestick', name: 'Stock Price', data: ohlcData, style: 'classic', // or 'hollow' itemStyle: { upColor: '#26a69a', downColor: '#ef5350', upBorderColor: '#26a69a', downBorderColor: '#ef5350', borderWidth: 1, }, barWidth: '80%', barMinWidth: 2, barMaxWidth: 40, }, ], }; const chart = await ChartGPU.create(container, options); return chart; } createCandlestickChart(); ``` ## Live Streaming Data with Auto-Scroll Stream real-time data using `appendData()` with auto-scrolling enabled. Includes data zoom (inside wheel/drag + slider UI) for interactive exploration. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUInstance, ChartGPUOptions, DataPoint } from 'chartgpu'; async function createStreamingChart() { const container = document.getElementById('chart')!; // Seed data const seedData: DataPoint[] = []; for (let i = 0; i < 800; i++) { const x = i * 0.02; const y = Math.sin(x) * 0.8 + Math.sin(x * 0.23 + 1.2) * 0.25; seedData.push([x, y]); } const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 44 }, xAxis: { type: 'value', name: 't' }, yAxis: { type: 'value', name: 'value' }, tooltip: { trigger: 'axis' }, autoScroll: true, // Keep view anchored to newest data dataZoom: [ { type: 'inside' }, // Wheel zoom + shift-drag pan { type: 'slider', start: 70, end: 100 }, // Slider UI ], palette: ['#4a9eff'], animation: false, // Disable for streaming performance series: [ { type: 'line', name: 'stream', data: seedData, color: '#4a9eff', lineStyle: { width: 2, opacity: 1 }, sampling: 'none', // Enables fast GPU append path }, ], }; const chart = await ChartGPU.create(container, options); // Streaming loop let nextX = seedData.length * 0.02; const rawData = [...seedData]; const maxPoints = 25000; const intervalId = setInterval(() => { const batch: DataPoint[] = []; for (let i = 0; i < 12; i++) { nextX += 0.02; const y = Math.sin(nextX) * 0.8 + Math.sin(nextX * 0.23 + 1.2) * 0.25 + Math.sin(nextX * 2.1) * 0.08 + (Math.random() - 0.5) * 0.04; batch.push([nextX, y]); } // Append new data to series index 0 chart.appendData(0, batch); rawData.push(...batch); // Trim to prevent unbounded growth if (rawData.length > maxPoints) { rawData.splice(0, rawData.length - maxPoints); } }, 60); // Cleanup window.addEventListener('beforeunload', () => { clearInterval(intervalId); chart.dispose(); }); return chart; } createStreamingChart(); ``` ## Scatter Density Chart (1M+ Points) Render large point clouds using GPU-binned density/heatmap mode. The `mode: 'density'` setting enables efficient visualization of overplotted data. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, ScatterPointTuple } from 'chartgpu'; // Generate 1 million points with Gaussian clusters function createDensityData(count: number): ScatterPointTuple[] { const data: ScatterPointTuple[] = []; for (let i = 0; i < count; i++) { const blob = Math.random() < 0.6 ? 0 : 1; const cx = blob === 0 ? 0.35 : 0.7; const cy = blob === 0 ? 0.55 : 0.35; const sx = blob === 0 ? 0.08 : 0.05; const sy = blob === 0 ? 0.10 : 0.07; // Box-Muller transform for Gaussian distribution const u1 = Math.max(1e-12, Math.random()); const u2 = Math.random(); const r = Math.sqrt(-2.0 * Math.log(u1)); const theta = 2.0 * Math.PI * u2; const x = cx + r * Math.cos(theta) * sx + (Math.random() - 0.5) * 0.03; const y = cy + r * Math.sin(theta) * sy + (Math.random() - 0.5) * 0.03; data.push([x, y]); } // Sort by x for efficient visible-range binning data.sort((a, b) => a[0] - b[0]); return data; } async function createDensityChart() { const container = document.getElementById('chart')!; const points = createDensityData(1_000_000); const options: ChartGPUOptions = { theme: 'dark', xAxis: { type: 'value' }, yAxis: { type: 'value' }, series: [ { type: 'scatter', name: 'density', data: points, mode: 'density', // Enable density heatmap mode binSize: 2, // Bin size in CSS pixels densityColormap: 'viridis', // 'viridis' | 'plasma' | 'inferno' | custom array densityNormalization: 'log', // 'linear' | 'sqrt' | 'log' sampling: 'none', }, ], }; const chart = await ChartGPU.create(container, options); // Update settings dynamically chart.setOption({ ...options, series: [{ ...options.series![0], binSize: 4, densityColormap: 'plasma', densityNormalization: 'sqrt', }], }); return chart; } createDensityChart(); ``` ## Pie and Donut Charts Create pie and donut charts with customizable radius, start angle, and per-slice colors. ```typescript import { ChartGPU, darkTheme } from 'chartgpu'; import type { ChartGPUOptions, PieDataItem, ThemeConfig } from 'chartgpu'; async function createPieCharts() { const pieContainer = document.getElementById('chart-pie')!; const donutContainer = document.getElementById('chart-donut')!; const theme: ThemeConfig = { ...darkTheme, backgroundColor: '#0f0f14', gridLineColor: 'rgba(255,255,255,0.06)', }; const slices: PieDataItem[] = [ { name: 'Compute', value: 42, color: '#00E5FF' }, { name: 'Memory', value: 30, color: '#FF2D95' }, { name: 'Raster', value: 18, color: '#B026FF' }, { name: 'Upload', value: 12, color: '#00F5A0' }, { name: 'Sync', value: 9, color: '#FFD300' }, { name: 'Other', value: 6, color: '#FF6B00' }, ]; const createPieOptions = (title: string, radius: [string | number, string]): ChartGPUOptions => ({ grid: { left: 24, right: 120, top: 24, bottom: 24 }, xAxis: { type: 'value', min: 0, max: 1 }, yAxis: { type: 'value', min: 0, max: 1 }, tooltip: { show: true, trigger: 'item' }, theme, animation: { duration: 900, easing: 'cubicOut' }, series: [ { type: 'pie', name: title, radius, // [innerRadius, outerRadius] center: ['50%', '50%'], startAngle: 90, data: slices, }, ], }); // Pie chart (solid) const pie = await ChartGPU.create(pieContainer, createPieOptions('Pie', [0, '72%'])); // Donut chart (hollow center) const donut = await ChartGPU.create(donutContainer, createPieOptions('Donut', ['40%', '72%'])); return { pie, donut }; } createPieCharts(); ``` ## Bar Charts (Grouped and Stacked) Create grouped and stacked bar charts with configurable bar width, gaps, and stacking behavior. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, DataPoint } from 'chartgpu'; async function createGroupedBarChart() { const container = document.getElementById('chart')!; const xs = [0, 1, 2, 3, 4, 5]; const makeSeries = (ys: number[]): DataPoint[] => xs.map((x, i) => [x, ys[i]]); const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 56 }, xAxis: { type: 'value', min: -0.75, max: 5.75, name: 'Category' }, yAxis: { type: 'value', min: -6, max: 10, name: 'Value' }, palette: ['#4a9eff', '#ff4ab0', '#40d17c'], tooltip: { show: true, trigger: 'axis' }, animation: { duration: 900, easing: 'cubicOut' }, series: [ { type: 'bar', name: 'Series A', data: makeSeries([8, 6, -3, 5, 2, -2]), color: '#4a9eff', stack: 's1', // Same stack ID = stacked bars barWidth: '70%', barGap: 0.01, // Gap between bars in same group barCategoryGap: 0.35, // Gap between categories }, { type: 'bar', name: 'Series B', data: makeSeries([5, -1, -2, 3, -4, 1]), color: '#ff4ab0', stack: 's1', // Stacked with Series A }, { type: 'bar', name: 'Series C', data: makeSeries([2, 3, 1, -2, 6, -5]), color: '#40d17c', // No stack ID = separate clustered bar }, ], }; const chart = await ChartGPU.create(container, options); return chart; } createGroupedBarChart(); ``` ## Annotations (Reference Lines, Markers, Text) Add visual annotations including horizontal/vertical reference lines, point markers, and text overlays. Supports both data-space (tracks with zoom/pan) and plot-space (pinned HUD-style) positioning. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions, AnnotationConfig } from 'chartgpu'; async function createChartWithAnnotations() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 56 }, xAxis: { type: 'value' }, yAxis: { type: 'value' }, series: [ { type: 'line', data: [[0, 1], [1, 3], [2, 2], [3, 5], [4, 4]] }, ], annotations: [ // Horizontal threshold line { id: 'threshold', type: 'lineY', y: 3.5, layer: 'belowSeries', style: { color: '#ffd166', lineWidth: 2, lineDash: [8, 6], opacity: 0.95 }, label: { template: 'threshold={y}', decimals: 1 }, }, // Vertical event marker { id: 'event', type: 'lineX', x: 2, layer: 'belowSeries', style: { color: '#40d17c', lineWidth: 2 }, label: { text: 'Event', offset: [8, 10], anchor: 'start' }, }, // Point marker at peak { id: 'peak', type: 'point', x: 3, y: 5, layer: 'aboveSeries', marker: { symbol: 'circle', size: 10, style: { color: '#ff4ab0' } }, label: { template: 'peak={y}', decimals: 2, offset: [10, -10], background: { color: '#000', opacity: 0.7, padding: [2, 6, 2, 6], borderRadius: 4 }, }, }, // Plot-space HUD text (pinned position) { id: 'watermark', type: 'text', position: { space: 'plot', x: 0.05, y: 0.05 }, // Fractions [0,1] text: 'Preliminary Data', layer: 'aboveSeries', style: { color: '#ffffff', opacity: 0.5 }, }, ], }; const chart = await ChartGPU.create(container, options); // Update annotations programmatically const annotations = [...(chart.options.annotations ?? [])]; annotations.push({ type: 'lineY', y: 4.5, style: { color: '#ef4444', lineWidth: 2, lineDash: [4, 4] }, label: { text: 'Alert' }, }); chart.setOption({ ...chart.options, annotations }); return chart; } createChartWithAnnotations(); ``` ## Interactive Annotation Authoring Enable interactive creation, editing, drag-to-reposition, and deletion of annotations with undo/redo support. ```typescript import { ChartGPU, createAnnotationAuthoring } from 'chartgpu'; import type { ChartGPUOptions } from 'chartgpu'; async function createInteractiveAnnotationChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { series: [{ type: 'line', data: [[0, 1], [1, 3], [2, 2], [3, 5], [4, 4]] }], annotations: [], }; const chart = await ChartGPU.create(container, options); // Enable annotation authoring UI const authoring = createAnnotationAuthoring(container, chart, { showToolbar: true, // Undo/redo/export buttons enableContextMenu: true, // Right-click to add/edit menuZIndex: 1000, toolbarZIndex: 10, }); // Programmatic API authoring.addVerticalLine(Date.now()); authoring.addTextNote(50, 75, 'Critical Point', 'data'); // Undo/redo operations authoring.undo(); authoring.redo(); // Export as JSON const json = authoring.exportJSON(); const annotations = authoring.getAnnotations(); console.log('Exported annotations:', json); // Cleanup (IMPORTANT: dispose authoring before chart) window.addEventListener('beforeunload', () => { authoring.dispose(); chart.dispose(); }); return { chart, authoring }; } createInteractiveAnnotationChart(); ``` ## Shared GPUDevice for Multi-Chart Dashboards Share a single `GPUDevice` across multiple charts to reduce GPU memory overhead and initialization time. Essential for dashboards with 3+ charts. ```typescript import { ChartGPU, createPipelineCache, connectCharts } from 'chartgpu'; import type { ChartGPUInstance, ChartGPUOptions } from 'chartgpu'; async function createDashboard() { // Create shared GPU resources const adapter = await navigator.gpu?.requestAdapter({ powerPreference: 'high-performance', }); if (!adapter) throw new Error('WebGPU not supported'); const device = await adapter.requestDevice(); const pipelineCache = createPipelineCache(device); const sharedContext = { adapter, device, pipelineCache }; const containers = [ document.getElementById('chart1')!, document.getElementById('chart2')!, document.getElementById('chart3')!, ]; const chartConfigs: ChartGPUOptions[] = [ { theme: 'dark', xAxis: { type: 'time' }, yAxis: { type: 'value', name: 'ms' }, autoScroll: true, dataZoom: [{ type: 'inside' }], animation: false, series: [ { type: 'line', name: 'P50', data: [], color: '#22c55e', sampling: 'none' }, { type: 'line', name: 'P95', data: [], color: '#eab308', sampling: 'none' }, ], }, { theme: 'dark', xAxis: { type: 'time' }, yAxis: { type: 'value', name: 'req/s' }, autoScroll: true, dataZoom: [{ type: 'inside' }], animation: false, series: [ { type: 'area', name: 'Throughput', data: [], color: '#3b82f6', areaStyle: { opacity: 0.3 }, sampling: 'none' }, ], }, { theme: 'dark', xAxis: { type: 'time' }, yAxis: { type: 'value', name: '%', min: 0, max: 100 }, autoScroll: true, dataZoom: [{ type: 'inside' }], animation: false, series: [ { type: 'line', name: 'CPU', data: [], color: '#f97316', sampling: 'none' }, { type: 'line', name: 'Memory', data: [], color: '#a855f7', sampling: 'none' }, ], }, ]; // Create charts with shared context const charts: ChartGPUInstance[] = []; for (let i = 0; i < chartConfigs.length; i++) { const chart = await ChartGPU.create(containers[i], chartConfigs[i], sharedContext); charts.push(chart); } // Synchronize crosshair and zoom across charts const disconnect = connectCharts(charts, { syncCrosshair: true, syncZoom: true, }); // Streaming loop const intervalId = setInterval(() => { const timestamp = Date.now(); // Chart 0: Latency metrics charts[0].appendData(0, [[timestamp, 50 + Math.random() * 20]]); charts[0].appendData(1, [[timestamp, 100 + Math.random() * 50]]); // Chart 1: Throughput charts[1].appendData(0, [[timestamp, 1000 + Math.random() * 500]]); // Chart 2: Resources charts[2].appendData(0, [[timestamp, 30 + Math.random() * 40]]); charts[2].appendData(1, [[timestamp, 50 + Math.random() * 30]]); }, 200); // Cleanup (proper order is critical) function cleanup() { clearInterval(intervalId); disconnect(); charts.forEach(chart => chart.dispose()); device.destroy(); } window.addEventListener('beforeunload', cleanup); return { charts, cleanup }; } createDashboard(); ``` ## Theming (Dark/Light and Custom) Apply built-in themes or create custom theme configurations with full control over colors, typography, and styling. ```typescript import { ChartGPU, darkTheme, lightTheme, getTheme } from 'chartgpu'; import type { ChartGPUOptions, ThemeConfig } from 'chartgpu'; async function createThemedChart() { const container = document.getElementById('chart')!; // Option 1: Use preset name const darkOptions: ChartGPUOptions = { theme: 'dark', // or 'light' series: [{ type: 'line', data: [[0, 1], [1, 3], [2, 2]] }], }; // Option 2: Extend preset with overrides const customDarkOptions: ChartGPUOptions = { theme: { ...darkTheme, backgroundColor: '#1e1e2e', colorPalette: ['#ff6b9d', '#4ecdc4', '#45b7d1'], }, series: [{ type: 'line', data: [[0, 1], [1, 3], [2, 2]] }], }; // Option 3: Full custom theme const customTheme: ThemeConfig = { backgroundColor: '#09090d', textColor: '#b0b0b0', axisLineColor: 'rgba(255,255,255,0.15)', axisTickColor: 'rgba(255,255,255,0.35)', gridLineColor: 'rgba(255,255,255,0.06)', colorPalette: ['#00E5FF', '#FF2D95', '#B026FF', '#00F5A0', '#FFD300'], fontFamily: 'system-ui, -apple-system, sans-serif', fontSize: 11, }; const fullCustomOptions: ChartGPUOptions = { theme: customTheme, series: [{ type: 'line', data: [[0, 1], [1, 3], [2, 2]] }], }; // Option 4: Override palette only const paletteOverrideOptions: ChartGPUOptions = { theme: 'dark', palette: ['#FF6384', '#36A2EB', '#FFCE56'], // Overrides theme palette series: [ { type: 'line', data: [[0, 1], [1, 2], [2, 3]] }, { type: 'line', data: [[0, 3], [1, 2], [2, 1]] }, { type: 'line', data: [[0, 2], [1, 3], [2, 2]] }, ], }; const chart = await ChartGPU.create(container, paletteOverrideOptions); return chart; } createThemedChart(); ``` ## Event Handling and Interaction Subscribe to chart events for click, hover, crosshair movement, zoom changes, and data append notifications. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions } from 'chartgpu'; async function createInteractiveChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { xAxis: { type: 'value' }, yAxis: { type: 'value' }, tooltip: { show: true, trigger: 'axis' }, dataZoom: [{ type: 'inside' }], series: [{ type: 'line', name: 'Series A', data: [[0, 1], [1, 3], [2, 2], [3, 5], [4, 4]] }], }; const chart = await ChartGPU.create(container, options); // Click event chart.on('click', (payload) => { console.log('Click:', { seriesIndex: payload.seriesIndex, dataIndex: payload.dataIndex, value: payload.value, seriesName: payload.seriesName, }); }); // Hover events chart.on('mouseover', (payload) => { console.log('Hover in:', payload.seriesName, payload.value); }); chart.on('mouseout', (payload) => { console.log('Hover out:', payload.seriesName); }); // Crosshair movement (includes sync updates) chart.on('crosshairMove', (payload) => { console.log('Crosshair X:', payload.x); // null when pointer leaves }); // Zoom range changes chart.on('zoomRangeChange', (payload) => { console.log('Zoom:', payload.start, '% -', payload.end, '%'); console.log('Source:', payload.sourceKind); // 'user' | 'auto-scroll' | 'api' }); // Data append (streaming) chart.on('dataAppend', (payload) => { console.log('Appended:', payload.count, 'points to series', payload.seriesIndex); console.log('X extent:', payload.xExtent.min, '-', payload.xExtent.max); }); // Programmatic zoom control const range = chart.getZoomRange(); console.log('Current zoom:', range); chart.setZoomRange(25, 75); // Zoom to middle 50% // Remove listener const handler = (p: any) => console.log(p); chart.on('click', handler); chart.off('click', handler); return chart; } createInteractiveChart(); ``` ## Data Zoom Configuration Configure data zoom with inside (wheel/drag) and slider UI components. Supports min/max span constraints for zoom limiting. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions } from 'chartgpu'; async function createZoomableChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { grid: { left: 70, right: 24, top: 24, bottom: 44 }, xAxis: { type: 'value' }, yAxis: { type: 'value', autoBounds: 'visible', // Y-axis scales to visible data during zoom (default) // autoBounds: 'global', // Keep Y-axis fixed to full dataset }, dataZoom: [ { type: 'inside', // Wheel zoom + shift-drag pan start: 0, end: 100, minSpan: 5, // Minimum zoom: 5% of data maxSpan: 100, // Maximum zoom: 100% (no limit) }, { type: 'slider', // Slider UI below chart start: 0, end: 100, }, ], series: [ { type: 'line', data: Array.from({ length: 1000 }, (_, i) => [i, Math.sin(i * 0.1) + Math.random() * 0.2]), sampling: 'lttb', // Enable LTTB downsampling samplingThreshold: 500, // Sample when > 500 points visible }, ], }; const chart = await ChartGPU.create(container, options); return chart; } createZoomableChart(); ``` ## Custom Axis Tick Formatters Customize axis label formatting with tick formatter functions for time, percentages, units, and more. ```typescript import { ChartGPU } from 'chartgpu'; import type { ChartGPUOptions } from 'chartgpu'; async function createFormattedChart() { const container = document.getElementById('chart')!; const options: ChartGPUOptions = { xAxis: { type: 'time', // Custom time formatter (receives timestamp in ms) tickFormatter: (ms) => { const date = new Date(ms); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); }, }, yAxis: { type: 'value', // Custom value formatter with units tickFormatter: (value) => { if (value >= 1000) return `${(value / 1000).toFixed(1)}k ms`; return `${value.toFixed(0)} ms`; }, }, series: [ { type: 'line', data: [ [Date.now() - 86400000 * 7, 150], [Date.now() - 86400000 * 6, 280], [Date.now() - 86400000 * 5, 420], [Date.now() - 86400000 * 4, 1200], [Date.now() - 86400000 * 3, 890], [Date.now() - 86400000 * 2, 650], [Date.now() - 86400000, 480], ], }, ], }; // Example formatters for different use cases: // Percentage: (v) => `${(v * 100).toFixed(0)}%` // Duration: (s) => `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m` // Integer: (v) => Number.isInteger(v) ? v.toLocaleString() : null // Currency: (v) => `$${v.toFixed(2)}` const chart = await ChartGPU.create(container, options); return chart; } createFormattedChart(); ``` ## React Integration ChartGPU provides React bindings via the `chartgpu-react` package for seamless integration with React applications. ```tsx // npm install chartgpu-react import { ChartGPUChart } from 'chartgpu-react'; import type { ChartGPUOptions } from 'chartgpu'; function MyChart() { const options: ChartGPUOptions = { series: [ { type: 'line', data: [[0, 1], [1, 3], [2, 2], [3, 5], [4, 4]], }, ], xAxis: { type: 'value' }, yAxis: { type: 'value' }, }; return ( <ChartGPUChart options={options} style={{ width: '100%', height: '400px' }} /> ); } export default MyChart; ``` ## Summary ChartGPU is designed for high-performance data visualization scenarios where traditional charting libraries struggle. Its primary use cases include real-time streaming dashboards (APM monitoring, financial trading terminals, IoT sensor displays), large dataset exploration (scientific visualization, log analysis, scatter density plots), and multi-chart synchronized dashboards. The library excels when rendering millions of data points while maintaining 60 FPS interactivity, making it ideal for applications that require both visual fidelity and responsive user interaction. Integration patterns center around the `ChartGPU.create()` factory method for initialization, `appendData()` for streaming updates, and `setOption()` for configuration changes. For dashboards, sharing a `GPUDevice` via the third context parameter significantly reduces resource usage, while `connectCharts()` enables synchronized crosshair and zoom interactions. The annotation system supports both declarative configuration and interactive authoring with full undo/redo support. Browser requirements (Chrome 113+, Edge 113+, Safari 18+) ensure WebGPU availability, and proper cleanup via `dispose()` prevents GPU resource leaks in long-running applications.