React Overview for SubCharts with Range Selection

Demonstrates how to create multiple synchronized subcharts with an interactive overview in a React application using SciChart.js

4

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

AxisSynchroniser.ts

theme.ts

SubChartsOverviewModifier.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    SciChartSurface,
3    NumericAxis,
4    NumberRange,
5    FastLineRenderableSeries,
6    XyDataSeries,
7    ZoomExtentsModifier,
8    MouseWheelZoomModifier,
9    ZoomPanModifier,
10    ESubSurfacePositionCoordinateMode,
11    Rect,
12    EPerformanceMarkType,
13    SciChartSubSurface,
14    I2DSubSurfaceOptions,
15    EAutoRange,
16    RolloverModifier,
17    EXyDirection,
18} from "scichart";
19
20import { appTheme } from "../../../theme";
21import { SubChartsOverviewModifier } from "./SubChartsOverviewModifier";
22import { AxisSynchroniser } from "../../MultiChart/SyncMultiChart/AxisSynchroniser";
23
24const colorsArr = [
25    appTheme.MutedBlue,
26    appTheme.MutedOrange,
27    appTheme.MutedPink,
28    appTheme.MutedPurple,
29    appTheme.MutedRed,
30    appTheme.MutedSkyBlue,
31    appTheme.MutedTeal,
32];
33
34export type TMarkType = EPerformanceMarkType | string;
35
36export interface SubChartConfig {
37    id: string;
38    phase: number;
39    color: string;
40    title: string;
41}
42
43export interface SubChartManager {
44    updateSubCharts: (configs: SubChartConfig[]) => void;
45    addSubChart: (config: SubChartConfig) => void;
46    removeSubChart: (id: string) => void;
47    updateLayout: () => void;
48}
49
50// Helper to create some sample data
51const createLineData = (phase: number) => {
52    const xValues: number[] = [];
53    const yValues: number[] = [];
54    for (let i = 0; i < 500; i++) {
55        const x = i;
56        const y = Math.sin(i * 0.1 + phase);
57        xValues.push(x);
58        yValues.push(y);
59    }
60    return { xValues, yValues };
61};
62
63export const drawExample = async (
64    rootElement: string | HTMLDivElement,
65    initialConfigs: SubChartConfig[]
66): Promise<{ wasmContext: any; sciChartSurface: SciChartSurface; manager: SubChartManager }> => {
67    // Create a SciChartSurface
68    const { wasmContext, sciChartSurface } = await SciChartSurface.create(rootElement);
69
70    // Store references to subcharts for dynamic management
71    const subChartMap = new Map<string, SciChartSubSurface>();
72    const axisSynchroniser = new AxisSynchroniser(new NumberRange(0, 500));
73
74    // Add main axes to the surface for the overview to reference
75    const mainXAxis = new NumericAxis(wasmContext, {
76        id: "mainXAxis",
77        isVisible: false, // Hidden since subcharts have their own axes
78        autoRange: EAutoRange.Always,
79    });
80    const mainYAxis = new NumericAxis(wasmContext, {
81        id: "mainYAxis",
82        isVisible: false, // Hidden since subcharts have their own axes
83        autoRange: EAutoRange.Always,
84    });
85
86    sciChartSurface.xAxes.add(mainXAxis);
87    sciChartSurface.yAxes.add(mainYAxis);
88
89    // Create overview modifier
90    const overviewModifier = new SubChartsOverviewModifier({
91        overviewPosition: new Rect(0, 0.8, 1, 0.2),
92        isTransparent: true,
93        axisTitle: "Overview - All Charts",
94        labelStyle: {
95            color: "#ffffff80",
96            fontSize: 10,
97        },
98        majorTickLineStyle: {
99            color: "#ffffff80",
100            tickSize: 6,
101            strokeThickness: 1,
102        },
103        yAxisGrowBy: new NumberRange(0.1, 0.1),
104    });
105
106    sciChartSurface.chartModifiers.add(overviewModifier);
107
108    const updateLayout = () => {
109        // Simple layout update without recreating subcharts
110        // This is called after add/remove operations to ensure proper spacing
111        // The actual repositioning will be handled by the individual add/remove functions
112    };
113
114    const addSubChart = (config: SubChartConfig, index?: number) => {
115        // Don't add if already exists
116        if (subChartMap.has(config.id)) {
117            return;
118        }
119
120        // For now, just add at the bottom to avoid repositioning existing charts
121        const currentCount = subChartMap.size;
122        const chartIndex = currentCount; // Always add at the end
123
124        // Calculate position: this is a simple approach that may cause overlapping
125        // but avoids the MouseManager issues
126        const rect = new Rect(0, chartIndex * 0.2, 1, 0.2);
127
128        const subChartOptions: I2DSubSurfaceOptions = {
129            id: config.id,
130            position: rect,
131            coordinateMode: ESubSurfacePositionCoordinateMode.Relative,
132        };
133
134        const subChart = SciChartSubSurface.createSubSurface(sciChartSurface, subChartOptions);
135
136        // Create axes for the subchart
137        const subXAxis = new NumericAxis(wasmContext);
138        const subYAxis = new NumericAxis(wasmContext, {
139            growBy: new NumberRange(0.1, 0.1),
140            axisTitle: config.title,
141            axisTitleStyle: { fontSize: 14 },
142            drawMinorGridLines: false,
143        });
144
145        subChart.xAxes.add(subXAxis);
146        subChart.yAxes.add(subYAxis);
147
148        // Create data and series
149        const data = createLineData(config.phase);
150        const dataSeries = new XyDataSeries(wasmContext, {
151            xValues: data.xValues,
152            yValues: data.yValues,
153        });
154
155        const lineSeries = new FastLineRenderableSeries(wasmContext, {
156            dataSeries,
157            strokeThickness: 4,
158            stroke: config.color,
159            opacity: 0.6,
160        });
161
162        // Add to synchronizer and subchart
163        axisSynchroniser.addAxis(subXAxis);
164        subChart.renderableSeries.add(lineSeries);
165
166        // Add modifiers
167        subChart.chartModifiers.add(
168            new ZoomPanModifier(),
169            new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
170            new ZoomExtentsModifier(),
171            new RolloverModifier({ modifierGroup: "one" })
172        );
173
174        // Store reference
175        subChartMap.set(config.id, subChart);
176
177        subChart.zoomExtents();
178    };
179
180    const removeSubChart = (id: string) => {
181        const subChart = subChartMap.get(id);
182        if (subChart) {
183            // Remove from synchronizer
184            const xAxis = subChart.xAxes.get(0);
185            if (xAxis) {
186                axisSynchroniser.removeAxis(xAxis);
187            }
188
189            // Use removeSubChart on the parent surface to properly remove from subChartsProperty array
190            // This prevents MouseManager from iterating over deleted subcharts
191            sciChartSurface.removeSubChart(subChart);
192            subChartMap.delete(id);
193        }
194    };
195
196    const updateSubChart = (id: string, config: SubChartConfig) => {
197        const subChart = subChartMap.get(id);
198        if (subChart) {
199            // Update title
200            const yAxis = subChart.yAxes.get(0);
201            if (yAxis) {
202                yAxis.axisTitle = config.title;
203            }
204
205            // Update color
206            const series = subChart.renderableSeries.get(0) as FastLineRenderableSeries;
207            if (series) {
208                series.stroke = config.color;
209            }
210
211            // Update data if phase changed
212            const data = createLineData(config.phase);
213            if (series && series.dataSeries) {
214                (series.dataSeries as XyDataSeries).clear();
215                (series.dataSeries as XyDataSeries).appendRange(data.xValues, data.yValues);
216            }
217        }
218    };
219
220    const updateSubCharts = (configs: SubChartConfig[]) => {
221        // Use the safer recreate approach to avoid MouseManager issues
222        recreateSubChartsWithLayout(configs);
223    };
224
225    const recreateSubChartsWithLayout = (configs: SubChartConfig[]) => {
226        // Suspend updates to prevent MouseManager from iterating over partially deleted subcharts
227        sciChartSurface.suspendUpdates();
228
229        try {
230            // Clear existing subcharts - use the proper removeSubChart function to ensure cleanup
231            const currentIds = Array.from(subChartMap.keys());
232            currentIds.forEach((id) => {
233                removeSubChart(id);
234            });
235
236            // Recreate with proper layout
237            const count = configs.length;
238            if (count === 0) {
239                sciChartSurface.resumeUpdates();
240                return;
241            }
242
243            configs.forEach((config, index) => {
244                // Calculate position: each subchart takes 1/count of the available 80% height
245                // Y position starts at (index/count) * 0.8 and has height of (1/count) * 0.8
246                const yStart = (index / count) * 0.8;
247                const height = (1 / count) * 0.8;
248                const rect = new Rect(0, yStart, 1, height);
249
250                const subChartOptions: I2DSubSurfaceOptions = {
251                    id: config.id,
252                    position: rect,
253                    coordinateMode: ESubSurfacePositionCoordinateMode.Relative,
254                };
255
256                const subChart = SciChartSubSurface.createSubSurface(sciChartSurface, subChartOptions);
257
258                // Create axes for the subchart
259                const subXAxis = new NumericAxis(wasmContext);
260                const subYAxis = new NumericAxis(wasmContext, {
261                    growBy: new NumberRange(0.1, 0.1),
262                    axisTitle: config.title,
263                    axisTitleStyle: { fontSize: 14 },
264                    drawMinorGridLines: false,
265                });
266
267                subChart.xAxes.add(subXAxis);
268                subChart.yAxes.add(subYAxis);
269
270                // Create data and series
271                const data = createLineData(config.phase);
272                const dataSeries = new XyDataSeries(wasmContext, {
273                    xValues: data.xValues,
274                    yValues: data.yValues,
275                });
276
277                const lineSeries = new FastLineRenderableSeries(wasmContext, {
278                    dataSeries,
279                    strokeThickness: 4,
280                    stroke: config.color,
281                    opacity: 0.6,
282                });
283
284                // Add to synchronizer and subchart
285                axisSynchroniser.addAxis(subXAxis);
286                subChart.renderableSeries.add(lineSeries);
287
288                // Add modifiers
289                subChart.chartModifiers.add(
290                    new ZoomPanModifier(),
291                    new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
292                    new ZoomExtentsModifier(),
293                    new RolloverModifier({ modifierGroup: "one" })
294                );
295
296                // Store reference
297                subChartMap.set(config.id, subChart);
298
299                subChart.zoomExtents();
300            });
301        } finally {
302            sciChartSurface.resumeUpdates();
303        }
304    };
305
306    // Initialize with provided configs
307    initialConfigs.forEach((config) => addSubChart(config));
308
309    sciChartSurface.zoomExtents();
310
311    const manager: SubChartManager = {
312        updateSubCharts,
313        addSubChart,
314        removeSubChart,
315        updateLayout,
316    };
317
318    return { wasmContext, sciChartSurface, manager };
319};
320

