Angular Overview for SubCharts with Range Selection

Demonstrates how to create multiple synchronized subcharts with an interactive overview in an Angular application using SciChart.js

4

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

AxisSynchroniser.ts

theme.ts

SubChartsOverviewModifier.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    SciChartSurface,
3    NumericAxis,
4    NumberRange,
5    FastLineRenderableSeries,
6    XyDataSeries,
7    ZoomExtentsModifier,
8    MouseWheelZoomModifier,
9    ZoomPanModifier,
10    ESubSurfacePositionCoordinateMode,
11    Rect,
12    EPerformanceMarkType,
13    SciChartSubSurface,
14    I2DSubSurfaceOptions,
15    EAutoRange,
16    RolloverModifier,
17    EXyDirection,
18} from "scichart";
19
20import { appTheme } from "../../../theme";
21import { SubChartsOverviewModifier } from "./SubChartsOverviewModifier";
22import { AxisSynchroniser } from "../../MultiChart/SyncMultiChart/AxisSynchroniser";
23
24const colorsArr = [
25    appTheme.MutedBlue,
26    appTheme.MutedOrange,
27    appTheme.MutedPink,
28    appTheme.MutedPurple,
29    appTheme.MutedRed,
30    appTheme.MutedSkyBlue,
31    appTheme.MutedTeal,
32];
33
34export type TMarkType = EPerformanceMarkType | string;
35
36export interface SubChartConfig {
37    id: string;
38    phase: number;
39    color: string;
40    title: string;
41}
42
43export interface SubChartManager {
44    updateSubCharts: (configs: SubChartConfig[]) => void;
45    addSubChart: (config: SubChartConfig) => void;
46    removeSubChart: (id: string) => void;
47    updateLayout: () => void;
48}
49
50// Helper to create some sample data
51const createLineData = (phase: number) => {
52    const xValues: number[] = [];
53    const yValues: number[] = [];
54    for (let i = 0; i < 500; i++) {
55        const x = i;
56        const y = Math.sin(i * 0.1 + phase);
57        xValues.push(x);
58        yValues.push(y);
59    }
60    return { xValues, yValues };
61};
62
63export const drawExample = async (
64    rootElement: string | HTMLDivElement,
65    initialConfigs: SubChartConfig[]
66): Promise<{ wasmContext: any; sciChartSurface: SciChartSurface; manager: SubChartManager }> => {
67    // Create a SciChartSurface
68    const { wasmContext, sciChartSurface } = await SciChartSurface.create(rootElement);
69
70    // Store references to subcharts for dynamic management
71    const subChartMap = new Map<string, SciChartSubSurface>();
72    const axisSynchroniser = new AxisSynchroniser(new NumberRange(0, 500));
73
74    // Add main axes to the surface for the overview to reference
75    const mainXAxis = new NumericAxis(wasmContext, {
76        id: "mainXAxis",
77        isVisible: false, // Hidden since subcharts have their own axes
78        autoRange: EAutoRange.Always,
79    });
80    const mainYAxis = new NumericAxis(wasmContext, {
81        id: "mainYAxis",
82        isVisible: false, // Hidden since subcharts have their own axes
83        autoRange: EAutoRange.Always,
84    });
85
86    sciChartSurface.xAxes.add(mainXAxis);
87    sciChartSurface.yAxes.add(mainYAxis);
88
89    // Create overview modifier
90    const overviewModifier = new SubChartsOverviewModifier({
91        overviewPosition: new Rect(0, 0.8, 1, 0.2),
92        isTransparent: true,
93        axisTitle: "Overview - All Charts",
94        labelStyle: {
95            color: "#ffffff80",
96            fontSize: 10,
97        },
98        majorTickLineStyle: {
99            color: "#ffffff80",
100            tickSize: 6,
101            strokeThickness: 1,
102        },
103        yAxisGrowBy: new NumberRange(0.1, 0.1),
104    });
105
106    sciChartSurface.chartModifiers.add(overviewModifier);
107
108    const updateLayout = () => {
109        // Simple layout update without recreating subcharts
110        // This is called after add/remove operations to ensure proper spacing
111        // The actual repositioning will be handled by the individual add/remove functions
112    };
113
114    const addSubChart = (config: SubChartConfig, index?: number) => {
115        // Don't add if already exists
116        if (subChartMap.has(config.id)) {
117            return;
118        }
119
120        // For now, just add at the bottom to avoid repositioning existing charts
121        const currentCount = subChartMap.size;
122        const chartIndex = currentCount; // Always add at the end
123
124        // Calculate position: this is a simple approach that may cause overlapping
125        // but avoids the MouseManager issues
126        const rect = new Rect(0, chartIndex * 0.2, 1, 0.2);
127
128        const subChartOptions: I2DSubSurfaceOptions = {
129            id: config.id,
130            position: rect,
131            coordinateMode: ESubSurfacePositionCoordinateMode.Relative,
132        };
133
134        const subChart = SciChartSubSurface.createSubSurface(sciChartSurface, subChartOptions);
135
136        // Create axes for the subchart
137        const subXAxis = new NumericAxis(wasmContext);
138        const subYAxis = new NumericAxis(wasmContext, {
139            growBy: new NumberRange(0.1, 0.1),
140            axisTitle: config.title,
141            axisTitleStyle: { fontSize: 14 },
142            drawMinorGridLines: false,
143        });
144
145        subChart.xAxes.add(subXAxis);
146        subChart.yAxes.add(subYAxis);
147
148        // Create data and series
149        const data = createLineData(config.phase);
150        const dataSeries = new XyDataSeries(wasmContext, {
151            xValues: data.xValues,
152            yValues: data.yValues,
153        });
154
155        const lineSeries = new FastLineRenderableSeries(wasmContext, {
156            dataSeries,
157            strokeThickness: 4,
158            stroke: config.color,
159            opacity: 0.6,
160        });
161
162        // Add to synchronizer and subchart
163        axisSynchroniser.addAxis(subXAxis);
164        subChart.renderableSeries.add(lineSeries);
165
166        // Add modifiers
167        subChart.chartModifiers.add(
168            new ZoomPanModifier(),
169            new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
170            new ZoomExtentsModifier(),
171            new RolloverModifier({ modifierGroup: "one" })
172        );
173
174        // Store reference
175        subChartMap.set(config.id, subChart);
176
177        subChart.zoomExtents();
178    };
179
180    const removeSubChart = (id: string) => {
181        const subChart = subChartMap.get(id);
182        if (subChart) {
183            // Remove from synchronizer
184            const xAxis = subChart.xAxes.get(0);
185            if (xAxis) {
186                axisSynchroniser.removeAxis(xAxis);
187            }
188
189            // Use removeSubChart on the parent surface to properly remove from subChartsProperty array
190            // This prevents MouseManager from iterating over deleted subcharts
191            sciChartSurface.removeSubChart(subChart);
192            subChartMap.delete(id);
193        }
194    };
195
196    const updateSubChart = (id: string, config: SubChartConfig) => {
197        const subChart = subChartMap.get(id);
198        if (subChart) {
199            // Update title
200            const yAxis = subChart.yAxes.get(0);
201            if (yAxis) {
202                yAxis.axisTitle = config.title;
203            }
204
205            // Update color
206            const series = subChart.renderableSeries.get(0) as FastLineRenderableSeries;
207            if (series) {
208                series.stroke = config.color;
209            }
210
211            // Update data if phase changed
212            const data = createLineData(config.phase);
213            if (series && series.dataSeries) {
214                (series.dataSeries as XyDataSeries).clear();
215                (series.dataSeries as XyDataSeries).appendRange(data.xValues, data.yValues);
216            }
217        }
218    };
219
220    const updateSubCharts = (configs: SubChartConfig[]) => {
221        // Use the safer recreate approach to avoid MouseManager issues
222        recreateSubChartsWithLayout(configs);
223    };
224
225    const recreateSubChartsWithLayout = (configs: SubChartConfig[]) => {
226        // Suspend updates to prevent MouseManager from iterating over partially deleted subcharts
227        sciChartSurface.suspendUpdates();
228
229        try {
230            // Clear existing subcharts - use the proper removeSubChart function to ensure cleanup
231            const currentIds = Array.from(subChartMap.keys());
232            currentIds.forEach((id) => {
233                removeSubChart(id);
234            });
235
236            // Recreate with proper layout
237            const count = configs.length;
238            if (count === 0) {
239                sciChartSurface.resumeUpdates();
240                return;
241            }
242
243            configs.forEach((config, index) => {
244                // Calculate position: each subchart takes 1/count of the available 80% height
245                // Y position starts at (index/count) * 0.8 and has height of (1/count) * 0.8
246                const yStart = (index / count) * 0.8;
247                const height = (1 / count) * 0.8;
248                const rect = new Rect(0, yStart, 1, height);
249
250                const subChartOptions: I2DSubSurfaceOptions = {
251                    id: config.id,
252                    position: rect,
253                    coordinateMode: ESubSurfacePositionCoordinateMode.Relative,
254                };
255
256                const subChart = SciChartSubSurface.createSubSurface(sciChartSurface, subChartOptions);
257
258                // Create axes for the subchart
259                const subXAxis = new NumericAxis(wasmContext);
260                const subYAxis = new NumericAxis(wasmContext, {
261                    growBy: new NumberRange(0.1, 0.1),
262                    axisTitle: config.title,
263                    axisTitleStyle: { fontSize: 14 },
264                    drawMinorGridLines: false,
265                });
266
267                subChart.xAxes.add(subXAxis);
268                subChart.yAxes.add(subYAxis);
269
270                // Create data and series
271                const data = createLineData(config.phase);
272                const dataSeries = new XyDataSeries(wasmContext, {
273                    xValues: data.xValues,
274                    yValues: data.yValues,
275                });
276
277                const lineSeries = new FastLineRenderableSeries(wasmContext, {
278                    dataSeries,
279                    strokeThickness: 4,
280                    stroke: config.color,
281                    opacity: 0.6,
282                });
283
284                // Add to synchronizer and subchart
285                axisSynchroniser.addAxis(subXAxis);
286                subChart.renderableSeries.add(lineSeries);
287
288                // Add modifiers
289                subChart.chartModifiers.add(
290                    new ZoomPanModifier(),
291                    new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
292                    new ZoomExtentsModifier(),
293                    new RolloverModifier({ modifierGroup: "one" })
294                );
295
296                // Store reference
297                subChartMap.set(config.id, subChart);
298
299                subChart.zoomExtents();
300            });
301        } finally {
302            sciChartSurface.resumeUpdates();
303        }
304    };
305
306    // Initialize with provided configs
307    initialConfigs.forEach((config) => addSubChart(config));
308
309    sciChartSurface.zoomExtents();
310
311    const manager: SubChartManager = {
312        updateSubCharts,
313        addSubChart,
314        removeSubChart,
315        updateLayout,
316    };
317
318    return { wasmContext, sciChartSurface, manager };
319};
320

