React Generic Animation

Demonstrates how to run Generic Animation using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

ExampleDataProvider.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    SciChartSurface,
3    NumericAxis,
4    NumberRange,
5    FastBubbleRenderableSeries,
6    XyzDataSeries,
7    EllipsePointMarker,
8    NativeTextAnnotation,
9    EVerticalAnchorPoint,
10    LineAnnotation,
11    GenericAnimation,
12} from "scichart";
13import { appTheme } from "../../../theme";
14import { fetchPopulationDataData } from "../../../ExampleData/ExampleDataProvider";
15
16const initializeChart = async (rootElement: string | HTMLDivElement) => {
17    // Create a SciChartSurface with bubble chart
18    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
19        theme: appTheme.SciChartJsTheme,
20    });
21
22    sciChartSurface.title = "In SciChart.js you can animate anything";
23    sciChartSurface.titleStyle = {
24        placeWithinChart: true,
25        fontSize: 24,
26        color: appTheme.ForegroundColor + "C4",
27    };
28
29    sciChartSurface.xAxes.add(
30        new NumericAxis(wasmContext, {
31            axisTitle: "Year",
32            labelPrecision: 0,
33        })
34    );
35    sciChartSurface.yAxes.add(
36        new NumericAxis(wasmContext, {
37            axisTitle: "Life Expectancy (years)",
38            labelPrecision: 0,
39            growBy: new NumberRange(0, 0.2),
40        })
41    );
42
43    return { sciChartSurface, wasmContext };
44};
45
46export const drawExample = async (rootElement: string | HTMLDivElement) => {
47    const [chart, data] = await Promise.all([initializeChart(rootElement), fetchPopulationDataData()]);
48
49    const { sciChartSurface, wasmContext } = chart;
50
51    // TODO link to data source file
52    const { year, lifeExpectancy, gdpPerCapita, population } = data;
53
54    const bubbleSeries0 = new FastBubbleRenderableSeries(wasmContext, {
55        dataSeries: new XyzDataSeries(wasmContext, { xValues: year, yValues: lifeExpectancy, zValues: gdpPerCapita }),
56        opacity: 0.3,
57        // Set the default pointmarker size
58        pointMarker: new EllipsePointMarker(wasmContext, {
59            fill: appTheme.VividSkyBlue,
60            opacity: 0.3,
61            width: 64,
62            height: 64,
63            strokeThickness: 0,
64        }),
65        // z sizes are pixels so normalize these until the largest value in gdpPerCapita = 100px
66        zMultiplier: 100 / Math.max(...gdpPerCapita),
67    });
68    sciChartSurface.renderableSeries.add(bubbleSeries0);
69
70    // add a label & line
71    const labelAnnotation1 = new NativeTextAnnotation({
72        x1: 1955,
73        y1: 82,
74        text: "In this dataset life expectancy increases with time (years).\n Bubble size is GDP/capita",
75        fontSize: 18,
76        opacity: 0, // initially hidden
77        textColor: appTheme.PaleSkyBlue,
78        verticalAnchorPoint: EVerticalAnchorPoint.Bottom,
79    });
80    sciChartSurface.annotations.add(labelAnnotation1);
81    const lineAnnotation = new LineAnnotation({
82        x1: 1960,
83        y1: 81.5,
84        x2: 1966,
85        y2: 76,
86        opacity: 0, // initially hidden
87        stroke: appTheme.PaleSkyBlue,
88        strokeThickness: 2,
89    });
90    sciChartSurface.annotations.add(lineAnnotation);
91
92    // Add some animations using genericAnimation
93    //
94
95    // From 0..2 seconds typewrite the title
96    sciChartSurface.addAnimation(addTypewriterEffect(2000, 0, sciChartSurface));
97
98    // From 2..4 seconds animate the label on the data
99    sciChartSurface.addAnimation(
100        new GenericAnimation({
101            from: 0,
102            to: 1,
103            onAnimate: (from: number, to: number, progress: number) => {
104                labelAnnotation1.opacity = to * progress;
105                lineAnnotation.opacity = to * progress;
106            },
107            duration: 2000,
108            delay: 2000,
109        })
110    );
111
112    // From 5..8s change the data and relabel
113    //
114    const bubbleSeries1 = new FastBubbleRenderableSeries(wasmContext, {
115        dataSeries: new XyzDataSeries(wasmContext, {
116            xValues: gdpPerCapita,
117            yValues: lifeExpectancy,
118            zValues: population,
119        }),
120        opacity: 0.3,
121        // Set the default pointmarker size
122        pointMarker: new EllipsePointMarker(wasmContext, {
123            fill: appTheme.VividSkyBlue,
124            opacity: 0.3,
125            width: 64,
126            height: 64,
127            strokeThickness: 0,
128        }),
129        // z sizes are pixels so normalize these until the largest value in population = 100px
130        zMultiplier: 100 / Math.max(...population),
131        // initially hidden
132        isVisible: false,
133    });
134    sciChartSurface.renderableSeries.add(bubbleSeries1);
135
136    // Animate the new data
137    sciChartSurface.addAnimation(
138        new GenericAnimation({
139            from: 0,
140            to: 0.3,
141            onAnimate: (from: number, to: number, progress: number) => {
142                bubbleSeries1.isVisible = true;
143                bubbleSeries1.pointMarker.opacity = to * progress;
144                bubbleSeries0.pointMarker.opacity = 0.3 * (1 - progress);
145                labelAnnotation1.opacity = 1 - progress;
146                lineAnnotation.opacity = 1 - progress;
147            },
148            onCompleted: () => {
149                bubbleSeries0.isVisible = false;
150                // When the data has changed, now zoom to fit new data
151                sciChartSurface.xAxes.get(0).animateVisibleRange(new NumberRange(0, 50000), 1000);
152                sciChartSurface.xAxes.get(0).axisTitle = "GDP per capita";
153            },
154            duration: 3000,
155            delay: 5000,
156        })
157    );
158
159    // add a second label & line from 7..9s
160    const labelAnnotation2 = new NativeTextAnnotation({
161        x1: 10000,
162        y1: 50,
163        text: "Let's swap the axis to GDP vs. Life Expectancy using GenericAnimation.\n Bubble size is Population",
164        fontSize: 18,
165        opacity: 0, // initially hidden
166        textColor: appTheme.PaleSkyBlue,
167        verticalAnchorPoint: EVerticalAnchorPoint.Top,
168    });
169    sciChartSurface.annotations.add(labelAnnotation2);
170    const lineAnnotation2 = new LineAnnotation({
171        x1: 10000,
172        y1: 60,
173        x2: 20000,
174        y2: 50,
175        opacity: 0, // initially hidden
176        stroke: appTheme.PaleSkyBlue,
177        strokeThickness: 2,
178    });
179    sciChartSurface.annotations.add(lineAnnotation2);
180
181    // Animate the 2nd label and line
182    sciChartSurface.addAnimation(
183        new GenericAnimation({
184            from: 0,
185            to: 1,
186            onAnimate: (from: number, to: number, progress: number) => {
187                labelAnnotation2.opacity = to * progress;
188                lineAnnotation2.opacity = to * progress;
189            },
190            duration: 2000,
191            delay: 7000,
192        })
193    );
194
195    return { sciChartSurface };
196};
197
198const addTypewriterEffect = (duration: number, delay: number, sciChartSurface: SciChartSurface) => {
199    return new GenericAnimation<string>({
200        from: "",
201        to: sciChartSurface.title as string,
202        onAnimate: (from: string, to: string, progress: number) => {
203            const length = Math.floor(to.length * progress);
204            sciChartSurface.title = to.substring(0, length);
205        },
206        duration,
207        delay,
208        setInitialValueImmediately: true,
209    });
210};
211

