Demonstrates how to run Generic Animation using SciChart.js, High Performance JavaScript Charts
drawExample.ts
index.tsx
ExampleDataProvider.ts
theme.ts
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};
211This 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.
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.
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.
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.

Demonstrates how to run Dataset Animations with JavaScript.

Demonstrates how to run Style Transition Animations with JavaScript.

Demonstrates how to run Startup Animations with JavaScript.

Bring annual comparison data to life with the React Animated Bar Chart example from SciChart. This demo showcases top 10 tennis players from 1990 to 2024.