Realtime Percentage Change using Filter

Demonstrates how to use a ScaleOffsetFilter to convert data to a Percentage Change with realtime updates, using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

RandomWalkGenerator.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import { appTheme } from "../../../theme";
2import { RandomWalkGenerator } from "../../../ExampleData/RandomWalkGenerator";
3import {
4    SciChartSurface,
5    NumericAxis,
6    NumberRange,
7    EAutoRange,
8    XyDataSeries,
9    XyScaleOffsetFilter,
10    FastLineRenderableSeries,
11    HitTestInfo,
12    XySeriesInfo,
13    SeriesInfo,
14    ZoomPanModifier,
15    ZoomExtentsModifier,
16    RolloverModifier,
17    TextAnnotation,
18    EHorizontalAnchorPoint,
19    EVerticalAnchorPoint,
20    ECoordinateMode,
21    EAnnotationLayer,
22    ENumericFormat,
23} from "scichart";
24
25// Custom formatNumber function to avoid conflicts
26const customFormatNumber = (value: number, format: ENumericFormat, precision: number) => {
27    return value.toFixed(precision);
28};
29
30const getScaleValue = (dataSeries: XyDataSeries, zeroXValue: number) => {
31    const dataLength = dataSeries.count();
32    let zeroIndex = -1;
33    for (let i = 0; i < dataLength; i++) {
34        const xValue = dataSeries.getNativeXValues().get(i);
35        if (xValue >= zeroXValue) {
36            zeroIndex = i;
37            break;
38        }
39    }
40    if (zeroIndex === -1) {
41        return 1;
42    }
43    return 100 / dataSeries.getNativeYValues().get(zeroIndex);
44};
45
46class TransformedSeries extends FastLineRenderableSeries {
47    public originalSeries: XyDataSeries;
48
49    public override getSeriesInfo(hitTestInfo: HitTestInfo): SeriesInfo {
50        const info = new XySeriesInfo(this, hitTestInfo);
51        if (this.originalSeries && info.dataSeriesIndex !== undefined) {
52            info.yValue = this.originalSeries.getNativeYValues().get(info.dataSeriesIndex);
53        }
54        return info;
55    }
56}
57
58export const drawExample = async (rootElement: string | HTMLDivElement, usePercentage: boolean) => {
59    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
60        theme: appTheme.SciChartJsTheme,
61    });
62
63    const xAxis = new NumericAxis(wasmContext);
64    sciChartSurface.xAxes.add(xAxis);
65
66    const yAxis = new NumericAxis(wasmContext, {
67        autoRange: EAutoRange.Always,
68        labelPostfix: usePercentage ? "%" : "",
69        labelPrecision: usePercentage ? 0 : 1,
70        growBy: new NumberRange(0.1, 0.1),
71    });
72
73    yAxis.labelProvider.formatCursorLabel = (value: number) => customFormatNumber(value, ENumericFormat.Decimal, 1);
74    sciChartSurface.yAxes.add(yAxis);
75
76    const lineSeries = new TransformedSeries(wasmContext, {
77        strokeThickness: 3,
78        stroke: appTheme.VividSkyBlue,
79    });
80    sciChartSurface.renderableSeries.add(lineSeries);
81
82    const data0 = new RandomWalkGenerator().Seed(1337).getRandomWalkSeries(100);
83    const dataSeries1 = new XyDataSeries(wasmContext, { xValues: data0.xValues, yValues: data0.yValues });
84
85    const transform1 = new XyScaleOffsetFilter(dataSeries1, { offset: -100 });
86
87    xAxis.visibleRangeChanged.subscribe(
88        (args) => (transform1.scale = getScaleValue(dataSeries1, args.visibleRange.min))
89    );
90
91    if (usePercentage) {
92        lineSeries.dataSeries = transform1;
93        lineSeries.originalSeries = dataSeries1;
94    } else {
95        lineSeries.dataSeries = dataSeries1;
96    }
97
98    const lineSeries2 = new TransformedSeries(wasmContext, {
99        strokeThickness: 3,
100        stroke: appTheme.VividOrange,
101    });
102    sciChartSurface.renderableSeries.add(lineSeries2);
103
104    const data1 = new RandomWalkGenerator().Seed(0).getRandomWalkSeries(100);
105    const dataSeries2 = new XyDataSeries(wasmContext, { xValues: data1.xValues, yValues: data1.yValues });
106
107    const transform2 = new XyScaleOffsetFilter(dataSeries2, { offset: -100 });
108    xAxis.visibleRangeChanged.subscribe(
109        (args) => (transform2.scale = getScaleValue(dataSeries2, args.visibleRange.min))
110    );
111
112    if (usePercentage) {
113        lineSeries2.dataSeries = transform2;
114        lineSeries2.originalSeries = dataSeries2;
115    } else {
116        lineSeries2.dataSeries = dataSeries2;
117    }
118
119    sciChartSurface.chartModifiers.add(new ZoomPanModifier({ enableZoom: true }));
120    sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
121    sciChartSurface.chartModifiers.add(new RolloverModifier({ rolloverLineStroke: appTheme.VividTeal }));
122
123    sciChartSurface.annotations.add(
124        new TextAnnotation({
125            text: "Toggle between original data & Percentage Changed on chart",
126            fontSize: 16,
127            textColor: appTheme.ForegroundColor,
128            x1: 0.5,
129            y1: 0,
130            opacity: 0.77,
131            horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
132            xCoordinateMode: ECoordinateMode.Relative,
133            yCoordinateMode: ECoordinateMode.Relative,
134        })
135    );
136
137    const watermarkText = usePercentage ? "Percentage Changed" : "Original Data";
138    sciChartSurface.annotations.add(
139        new TextAnnotation({
140            text: watermarkText,
141            fontSize: 32,
142            textColor: appTheme.ForegroundColor,
143            x1: 0.5,
144            y1: 0.5,
145            opacity: 0.23,
146            horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
147            verticalAnchorPoint: EVerticalAnchorPoint.Center,
148            xCoordinateMode: ECoordinateMode.Relative,
149            yCoordinateMode: ECoordinateMode.Relative,
150            annotationLayer: EAnnotationLayer.BelowChart,
151        })
152    );
153
154    return { sciChartSurface, wasmContext };
155};
156

