Creates a Angular Animated Bar Chart using SciChart.js that displays animated ATP Year-end Top Ten rankings from 1990 to 2024..
drawExample.ts
angular.ts
theme.ts
atp-rankings.ts
1import {
2 SciChartSurface,
3 NumericAxis,
4 FastRectangleRenderableSeries,
5 EColumnMode,
6 EColumnYMode,
7 Thickness,
8 EAxisAlignment,
9 ETextAlignment,
10 ETitlePosition,
11 IPointMetadata,
12 easing,
13 EDataLabelSkipMode,
14 EVerticalTextPosition,
15 EHorizontalTextPosition,
16 NumberRange,
17 XyxDataSeries,
18 ColumnAnimation,
19 XyDataSeries,
20 DefaultPaletteProvider,
21 TSciChart,
22 parseColorToUIntArgb,
23} from "scichart";
24
25import { appTheme } from "../../../theme";
26import { data } from "./atp-rankings";
27
28type ATPMetadata = IPointMetadata & {
29 rank: number;
30 name: string;
31 country: string;
32};
33class CountryPaletteProvider extends DefaultPaletteProvider {
34 private colorMap: Map<string, { stroke: number; fill: number }> = new Map<
35 string,
36 { stroke: number; fill: number }
37 >();
38
39 constructor(wasmContext: TSciChart) {
40 super();
41 const countries = [
42 "SE",
43 "CS",
44 "US",
45 "EC",
46 "AT",
47 "HR",
48 "NL",
49 "UA",
50 "RU",
51 "ZA",
52 "AU",
53 "GB",
54 "CL",
55 "SK",
56 "BR",
57 "CH",
58 "CZ",
59 "AR",
60 "RS",
61 "JP",
62 "ES",
63 "YU",
64 "FR",
65 "CA",
66 "BG",
67 "BE",
68 "GR",
69 "IT",
70 "NO",
71 "DE",
72 "PL",
73 "DK",
74 ];
75 const max = countries.length - 1;
76 for (let i = 0; i < countries.length; i++) {
77 const country = countries[i];
78 const stroke = parseColorToUIntArgb(appTheme.SciChartJsTheme.getStrokeColor(i, max, wasmContext));
79 const fill = parseColorToUIntArgb(appTheme.SciChartJsTheme.getFillColor(i, max, wasmContext));
80 this.colorMap.set(country, { stroke, fill });
81 }
82 }
83
84 public overrideStrokeArgb(
85 xValue: number,
86 yValue: number,
87 index: number,
88 opacity?: number,
89 metadata?: IPointMetadata
90 ): number | undefined {
91 const country = (metadata as ATPMetadata).country;
92 return this.colorMap.get(country).stroke;
93 }
94
95 public overrideFillArgb(
96 xValue: number,
97 yValue: number,
98 index: number,
99 opacity?: number,
100 metadata?: IPointMetadata
101 ): number | undefined {
102 const country = (metadata as ATPMetadata).country;
103 return this.colorMap.get(country).fill;
104 }
105}
106
107export const drawExample = async (rootElement: string | HTMLDivElement) => {
108 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
109 theme: appTheme.SciChartJsTheme,
110 });
111
112 // Setup axes
113 sciChartSurface.xAxes.add(
114 new NumericAxis(wasmContext, {
115 visibleRange: new NumberRange(0, 15),
116 isVisible: false,
117 })
118 );
119
120 sciChartSurface.yAxes.add(
121 new NumericAxis(wasmContext, {
122 visibleRange: new NumberRange(0.5, 10.5),
123 axisTitle: "Rank",
124 axisTitleStyle: {
125 fontSize: 18,
126 },
127 axisAlignment: EAxisAlignment.Left,
128 drawMajorBands: false,
129 drawLabels: true,
130 drawMinorGridLines: false,
131 drawMajorGridLines: false,
132 drawMinorTickLines: false,
133 drawMajorTickLines: false,
134 keepLabelsWithinAxis: false,
135 autoTicks: false,
136 flippedCoordinates: true,
137 majorDelta: 1,
138 labelPrecision: 0,
139 labelStyle: {
140 fontSize: 22,
141 fontFamily: "Arial",
142 },
143 })
144 );
145
146 sciChartSurface.yAxes.get(0).axisRenderer.hideOverlappingLabels = false;
147
148 sciChartSurface.title = [`ATP Year-end Top 10 in ${data[0].year.toString()}`];
149
150 const topMargin = 30;
151 const rightMargin = 30;
152 const bottomMargin = 30;
153 const leftMargin = 30;
154
155 sciChartSurface.padding = new Thickness(topMargin, rightMargin, bottomMargin, leftMargin);
156
157 const xValues: number[] = [];
158 const x1Values: number[] = [];
159 const yValues: number[] = [];
160 const metadata: ATPMetadata[] = [];
161
162 for (const element of data[0].top10) {
163 xValues.push(0);
164 yValues.push(element.rank);
165 x1Values.push(16 - element.rank);
166 metadata.push({ isSelected: false, ...element });
167 }
168
169 // setup data
170 const dataSeriesA = new XyxDataSeries(wasmContext, { xValues, yValues, x1Values, metadata });
171 const dataSeriesB = new XyxDataSeries(wasmContext);
172
173 const rectangleSeries = new FastRectangleRenderableSeries(wasmContext, {
174 dataSeries: dataSeriesA,
175 columnXMode: EColumnMode.StartEnd,
176 columnYMode: EColumnYMode.CenterHeight,
177 defaultY1: 1,
178 strokeThickness: 4,
179 opacity: 0.3,
180 paletteProvider: new CountryPaletteProvider(wasmContext),
181 dataLabels: {
182 skipMode: EDataLabelSkipMode.ShowAll,
183 verticalTextPosition: EVerticalTextPosition.Center,
184 horizontalTextPosition: EHorizontalTextPosition.Center,
185 style: {
186 fontFamily: "Arial",
187 fontSize: 16,
188 },
189 color: appTheme.ForegroundColor,
190 metaDataSelector: (md) => {
191 const metadata = md as ATPMetadata;
192 return `${metadata.name.toString()} (${metadata.country.toString()})`;
193 },
194 //updateTextInAnimation: true
195 },
196 });
197 sciChartSurface.renderableSeries.add(rectangleSeries);
198 // Setup animations
199
200 const updateData = (i: number, curDataSeries: XyxDataSeries, nextDataSeries: XyxDataSeries) => {
201 sciChartSurface.title = [`ATP Year-end Top 10 in ${data[i].year.toString()}`];
202 nextDataSeries.clear();
203 const cur: ATPMetadata[] = [];
204 const next = data[i].top10;
205 // Series animations work by animating values at the same index, so it is important to preserve the order of entries, which may be totally unrelated to the display order
206 for (let p = 0; p < curDataSeries.count(); p++) {
207 // Look at all existing entries
208 const e = curDataSeries.getMetadataAt(p) as ATPMetadata;
209 // see if they should still be on the chart in the next period
210 const eNext = next.find((n) => n.name === e.name);
211 if (eNext) {
212 // Add to next data with new value
213 nextDataSeries.append(0, eNext.rank, 16 - eNext.rank, { isSelected: false, ...eNext });
214 } else {
215 if (curDataSeries.getNativeYValues().get(p) > 0) {
216 // If they are currently in view, set them to be out of view in next period
217 nextDataSeries.append(0, 12, 0, e);
218 }
219 }
220 // track all the current entries
221 cur.push(e);
222 }
223 for (const element of next) {
224 // Find entries that are completely new
225 const isNew = cur.find((e) => e.name === element.name) === undefined;
226 if (isNew) {
227 // add out of view in current data, and with new value in next data
228 curDataSeries.append(0, 12, 0, { isSelected: false, ...element });
229 nextDataSeries.append(0, element.rank, 16 - element.rank, { isSelected: false, ...element });
230 }
231 }
232 //Create an animation which will call the update for the following period when it completes
233 const animation = new ColumnAnimation({
234 duration: 1000,
235 ease: easing.inOutQuart,
236 dataSeries: nextDataSeries as any as XyDataSeries,
237 onCompleted: () => {
238 if (i < data.length - 2) {
239 updateData(i + 1, curDataSeries, nextDataSeries);
240 }
241 },
242 });
243 rectangleSeries.runAnimation(animation);
244 };
245
246 sciChartSurface.titleStyle = {
247 color: appTheme.ForegroundColor,
248 fontSize: 30,
249 alignment: ETextAlignment.Center,
250 position: ETitlePosition.Top,
251 placeWithinChart: false,
252 padding: Thickness.fromString("40 0 0 0"),
253 };
254 updateData(1, dataSeriesA, dataSeriesB);
255
256 return { sciChartSurface, wasmContext };
257};
258This Angular standalone component demonstrates an animated tennis rankings visualization using SciChart.js. The implementation uses the scichart-angular package for seamless integration with Angular's component system.
The chart is configured through the drawExample function passed to the ScichartAngularComponent. It creates a SciChartSurface with a FastRectangleRenderableSeries using EColumnYMode.CenterHeight for proper column sizing.
The component animates yearly ranking changes with smooth transitions using ColumnAnimation. A custom palette provider colors columns by player nationality, and data labels display player information. The flipped Y-axis correctly represents ranking positions.
The example follows Angular best practices by using standalone components and proper dependency management. The scichart-angular wrapper handles chart lifecycle management, including WebAssembly context creation and cleanup.