Overview for SubCharts – React

Overview

This example demonstrates how to implement a multi-subchart layout with a shared overview in a React application using SciChart.js. Multiple vertically stacked charts are rendered within a single SciChartSurface, each synchronized on the X-axis and controlled through an interactive overview panel.

Technical Implementation

The chart is initialized via the <SciChartReact /> component, which invokes a custom drawExample function. This function dynamically creates several SciChartSubSurface instances, each configured with its own axes, renderable series, and interaction modifiers. An AxisSynchroniser ensures all subcharts maintain the same visible X-range.

The overview functionality is encapsulated in a reusable SubChartsOverviewModifier, which listens for subchart lifecycle events and mirrors their renderable series into an overview subsurface. The OverviewRangeSelectionModifier allows users to control zoom and pan interactions across all subcharts from a single control surface.

Features and Capabilities

React-Friendly Lifecycle Management: Subcharts are safely created and destroyed without React reconciliation conflicts by leveraging SciChart’s internal update suspension mechanisms.

Centralized Zoom Control: Users can zoom and pan all subcharts simultaneously using either direct mouse interaction or the overview range selector.

Reusable Overview Modifier: The overview logic is encapsulated in a custom chart modifier, making it easy to reuse across different dashboards or chart configurations.

High-Performance Real-Time Charts: The example showcases how SciChart.js integrates seamlessly into React while maintaining WebAssembly-powered performance.

