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        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};
124

Synchronise Multiple Charts - React

Overview

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

Technical Implementation

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.

Features and Capabilities

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.

Integration and Best Practices

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.

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