Demonstrates how to run Generic Animation using SciChart.js, High Performance JavaScript Charts
drawExample.ts
angular.ts
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 SciChart.js into an Angular standalone component using the scichart-angular package. The "Generic Animation" example showcases how to animate various chart elements including the chart title, annotations, and data series. By leveraging asynchronous initialization and the powerful GenericAnimation class, developers can create dynamic, interactive charts that engage users with smooth animation transitions.
The implementation is centered around the asynchronous initialization of the SciChartSurface in an Angular component. The drawExample function sets up the chart by creating axes, bubble series, and annotations, then applies custom animations using the GenericAnimation class. One animation implements a typewriter effect to reveal the chart title, while others gradually fade in annotations and manage transitions between different bubble series. Developers can dive deeper into customizing these animations in the Generic Animations documentation. The asynchronous setup follows best practices outlined in Getting Started with SciChart JS and integrates seamlessly with Angular via the scichart-angular package.
The example features several advanced capabilities including real-time update effects and dynamic annotation management. Notable features include:
Integration into Angular is achieved through a standalone component that encapsulates the SciChart initialization and animation logic. This design approach ensures efficient lifecycle management and optimal performance. The timing and sequencing of animations are managed using precise delays and duration settings within the GenericAnimation instances, exemplifying best practices for handling dynamic animations in Angular. Further insights into similar animation techniques can be found in the Angular Startup Animation demo, while performance considerations are well documented in Performance Optimisation of JavaScript Applications & Charts.

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 Angular Animated Bar Chart example from SciChart. This demo showcases top 10 tennis players from 1990 to 2024.