React Generic Animation Example

Overview

This example demonstrates how to integrate advanced chart animations into a React application using <SciChartReact/>. The "Generic Animation" example showcases smooth and dynamic animations including a typewriter effect for the chart title, animated annotations, and data series transitions, all rendered using SciChart.js.

Technical Implementation

The implementation initializes the chart asynchronously through the <SciChartReact/> component's initChart prop. Multiple animations are defined using the GenericAnimation class, delivering staged transitions such as fading in annotations and performing a typewriter effect on the title. This setup is aligned with best practices for React integration and asynchronous initialization as explained in Creating a SciChart React Component from the Ground Up.

Features and Capabilities

Key features include real-time updates and advanced animation sequencing. For instance, the example employs a custom typewriter effect to sequentially reveal the chart title, and coordinated animations to transition between bubble series and annotations. Developers can further explore the GenericAnimation documentation for deeper customization of these effects.

Integration and Best Practices

The React integration is achieved by using the <SciChartReact/> component to encapsulate the chart rendering logic within a React component, ensuring efficient lifecycle management and performance optimization. Animation sequencing with built-in delays demonstrates how to manage complex state transitions while keeping the user interface responsive. Additional performance tuning insights can be found in Performance Optimisation of JavaScript Applications & Charts, and for further enhancements such as the typewriter effect, resources like Creating a typewriter effect in React provide practical guidance.

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