Overview for SubCharts – Angular

Overview

This example demonstrates how to create a multi-panel chart layout with synchronized subcharts and an overview range selector using SciChart.js within an Angular application. Each subchart displays its own data while remaining fully synchronized through shared zoom and pan interactions.

Technical Implementation

The chart is hosted inside a standalone Angular component using the scichart-angular integration. A custom initialization function dynamically creates multiple SciChartSubSurface instances, each with its own NumericAxis, FastLineRenderableSeries, and interaction modifiers such as ZoomPanModifier and MouseWheelZoomModifier.

An overview panel is added using a custom SubChartsOverviewModifier, which creates an additional subsurface at the bottom of the chart. This overview aggregates series from all subcharts and applies an OverviewRangeSelectionModifier to synchronize the visible range across every chart.

Features and Capabilities

Dynamic Multi-Chart Layout: Subcharts are automatically positioned and resized based on the number of active charts.

Unified Range Selection: The overview panel provides a single control point for zooming and panning all subcharts simultaneously.

Robust Lifecycle Handling: The example carefully manages subchart creation and deletion to avoid interaction issues, ensuring stable behavior during dynamic updates.

Enterprise-Grade Performance: Leveraging SciChart.js WebAssembly rendering ensures smooth interactivity even with multiple charts and dense datasets.

