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 - Angular

Overview

This example, "Synchronise Multiple Charts", demonstrates how to synchronise layout, visible ranges, and data series across multiple dynamic chart components in an Angular application using SciChart.js. The implementation focuses on coordinating zoom, pan, and overview series updates among various charts to deliver a consistent and responsive dashboard experience.

Technical Implementation

The core of the implementation is a custom AxisSynchroniser class that manages the visible range state across multiple X axes. Each chart’s axis subscribes to range change events, and any update is propagated to all linked charts. The charts are created dynamically by invoking SciChart.js methods such as SciChartSurface.create() and instantiating axes like NumericAxis, without the use of a Builder API, ensuring that every chart is independently rendered and easily synchronised. This approach also leverages Angular’s component lifecycle techniques (similar to ngOnInit and ngOnDestroy as explained in the Angular Component Lifecycle) to handle proper initialisation and cleanup, thereby avoiding memory leaks as detailed in the Memory Best Practices documentation.

Features and Capabilities

The example supports real-time updating of charts with dynamic data, synchronized zooming and panning, and an interactive overview chart that controls the visible range of the main charts. Users can dynamically add or remove charts, and toggle synchronization using built-in UI controls. The custom implementation seamlessly links the primary charts with an overview component by copying series data and manually managing event handlers for range updates. This interactivity and custom synchronisation mechanism reflect advanced features of SciChart.js and provide a robust foundation for developing high-performance, multi-chart Angular dashboards.

Integration and Best Practices

Designed specifically for Angular, this example follows best practices for integration by utilising Angular Material and Flexbox for layout management, ensuring a fully responsive multi-chart dashboard as described in resources like Angular Material and CSS Flex Layout. Additionally, efficient resource management is demonstrated through rigorous cleanup routines and controlled event subscription handling, principles that are essential in Angular applications. For organizing chart synchronisation logic, the use of dependency injection with Angular services can further modularise and enhance maintainability, aligning with the strategies outlined in Angular Services and Dependency Injection Explained. Finally, developers interested in advanced synchronisation techniques might find it beneficial to review the strategies provided in the Tutorial 09 - Linking Multiple Charts for a deeper technical context.

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