Create an Angular Histogram Chart with custom texture fills and patterns. Try the SciChartAngular wrapper component for seamless Angular integration today.

Build an Angular Gantt Chart with SciChart. View the demo for horizontal bars, rounded corners and data labels to show project timelines and task completion.

Create an Angular Choropleth map, a type of thematic map where areas are shaded or patterned in proportion to the value of a variable being represented.

Create a Angular Multi-Layer Map Example, using FastTriangleRenderableSeries with GeoJSON data-points using a constrained delaunay triangulation algorithm.

View the Angular Vector Field Plot example from SciChart, including dynamic vector generation, gradient-colored segments, and interactive zoom/pan. Try demo.

Build an Angular Waterfall Chart with dynamic coloring, multi-line data labels & responsive design, using ScichartAngular component for seamless integration

Try the Angular Box Plot Chart example for Angular-friendly chart lifecycle management, dynamic sub-surface positioning, and custom styling. Try the demo now.

Create Angular Triangle Meshes with the Triangle Series from SciChart. This demo supports strip mode, list mode and the drawing of polygons. View the example.

Create an Angular Treemap Chart to define rectangle positions based on total value. Use SciChart FastRectangleRenderableSeries and d3-hierarchy.js layouts.

Design a highly dynamic Angular Map Chart with Heatmap overlay with SciChart's feature-rich JavaScript Chart Library. Get your free demo today.

Demonstrating the capability of SciChart.js to create a JavaScript Audio Analyzer Bars and visualize the Fourier-Transform of an audio waveform in realtime.

View the Angular Linear Gauge Chart example to combine rectangles & annotations. Create a linear gauge dashboard with animated indicators and custom scales.

The Angular Order of Rendering example gives you full control of the draw order of series and annotations for charts. Try SciChart's advanced customizations.

Build Responsive Angular HTML Annotations with SciChart. Use the advanced CSS container queries for responsive text layout and custom design. View demo now.

Angular HTML Chart Control example demonstrates advanced HTML annotation integration and how to render HTML components within charts. Try the SciChart demo.

Explore SciChart's Polar Interactivity Modifiers including zooming, panning, and cursor tracking. Try the demo to trial the Polar Chart Behavior Modifiers.