Integration and Best Practices

This example follows recommended patterns for integrating SciChart.js into Angular, including isolating chart initialization logic and using safe update suspension during layout changes. Developers building analytical dashboards or monitoring tools can use this approach as a foundation. See the SciChart Angular Documentation and SubCharts API for further details.

angular Chart Examples & Demos

See Also: Zoom and Pan a Chart (9 Demos)

Angular Chart with Multiple X Axes | SciChart.js Demo

Angular Chart with Multiple X Axes

Demonstrates Multiple X & Y Axis on a Angular Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Angular Chart with Secondary Y Axes | SciChart.js Demo

Angular Chart with Secondary Y Axes

Demonstrates Secondary Y Axis on a Angular Chart using SciChart.js. SciChart supports unlimited, multiple left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Drag Angular Chart Axis to Scale or Pan | SciChart.js

Drag Angular Chart Axis to Scale or Pan

Demonstrates how to Zoom, Scale or Pan individual Axis on a Angular Chart with SciChart.js AxisDragModifiers

Zoom and Pan a Realtime Angular Chart | SciChart.js Demo

Zoom and Pan a Realtime Angular Chart

Demonstrates how to zoom and pan a realtime Angular Chart while it is updating, with SciChart.js ZoomState API

Zoom and Pan with Angular Chart multiple Modifiers | SciChart

Zoom and Pan with Angular Chart multiple Modifiers

Demonstrates how to use multiple Zoom and Pan Modifiers on a Angular Chart with SciChart.js

Zoom and Pan with Overview Chart | Angular Charts | SciChart.js

Zoom and Pan with Overview Chart

Demonstrates how to zoom and pan with an Overview Chart

Virtualized Angular Charts: Load Data on Zoom/Pan | SciChart

Virtualized Angular Charts: Load Data on Zoom/Pan

shows how to load data on zoom/pan and how to create an overview chart for this case.

Angular Polar Modifiers | Polar Interactivity Modifiers

Angular Polar Modifiers | Polar Interactivity Modifiers Demo

Explore SciChart's Polar Interactivity Modifiers including zooming, panning, and cursor tracking. Try the demo to trial the Polar Chart Behavior Modifiers.

NEW!
High Precision Date Axis | Angular Charts | SciChart.js Demo

High Precision Date Axis

Demonstrates 64-bit precision Date Axis in SciChart.js handling Nanoseconds to Billions of Years

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