Demonstrates loading 500 series, each with 500 points (250k points total) instantly. Click the Reload button at the bottom of the demo to see the chart draw again.
drawExample.ts
index.html
vanilla.ts
theme.ts
1import {
2 SciChartSurface,
3 NumericAxis,
4 NumberRange,
5 EAutoRange,
6 TextAnnotation,
7 EHorizontalAnchorPoint,
8 EVerticalAnchorPoint,
9 ECoordinateMode,
10 EAnnotationLayer,
11 XyDataSeries,
12 FastLineRenderableSeries,
13 ZoomExtentsModifier,
14 ZoomPanModifier,
15 MouseWheelZoomModifier,
16 EAxisAlignment,
17} from "scichart";
18import { appTheme } from "../../../theme";
19
20export type TTimeSpan = {
21 title: string;
22 durationMs: number;
23};
24
25const SERIES = 500;
26const POINTS = 500;
27
28export const drawExample = async (
29 rootElement: string | HTMLDivElement,
30 updateTimeSpans: (newTimeSpans: TTimeSpan[]) => void,
31 useVerticalChart = false
32) => {
33 // Create the SciChartSurface
34 const { wasmContext, sciChartSurface } = await SciChartSurface.create(rootElement, {
35 theme: appTheme.SciChartJsTheme,
36 });
37
38 // Create an X,Y Axis
39 sciChartSurface.xAxes.add(
40 new NumericAxis(wasmContext, {
41 isVisible: false,
42 axisAlignment: useVerticalChart ? EAxisAlignment.Left : EAxisAlignment.Bottom,
43 flippedCoordinates: useVerticalChart,
44 visibleRange: new NumberRange(0, POINTS),
45 autoRange: EAutoRange.Never,
46 axisTitle: "X Axis",
47 })
48 );
49 sciChartSurface.yAxes.add(
50 new NumericAxis(wasmContext, {
51 isVisible: false,
52 axisAlignment: useVerticalChart ? EAxisAlignment.Bottom : EAxisAlignment.Left,
53 visibleRange: new NumberRange(-250, 250),
54 autoRange: EAutoRange.Never,
55 axisTitle: "Y Axis",
56 })
57 );
58
59 if (!useVerticalChart) {
60 const watermarkAnnotation = (text: string, offset: number = 0) => {
61 return new TextAnnotation({
62 text,
63 fontSize: 42,
64 fontWeight: "Bold",
65 textColor: appTheme.ForegroundColor,
66 x1: 0.5,
67 y1: 0.5,
68 yCoordShift: offset,
69 opacity: 0.43,
70 horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
71 verticalAnchorPoint: EVerticalAnchorPoint.Center,
72 xCoordinateMode: ECoordinateMode.Relative,
73 yCoordinateMode: ECoordinateMode.Relative,
74 annotationLayer: EAnnotationLayer.AboveChart,
75 });
76 };
77 // add a title annotation
78 sciChartSurface.annotations.add(watermarkAnnotation("SciChart.js Performance Demo", -52));
79 sciChartSurface.annotations.add(watermarkAnnotation(`${SERIES} Series x ${POINTS} Points per series`, 0));
80 sciChartSurface.annotations.add(watermarkAnnotation(`(${(SERIES * POINTS) / 1000}k DataPoints)`, 52));
81 }
82
83 // // add a title annotation
84 // // Add title annotation
85 // sciChartSurface.annotations.add(new TextAnnotation({
86 // text: "SciChart.js Performance Demo: Draw 500 Series x 500 Points (250k Points total)",
87 // fontSize: 16,
88 // textColor: appTheme.ForegroundColor,
89 // x1: 1,
90 // y1: 0,
91 // xCoordShift: -20,
92 // opacity: 0.77,
93 // horizontalAnchorPoint: EHorizontalAnchorPoint.Right,
94 // xCoordinateMode: ECoordinateMode.Relative,
95 // yCoordinateMode: ECoordinateMode.Relative,
96 // }));
97
98 // We pre-create N empty FastLineRenderableSeries for the performance test. Going to fill these with data below
99 const dataSeriesArray: XyDataSeries[] = new Array<XyDataSeries>(SERIES);
100 const rendSeriesArray: FastLineRenderableSeries[] = new Array<FastLineRenderableSeries>(SERIES);
101 for (let i = 0; i < SERIES; i++) {
102 const dataSeries: XyDataSeries = new XyDataSeries(wasmContext);
103 const rendSeries: FastLineRenderableSeries = new FastLineRenderableSeries(wasmContext, {
104 dataSeries,
105 strokeThickness: 2,
106 stroke: "auto",
107 });
108
109 dataSeriesArray[i] = dataSeries;
110 rendSeriesArray[i] = rendSeries;
111
112 sciChartSurface.renderableSeries.add(rendSeries);
113 }
114
115 // Add some interactivity modifiers
116 sciChartSurface.chartModifiers.add(
117 new ZoomExtentsModifier(),
118 new ZoomPanModifier({ enableZoom: true }),
119 new MouseWheelZoomModifier()
120 );
121
122 // Buttons for chart
123 const loadPoints = () => {
124 const newTimeSpans: TTimeSpan[] = [];
125
126 // Start counting Points generation time
127 const generateTimestamp = Date.now();
128
129 const xValuesArray: number[][] = new Array<number[]>(SERIES);
130 const yValuesArray: number[][] = new Array<number[]>(SERIES);
131 for (let i = 0; i < SERIES; i++) {
132 // Allocate data arrays
133 xValuesArray[i] = new Array<number>(POINTS);
134 yValuesArray[i] = new Array<number>(POINTS);
135
136 // Clear data, if any
137 dataSeriesArray[i].clear();
138
139 // Generate points
140 let prevYValue = 0;
141 for (let j = 0; j < POINTS; j++) {
142 const curYValue = Math.random() * 10 - 5;
143
144 xValuesArray[i][j] = j;
145 yValuesArray[i][j] = prevYValue + curYValue;
146
147 prevYValue += curYValue;
148 }
149 }
150
151 // Add the first time span: Generating 500 series x 500 points
152 newTimeSpans.push({
153 title: "Generate Data Points",
154 durationMs: Date.now() - generateTimestamp,
155 });
156
157 // Start counting batch append time
158 const appendTimestamp = Date.now();
159 for (let i = 0; i < SERIES; i++) {
160 dataSeriesArray[i].appendRange(xValuesArray[i], yValuesArray[i]);
161 }
162
163 // Add the second time span: Generation of data point
164 newTimeSpans.push({
165 title: "Append Data Points",
166 durationMs: Date.now() - appendTimestamp,
167 });
168
169 // Subscribe to sciChartSurface.rendered event,
170 // and calculate time duration between the append and
171 // the first frame after it
172 const firstFrameTimestamp = Date.now();
173 let frameIndex: number = 0;
174 let nextFramesTimestamp: number;
175 const handler = () => {
176 if (frameIndex === 0) {
177 // Add the third time span: Render the first frame
178 newTimeSpans.push({
179 title: "Render the frame",
180 durationMs: Date.now() - firstFrameTimestamp,
181 });
182 nextFramesTimestamp = Date.now();
183 } else {
184 // Unsubscribe from sciChartSurface.rendered
185 updateTimeSpans(newTimeSpans);
186 sciChartSurface.rendered.unsubscribe(handler);
187
188 // Zoom extents at the end of performance measurement
189 // sciChartSurface.zoomExtents();
190 }
191 setTimeout(sciChartSurface.invalidateElement, 0);
192 // Increment frame index
193 frameIndex++;
194 };
195 sciChartSurface.rendered.subscribe(handler);
196 };
197
198 let timerId: NodeJS.Timeout;
199 const startUpdate = () => {
200 timerId = setInterval(loadPoints, 200);
201 };
202
203 const stopUpdate = () => {
204 clearInterval(timerId);
205 };
206
207 const reloadOnce = () => {
208 loadPoints();
209 };
210
211 return { wasmContext, sciChartSurface, controls: { startUpdate, stopUpdate, reloadOnce } };
212};
213This example demonstrates how to render a performance‐focused chart using SciChart.js and JavaScript. The example pre-creates 500 line series with 500 data points each and then updates them periodically, providing real-time performance measurements. The chart displays custom watermark annotations and leverages WebGL rendering for optimal performance.
The chart is initialized using the SciChartSurface.create() method with a WebAssembly context (wasmContext), which is detailed in the Creating a new SciChartSurface and loading Wasm documentation. NumericAxis are configured with fixed visible ranges and autoRange set to EAutoRange.Never, ensuring that the chart always displays the full extent of the 500 data points. For more information on axis configuration, refer to the Axis Ranging - Set Range and Zoom to Fit documentation.
Pre-creation of rendering series is done by creating arrays of XyDataSeries and FastLineRenderableSeries. Data is generated in batches and appended via XyDataSeries.appendRange() – a recommended approach for optimizing the update of large-scale data sets. More details on data series management can be found in the Append, Insert, Update, Remove documentation.
The example uses setInterval to periodically update the data series and measure performance timing for data generation, appending, and rendering the first frame. Additionally, performance optimizations such as the usage of FastLineRenderableSeries for optimal WebGL rendering are explained in the FastLineRenderableSeries API Documentation and Performance Tips & Tricks guides.
Real-time updates: The chart periodically reloads data every 200 milliseconds to simulate a continuously updating data stream, while performance results such as data generation duration, appending time, and rendering performance are measured and displayed.
Custom annotations: Watermark text annotations are layered on top of the chart using relative coordinates. These annotations include dynamic text such as the series count and total data points. For further details on annotations, refer to the TextAnnotation Documentation.
Interactivity: The integration of chart modifiers like ZoomExtentsModifier, ZoomPanModifier, and MouseWheelZoomModifier enables users to interact with the chart. Detailed guidance on these features is available in the Tutorial 03 - Adding Zooming, Panning Behavior resource.
This implementation is built entirely in JavaScript without reliance on framework-specific APIs. Best practices for performance optimization are observed by pre-allocating data series, batching data appends, and using WebGL for rendering large datasets. Developers looking for additional performance comparisons of JavaScript Charts may review the Fastest JS Chart blog post.
Overall, this example serves as a robust template for implementing high-performance, real-time updating charts using SciChart.js with JavaScript, and it showcases several advanced features and optimizations that developers can leverage for building sophisticated data visualization applications.

This demo showcases the incredible realtime performance of our JavaScript charts by updating the series with millions of data-points!

This demo showcases the incredible performance of our JavaScript Chart by loading a million points instantly.

This demo showcases the realtime performance of our JavaScript Chart by animating several series with thousands of data-points at 60 FPS

See the frequency of recordings with the JavaScript audio spectrum analyzer example from SciChart. This real-time visualizer demo uses a Fourier Transform.

Demonstrates how to create Oil and Gas Dashboard

This demo showcases the incredible realtime performance of our JavaScript charts by updating the series with millions of data-points!

This dashboard demo showcases the incredible realtime performance of our JavaScript charts by updating the series with millions of data-points!

This demo showcases the incredible realtime performance of our JavaScript charts by updating the series with millions of data-points!

Demonstrates a custom modifier which can convert from single chart to grid layout and back.

Demonstrates how to repurpose a Candlestick Series into dragabble, labled, event markers

Population Pyramid of Europe and Africa

Demonstrates how to use the SVG render layer in SciChart.js to maintain smooth cursor interaction on heavy charts with millions of points.