Integration and Best Practices

This approach follows best practices for integrating SciChart.js into React by isolating chart creation logic from React rendering. Developers can extend this pattern to support real-time streaming data, dynamic chart layouts, or advanced dashboard interactions. For more guidance, see Creating a SciChart React Component and the React Charts with SciChart.js guide.

react Chart Examples & Demos

See Also: Zoom and Pan a Chart (9 Demos)

React Chart with Multiple X Axes | React Charts | SciChart.js

React Chart with Multiple X Axes

Demonstrates Multiple X & Y Axis on a React Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

React Chart with Secondary Y Axes | SciChart.js Demo

React Chart with Secondary Y Axes

Demonstrates Secondary Y Axis on a React Chart using SciChart.js. SciChart supports unlimited, multiple left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Drag React Chart Axis to Scale or Pan | SciChart.js Demo

Drag React Chart Axis to Scale or Pan

Demonstrates how to Zoom, Scale or Pan individual Axis on a React Chart with SciChart.js AxisDragModifiers

Zoom and Pan a Realtime React Chart | SciChart.js Demo

Zoom and Pan a Realtime React Chart

Demonstrates how to zoom and pan a realtime React Chart while it is updating, with SciChart.js ZoomState API

Zoom and Pan with React Chart multiple Modifiers | SciChart

Zoom and Pan with React Chart multiple Modifiers

Demonstrates how to use multiple Zoom and Pan Modifiers on a React Chart with SciChart.js

Zoom and Pan with Overview Chart | React Charts | SciChart.js

Zoom and Pan with Overview Chart

Demonstrates how to zoom and pan with an Overview Chart

Virtualized React Charts: Load Data on Zoom/Pan | SciChart

Virtualized React Charts: Load Data on Zoom/Pan

shows how to load data on zoom/pan and how to create an overview chart for this case.

React Polar Modifiers | Polar Interactivity Modifiers

React Polar Modifiers | Polar Interactivity Modifiers Demo

Explore SciChart's Polar Interactivity Modifiers including zooming, panning, and cursor tracking. Try the demo to trial the Polar Chart Behavior Modifiers.

NEW!
High Precision Date Axis | React Charts | SciChart.js Demo

High Precision Date Axis

Demonstrates 64-bit precision Date Axis in SciChart.js handling Nanoseconds to Billions of Years

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.