Percentage Change Example using React

Overview

This example demonstrates how to implement a real-time percentage change chart using SciChart.js in a React application. It showcases toggling between displaying the original data and a percentage change transformation in a high performance chart. The implementation leverages the powerful SciChart React integration for embedding charts into a React component.

Technical Implementation

The core of the example is in the drawExample function, where a SciChartSurface is created. Two data series are generated using a Random Walk algorithm and then transformed using a ScaleOffsetFilter to compute a percentage change over a baseline. The X-axis visible range event (visibleRangeChanged) is used to update the scale factor of the transformation dynamically. Customizations include the extension of the FastLineRenderableSeries by creating a TransformedSeries class to override the getSeriesInfo method for precise tooltip display. For an in-depth understanding of SciChart.js filters, see the filters API.

Features and Capabilities

This example exhibits several advanced features: real-time data updates through reactive event handling, dynamic data transformation using the XyScaleOffsetFilter, and responsive chart annotations. It also demonstrates the use of custom number formatting, efficient re-rendering by forcing chart reinitialization using the React key prop, and a dual visualization mode toggled via a Material UI ToggleButtonGroup. Developers interested in event-driven data transformations can refer to the event-driven updates documentation for further details.

Integration and Best Practices

The integration with React is facilitated by the <SciChartReact/> component, which makes it simple to embed the SciChartSurface into the React component tree. The use of the key property in React ensures proper reinitialization when toggling between percentage change and original data modes, a best practice for managing component state resets as highlighted in common React re-rendering techniques. Moreover, the example integrates Material UI’s ToggleButtonGroup to provide a seamless UI for switching chart modes, demonstrating best practices in combining Material UI with SciChart. For more on optimizing real-time chart performance in React, you might find this React and SciChart performance optimization guide useful.

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