JavaScript Generic Animation

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

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.html

vanilla.ts

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

JavaScript Generic Animation Example

Overview

This example demonstrates how to leverage SciChart.js with JavaScript to create dynamic and interactive 2D charts enhanced with smooth animations. The focus is on using the GenericAnimation class to create effects such as a typewriter reveal for the chart title, seamless annotation fade-ins, and fluid transitions between different bubble series.

Technical Implementation

The implementation begins with asynchronous initialization of the SciChartSurface as described in Getting Started with SciChart JS. The chart is constructed by setting up numeric axes, bubble series with XyzDataSeries and FastBubbleRenderableSeries, and integrating annotations directly into the visualization. Custom animations are created using the GenericAnimation class, which offers granular control over the animation progress. For example, a custom typewriter effect is implemented to reveal the chart title gradually, a technique that aligns with approaches covered in Javascript Beginner Tutorial - Typewriter Effect with Vanilla JS. The example also employs axis animations via the animateVisibleRange method to smoothly adjust axis ranges, as detailed in Axis Ranging - Set Range and Zoom to Fit - SciChart.

Features and Capabilities

Key features include real-time update animations that manage opacity transitions between annotations and bubble series, dynamic changes to axis titles, and coordinated delays that sequence various animations over time. These capabilities allow for visually engaging transitions and offer developers a template for implementing sophisticated interactive charts.

Integration and Best Practices

Built purely with JavaScript, this example avoids reliance on frameworks and demonstrates clean, efficient code management. It emphasizes asynchronous chart initialization, proper resource cleanup using sciChartSurface.delete(), and detailed control over animation timing. Additionally, performance optimization techniques are applied, ensuring responsiveness even during complex animation sequences. Developers can further explore performance strategies in Performance Optimisation of JavaScript Applications & Charts.

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