Synchronise Multiple Charts

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.

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

RandomWalkGenerator.ts

theme.ts

AxisSynchroniser.ts

Copy to clipboard
Minimise
Fullscreen
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};
122

Synchronise Multiple Charts using JavaScript

Overview

This 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.

Technical Implementation

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.

Features and Capabilities

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.

Integration and Best Practices

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.

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