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 theme: appTheme.SciChartJsTheme,
26 disableAspect: true,
27 });
28
29 // Create and add an XAxis and YAxis
30 sciChartSurface.xAxes.add(new NumericAxis(wasmContext, {}));
31 sciChartSurface.yAxes.add(
32 new NumericAxis(wasmContext, {
33 autoRange: EAutoRange.Always,
34 growBy: new NumberRange(0.1, 0.1),
35 axisAlignment: EAxisAlignment.Left,
36 })
37 );
38
39 const stroke = appTheme.SciChartJsTheme.getStrokeColor(id, 5, wasmContext);
40 const POINTS = 1000;
41 const data0 = new RandomWalkGenerator().Seed((id + 1) * 10).getRandomWalkSeries(POINTS);
42 sciChartSurface.renderableSeries.add(
43 new FastLineRenderableSeries(wasmContext, {
44 dataSeries: new XyDataSeries(wasmContext, { xValues: data0.xValues, yValues: data0.yValues }),
45 strokeThickness: 3,
46 stroke,
47 })
48 );
49
50 // Use modifierGroup to trigger the modifier in the same place on multiple charts
51 sciChartSurface.chartModifiers.add(
52 new RolloverModifier({ modifierGroup: "one" }),
53 new RubberBandXyZoomModifier({
54 executeCondition: { button: EExecuteOn.MouseRightButton },
55 modifierGroup: "one",
56 }),
57 // These do not need modifierGroup as the xAxes are synchronised.
58 new ZoomPanModifier({ enableZoom: true }),
59 new ZoomExtentsModifier(),
60 new MouseWheelZoomModifier()
61 );
62
63 return { sciChartSurface, wasmContext };
64};
65
66export const createOverview = async (divId: string, axisSynchroniser: AxisSynchroniser) => {
67 // Note this does not use SciChartOverview.
68 // Instead we create a normal chart and then manually add the OverviewRangeSelectionModifier and bind it to the axisSynchroniser
69 const { wasmContext, sciChartSurface } = await SciChartSurface.create(divId, {
70 theme: appTheme.SciChartJsTheme,
71 });
72
73 // Create and add an XAxis and YAxis
74 const xAxis = new NumericAxis(wasmContext, { visibleRange: new NumberRange(0, 1000), autoRange: EAutoRange.Never });
75 sciChartSurface.xAxes.add(xAxis);
76 sciChartSurface.yAxes.add(
77 new NumericAxis(wasmContext, {
78 autoRange: EAutoRange.Always,
79 growBy: new NumberRange(0.1, 0.1),
80 axisAlignment: EAxisAlignment.Left,
81 })
82 );
83
84 const rangeSelectionModifier = new OverviewRangeSelectionModifier();
85 // When the range selection is moved, updated the linked charts
86 rangeSelectionModifier.onSelectedAreaChanged = (selectedRange: NumberRange) => {
87 if (!selectedRange.equals(axisSynchroniser.visibleRange)) {
88 axisSynchroniser.publishChange({ visibleRange: selectedRange }, xAxis);
89 }
90 };
91 rangeSelectionModifier.selectedArea = axisSynchroniser.visibleRange;
92 sciChartSurface.chartModifiers.add(rangeSelectionModifier);
93
94 // When charts are moved, update the range selection
95 axisSynchroniser.visibleRangeChanged.subscribe(({ visibleRange }) => {
96 const updatedSelectedRange = visibleRange.clip(xAxis.visibleRange);
97 const shouldUpdateSelectedRange = !updatedSelectedRange.equals(rangeSelectionModifier.selectedArea);
98 if (shouldUpdateSelectedRange) {
99 rangeSelectionModifier.selectedArea = updatedSelectedRange;
100 }
101 });
102 return { wasmContext, sciChartSurface };
103};
104
105export const addToOverview = (series: IRenderableSeries, overview: SciChartSurface) => {
106 // Deep clone the series but without the data
107 const cloneSeries = buildSeries(overview.webAssemblyContext2D, series.toJSON(true))[0];
108 // Reference the original data
109 cloneSeries.dataSeries = series.dataSeries;
110 // Clear the axisIds so the series will automatically be assigned to the default axes on the overview.
111 // in v4 we can no longer rely on the axisIds being DefaultAxisId
112 cloneSeries.xAxisId = undefined;
113 cloneSeries.yAxisId = undefined;
114 overview.renderableSeries.add(cloneSeries);
115};
116
117export const removeFromOverview = (series: IRenderableSeries, overview: SciChartSurface) => {
118 const overviewSeries = overview.renderableSeries.getById(series.id);
119 // Do not delete children as this is using shared data
120 overview.renderableSeries.remove(overviewSeries, false);
121};
122This example demonstrates how to synchronise layout, visible ranges, and data series across multiple dynamic charts using SciChart.js in a JavaScript environment. The implementation includes a manually configured overview chart that controls the visible range for all the main charts, delivering a cohesive and interactive dashboard experience.
The example employs a custom AxisSynchroniser class that implements custom event handling to listen for visible range changes and propagate updates to all linked axes. For details on how to listen to visible range changes, refer to the Axis Ranging Documentation. In addition, the overview chart is manually implemented by adding an OverviewRangeSelectionModifier to a standard SciChartSurface. This approach ensures that when the selected area in the overview changes, the new range is immediately applied to the main charts. The overall coordination of multiple charts is in line with the techniques described in Synchronizing Multiple Charts and the methods outlined in Linking JavaScript Charts and Synchronising Zooming, Panning, Crosshairs.
This example showcases several advanced features, including real-time dynamic chart rendering, coordinated zooming and panning through modifier groups such as RolloverModifier and RubberBandXyZoomModifier, and dynamic addition or removal of chart instances. The ability to clone renderable series for integration into the overview chart ensures that data continuity is maintained without data duplication.
By relying solely on JavaScript, the example adheres to efficient memory and resource management practices, including the proper cleanup of SciChartSurface objects when charts are removed. For further guidance on integrating SciChart.js and optimising performance, developers are encouraged to review the SciChart.js JavaScript Charts User Manual and the article on Performance Optimisation of JavaScript Applications & Charts. The techniques demonstrated here provide a solid foundation for building high-performance, interactive chart dashboards with SciChart.js.

Create a JavaScript 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 JavaScript charts by updating the series with millions of data-points!