This example demonstrates how to synchronise layout and visible range across multiple dynamic charts, and how to synchronise series with an overview chart.using SciChart.js, High Performance JavaScript Charts
Click and drag or mousewheel to zoom/pan the charts.
drawExample.ts
index.tsx
RandomWalkGenerator.ts
theme.ts
AxisSynchroniser.ts
1import {
2 EAutoRange,
3 EAxisAlignment,
4 EExecuteOn,
5 FastLineRenderableSeries,
6 IRenderableSeries,
7 MouseWheelZoomModifier,
8 NumberRange,
9 NumericAxis,
10 OverviewRangeSelectionModifier,
11 RolloverModifier,
12 RubberBandXyZoomModifier,
13 SciChartSurface,
14 XyDataSeries,
15 ZoomExtentsModifier,
16 ZoomPanModifier,
17 buildSeries,
18} from "scichart";
19import { RandomWalkGenerator } from "../../../ExampleData/RandomWalkGenerator";
20import { appTheme } from "../../../theme";
21import { AxisSynchroniser } from "./AxisSynchroniser";
22
23export const createChart = async (divId: string, id: number) => {
24 const { wasmContext, sciChartSurface } = await SciChartSurface.create(divId, {
25 id: divId,
26 theme: appTheme.SciChartJsTheme,
27 disableAspect: true,
28 });
29
30 // Create and add an XAxis and YAxis
31 sciChartSurface.xAxes.add(new NumericAxis(wasmContext, {}));
32 sciChartSurface.yAxes.add(
33 new NumericAxis(wasmContext, {
34 autoRange: EAutoRange.Always,
35 growBy: new NumberRange(0.1, 0.1),
36 axisAlignment: EAxisAlignment.Left,
37 })
38 );
39
40 const stroke = appTheme.SciChartJsTheme.getStrokeColor(id, 5, wasmContext);
41 const POINTS = 1000;
42 const data0 = new RandomWalkGenerator().Seed((id + 1) * 10).getRandomWalkSeries(POINTS);
43 sciChartSurface.renderableSeries.add(
44 new FastLineRenderableSeries(wasmContext, {
45 dataSeries: new XyDataSeries(wasmContext, { xValues: data0.xValues, yValues: data0.yValues }),
46 strokeThickness: 3,
47 stroke,
48 })
49 );
50
51 // Use modifierGroup to trigger the modifier in the same place on multiple charts
52 sciChartSurface.chartModifiers.add(
53 new RolloverModifier({ modifierGroup: "one" }),
54 new RubberBandXyZoomModifier({
55 executeCondition: { button: EExecuteOn.MouseRightButton },
56 modifierGroup: "one",
57 }),
58 // These do not need modifierGroup as the xAxes are synchronised.
59 new ZoomPanModifier({ enableZoom: true }),
60 new ZoomExtentsModifier(),
61 new MouseWheelZoomModifier()
62 );
63
64 return { sciChartSurface, wasmContext };
65};
66
67export const createOverview = async (divId: string, axisSynchroniser: AxisSynchroniser) => {
68 // Note this does not use SciChartOverview.
69 // Instead we create a normal chart and then manually add the OverviewRangeSelectionModifier and bind it to the axisSynchroniser
70 const { wasmContext, sciChartSurface } = await SciChartSurface.create(divId, {
71 id: divId,
72 theme: appTheme.SciChartJsTheme,
73 });
74
75 // Create and add an XAxis and YAxis
76 const xAxis = new NumericAxis(wasmContext, { visibleRange: new NumberRange(0, 1000), autoRange: EAutoRange.Never });
77 sciChartSurface.xAxes.add(xAxis);
78 sciChartSurface.yAxes.add(
79 new NumericAxis(wasmContext, {
80 autoRange: EAutoRange.Always,
81 growBy: new NumberRange(0.1, 0.1),
82 axisAlignment: EAxisAlignment.Left,
83 })
84 );
85
86 const rangeSelectionModifier = new OverviewRangeSelectionModifier();
87 // When the range selection is moved, updated the linked charts
88 rangeSelectionModifier.onSelectedAreaChanged = (selectedRange: NumberRange) => {
89 if (!selectedRange.equals(axisSynchroniser.visibleRange)) {
90 axisSynchroniser.publishChange({ visibleRange: selectedRange }, xAxis);
91 }
92 };
93 rangeSelectionModifier.selectedArea = axisSynchroniser.visibleRange;
94 sciChartSurface.chartModifiers.add(rangeSelectionModifier);
95
96 // When charts are moved, update the range selection
97 axisSynchroniser.visibleRangeChanged.subscribe(({ visibleRange }) => {
98 const updatedSelectedRange = visibleRange.clip(xAxis.visibleRange);
99 const shouldUpdateSelectedRange = !updatedSelectedRange.equals(rangeSelectionModifier.selectedArea);
100 if (shouldUpdateSelectedRange) {
101 rangeSelectionModifier.selectedArea = updatedSelectedRange;
102 }
103 });
104 return { wasmContext, sciChartSurface };
105};
106
107export const addToOverview = (series: IRenderableSeries, overview: SciChartSurface) => {
108 // Deep clone the series but without the data
109 const cloneSeries = buildSeries(overview.webAssemblyContext2D, series.toJSON(true))[0];
110 // Reference the original data
111 cloneSeries.dataSeries = series.dataSeries;
112 // Clear the axisIds so the series will automatically be assigned to the default axes on the overview.
113 // in v4 we can no longer rely on the axisIds being DefaultAxisId
114 cloneSeries.xAxisId = undefined;
115 cloneSeries.yAxisId = undefined;
116 overview.renderableSeries.add(cloneSeries);
117};
118
119export const removeFromOverview = (series: IRenderableSeries, overview: SciChartSurface) => {
120 const overviewSeries = overview.renderableSeries.getById(series.id);
121 // Do not delete children as this is using shared data
122 overview.renderableSeries.remove(overviewSeries, false);
123};
124This example demonstrates how to synchronise layout and visible range across multiple dynamic charts in a React application using SciChart.js. It features a main overview chart that is linked to several dynamic charts, allowing the user to zoom and pan in one chart and see the changes reflected in the others.
The implementation utilizes React hooks such as useState, useRef, and useEffect to manage the lifecycle of each SciChartSurface component dynamically. A custom AxisSynchroniser class manages the visible range updates for all linked X axes, ensuring synchronized navigation across charts. The example also demonstrates how to clone series for the overview chart using SciChart.js methods, and integrates various chart modifiers like RolloverModifier, RubberBandXyZoomModifier, ZoomPanModifier, and MouseWheelZoomModifier to enhance interactivity. For further technical details on synchronizing charts, refer to the Synchronizing Multiple Charts Documentation.
This example offers several advanced features including real-time dynamic chart rendering, coordinated zooming and panning across multiple charts, and interactive adding or removing of chart components. Custom event handling through the AxisSynchroniser class allows for smooth updates between the main charts and the overview. The efficient use of custom event handling for axis ranging ensures that performance remains optimal even during dynamic data updates.
Built exclusively with React, this example highlights best practices for integrating third-party libraries like SciChart.js into a React project. The use of refs for managing instances such as SciChartVerticalGroup, combined with meticulous cleanup within the useEffect hook, adheres to performance optimization techniques as detailed in the Memory Best Practices. Additionally, the integration of Material UI components for layout management provides a clear example of how to combine modern UI toolkits with high-performance charting. Developers looking for an in-depth understanding of React integration can explore the guidance provided in Creating a SciChart React Component from the Ground Up.

Create a React Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

This dashboard demo showcases the incredible realtime performance of our React charts by updating the series with millions of data-points!