22
33React bindings for [ ChartGPU] ( https://github.com/huntergemmer/chart-gpu ) - a WebGPU-powered charting library delivering high-performance data visualization.
44
5- ## Features
5+ ## Documentation
66
7- - ** WebGPU-Accelerated** : Leverages GPU compute and rendering for exceptional performance
8- - ** React 18+** : Built with modern React patterns (hooks, functional components)
9- - ** Type-Safe** : Full TypeScript support with comprehensive type definitions
10- - ** Production-Ready** : Handles async initialization, cleanup, and edge cases safely
11- - ** Flexible API** : Declarative options-based configuration
7+ - ** Getting started** : [ ` docs/GETTING_STARTED.md ` ] ( ./docs/GETTING_STARTED.md )
8+ - ** API reference** : [ ` docs/API.md ` ] ( ./docs/API.md )
9+ - ** Recipes** :
10+ - [ ` onCrosshairMove ` ] ( ./docs/recipes/crosshair-move.md )
11+ - [ ` useConnectCharts ` / ` connectCharts ` ] ( ./docs/recipes/chart-sync.md )
12+ - [ ` createAnnotationAuthoring ` ] ( ./docs/recipes/annotation-authoring.md )
13+ - [ ` appendData ` streaming] ( ./docs/recipes/streaming.md )
14+ - [ ` dataZoom ` + ` onZoomChange ` ] ( ./docs/recipes/datazoom-basics.md )
1215
1316## Installation
1417
@@ -29,10 +32,11 @@ Check browser compatibility at [caniuse.com/webgpu](https://caniuse.com/webgpu)
2932## Quick Start
3033
3134``` tsx
32- import { ChartGPUChart } from ' chartgpu-react' ;
35+ import { ChartGPU } from ' chartgpu-react' ;
36+ import type { ChartGPUOptions } from ' chartgpu-react' ;
3337
3438function MyChart() {
35- const options = {
39+ const options: ChartGPUOptions = {
3640 series: [
3741 {
3842 type: ' line' ,
@@ -53,133 +57,138 @@ function MyChart() {
5357 };
5458
5559 return (
56- <ChartGPUChart
60+ <ChartGPU
5761 options = { options }
5862 style = { { width: ' 100%' , height: ' 400px' }}
5963 />
6064 );
6165}
6266```
6367
64- ## Component API
68+ ## What this package provides
6569
66- ### ` ChartGPUChart `
70+ - ** ` ChartGPU ` ** React component (recommended)
71+ - lifecycle management (async create + dispose)
72+ - ` ResizeObserver ` resize (debounced)
73+ - event props: ` onClick ` , ` onCrosshairMove ` , ` onZoomChange ` , etc.
74+ - imperative ` ref ` API: ` ChartGPUHandle ` (` getChart ` , ` getContainer ` , ` appendData ` , ` setOption ` )
75+ - ** Hooks**
76+ - ` useChartGPU(containerRef, options) ` — create/manage a chart instance
77+ - ` useConnectCharts([chartA, chartB, ...]) ` — sync crosshair/interaction-x across charts
78+ - ** Deprecated**
79+ - ` ChartGPUChart ` (legacy adapter; use ` ChartGPU ` instead)
80+ - ** Helper re-exports** (from peer dependency ` chartgpu ` )
81+ - ` createChart ` , ` connectCharts ` , ` createAnnotationAuthoring `
6782
68- Main React component wrapping ChartGPU functionality .
83+ For details, start with the [ API reference ] ( ./docs/API.md ) .
6984
70- #### Props
85+ ## v0.2.3 feature snippets (ChartGPU core)
7186
72- | Prop | Type | Required | Description |
73- | ------| ------| ----------| -------------|
74- | ` options ` | ` ChartGPUOptions ` | Yes | Chart configuration (series, axes, styling) |
75- | ` className ` | ` string ` | No | CSS class name for the container div |
76- | ` style ` | ` React.CSSProperties ` | No | Inline styles for the container div |
77- | ` onInit ` | ` (instance: ChartGPUInstance) => void ` | No | Callback fired when chart instance is created |
78- | ` onDispose ` | ` () => void ` | No | Callback fired when chart instance is disposed |
87+ These snippets use helpers and events from the ` chartgpu ` core library (peer dependency of ` chartgpu-react ` ).
7988
80- #### Behavior
89+ ### Crosshair / interaction X ( ` 'crosshairMove' ` )
8190
82- ** Lifecycle Management:**
83- - Creates ChartGPU instance on mount via ` ChartGPU.create() `
84- - Safely handles async initialization race conditions
85- - Automatically disposes instance on unmount
86- - Prevents state updates after component unmount
91+ ``` tsx
92+ import { ChartGPU } from ' chartgpu-react' ;
93+ import type { ChartGPUCrosshairMovePayload } from ' chartgpu-react' ;
94+
95+ <ChartGPU
96+ options = { options }
97+ onCrosshairMove = { (p : ChartGPUCrosshairMovePayload ) => {
98+ // p.x is the current interaction x (domain units), or null when cleared
99+ console .log (' crosshair x:' , p .x , ' source:' , p .source );
100+ }}
101+ />;
102+ ```
87103
88- ** Options Updates:**
89- - Calls ` instance.setOption(options) ` when ` options ` prop changes
90- - Triggers automatic re-render of the chart
104+ ### Connect charts (sync crosshair/tooltip)
91105
92- ** Resize Handling:**
93- - Listens to window resize events
94- - Calls ` instance.resize() ` automatically
95- - Ensures chart maintains correct dimensions
106+ ``` tsx
107+ import { connectCharts } from ' chartgpu' ;
96108
97- ## Examples
109+ // When you have two ChartGPUInstance objects:
110+ const disconnect = connectCharts ([chartA , chartB ]);
111+
112+ // Later:
113+ disconnect ();
114+ ```
115+
116+ If you prefer a hook-driven approach, you can use ` onReady ` (or ` useChartGPU ` ) to capture instances, then call ` connectCharts(...) ` once both are available.
98117
99- ### Multi-Series Line Chart
118+ ### Annotation authoring UI ( ` createAnnotationAuthoring ` )
100119
101120``` tsx
102- import { ChartGPUChart } from ' chartgpu-react' ;
121+ import { useEffect , useRef , useState } from ' react' ;
122+ import { ChartGPU } from ' chartgpu-react' ;
123+ import type { ChartGPUHandle , ChartGPUInstance } from ' chartgpu-react' ;
124+ import { createAnnotationAuthoring } from ' chartgpu-react' ;
125+
126+ function AnnotationAuthoringExample() {
127+ const chartRef = useRef <ChartGPUHandle >(null );
128+ const [chart, setChart] = useState <ChartGPUInstance | null >(null );
129+
130+ useEffect (() => {
131+ const container = chartRef .current ?.getContainer ();
132+ const instance = chartRef .current ?.getChart ();
133+ if (! container || ! instance ) return ;
134+
135+ const authoring = createAnnotationAuthoring (container , instance , {
136+ enableContextMenu: true ,
137+ });
103138
104- function MultiSeriesExample() {
105- const options = {
106- series: [
107- {
108- type: ' line' ,
109- name: ' Revenue' ,
110- data: generateData (50 ),
111- lineStyle: { color: ' #667eea' , width: 2 },
112- },
113- {
114- type: ' line' ,
115- name: ' Expenses' ,
116- data: generateData (50 ),
117- lineStyle: { color: ' #f093fb' , width: 2 },
118- },
119- ],
120- xAxis: { type: ' value' },
121- yAxis: { type: ' value' },
122- grid: { left: 60 , right: 40 , top: 40 , bottom: 40 },
123- tooltip: { show: true },
124- };
139+ // IMPORTANT: dispose authoring before disposing the chart
140+ return () => authoring .dispose ();
141+ }, [chart ]);
125142
126- return (
127- <ChartGPUChart
128- options = { options }
129- style = { { width: ' 100%' , height: ' 400px' }}
130- />
131- );
143+ return <ChartGPU ref = { chartRef } options = { options } onReady = { setChart } />;
132144}
133145```
134146
135- ### Area Chart with Gradient
147+ ### Candlestick streaming ( ` appendData ` + ` OHLCDataPoint ` )
136148
137149``` tsx
138- function AreaChartExample() {
139- const options = {
150+ import { useEffect , useRef } from ' react' ;
151+ import { ChartGPU } from ' chartgpu-react' ;
152+ import type { ChartGPUHandle , ChartGPUOptions } from ' chartgpu-react' ;
153+ import type { OHLCDataPoint } from ' chartgpu' ;
154+
155+ function CandlestickStreaming() {
156+ const ref = useRef <ChartGPUHandle >(null );
157+
158+ const options: ChartGPUOptions = {
159+ xAxis: { type: ' time' },
160+ dataZoom: [{ type: ' inside' }, { type: ' slider' }],
161+ autoScroll: true ,
140162 series: [
141163 {
142- type: ' line' ,
143- data: generateSineWave (100 ),
144- lineStyle: { color: ' #667eea' , width: 2 },
145- areaStyle: { color: ' rgba(102, 126, 234, 0.2)' },
164+ type: ' candlestick' ,
165+ sampling: ' ohlc' ,
166+ data: [], // start empty; stream in candles below
146167 },
147168 ],
148- xAxis: { type: ' value' },
149- yAxis: { type: ' value' },
150169 };
151170
152- return <ChartGPUChart options = { options } style = { { height: ' 300px' }} />;
171+ useEffect (() => {
172+ const timer = window .setInterval (() => {
173+ const next: OHLCDataPoint = {
174+ timestamp: Date .now (),
175+ open: 100 ,
176+ close: 102 ,
177+ low: 99 ,
178+ high: 103 ,
179+ };
180+ ref .current ?.appendData (0 , [next ]);
181+ }, 500 );
182+ return () => window .clearInterval (timer );
183+ }, []);
184+
185+ return <ChartGPU ref = { ref } options = { options } style = { { height: 360 }} />;
153186}
154187```
155188
156- ### Using Chart Instance Callbacks
157-
158- ``` tsx
159- function ChartWithCallbacks() {
160- const handleInit = (instance : ChartGPUInstance ) => {
161- console .log (' Chart initialized:' , instance );
162-
163- // Add event listeners
164- instance .on (' click' , (payload ) => {
165- console .log (' Chart clicked:' , payload );
166- });
167- };
168-
169- const handleDispose = () => {
170- console .log (' Chart cleaned up' );
171- };
189+ ## Examples
172190
173- return (
174- <ChartGPUChart
175- options = { options }
176- onInit = { handleInit }
177- onDispose = { handleDispose }
178- style = { { height: ' 400px' }}
179- />
180- );
181- }
182- ```
191+ See the runnable example app in [ ` examples/main.tsx ` ] ( ./examples/main.tsx ) .
183192
184193## Development
185194
@@ -246,54 +255,6 @@ import type {
246255} from ' chartgpu-react' ;
247256```
248257
249- ## Technical Details
250-
251- ### Async Initialization Safety
252-
253- The component uses a mounted ref pattern to prevent React state updates after unmount:
254-
255- ``` typescript
256- useEffect (() => {
257- mountedRef .current = true ;
258-
259- const initChart = async () => {
260- const instance = await ChartGPU .create (container , options );
261-
262- // Only update state if still mounted
263- if (mountedRef .current ) {
264- instanceRef .current = instance ;
265- } else {
266- // Dispose immediately if unmounted during async create
267- instance .dispose ();
268- }
269- };
270-
271- initChart ();
272-
273- return () => {
274- mountedRef .current = false ;
275- instanceRef .current ?.dispose ();
276- };
277- }, []);
278- ```
279-
280- This pattern ensures:
281- 1 . No memory leaks from orphaned chart instances
282- 2 . No React warnings about setState on unmounted components
283- 3 . Clean resource cleanup even if creation takes time
284-
285- ### Options Updates
286-
287- Options changes trigger ` setOption() ` on the existing instance rather than recreating the chart:
288-
289- ``` typescript
290- useEffect (() => {
291- instanceRef .current ?.setOption (options );
292- }, [options ]);
293- ```
294-
295- This provides better performance for dynamic data updates.
296-
297258## Browser Compatibility
298259
299260WebGPU is required. Check support at runtime:
0 commit comments