Creates a React Animated Bar Chart using SciChart.js that displays animated ATP Year-end Top Ten rankings from 1990 to 2024.
drawExample.ts
index.tsx
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 React example creates an animated visualization of ATP tennis rankings using SciChart.js. The component leverages the SciChartReact wrapper for seamless integration with React's lifecycle.
The chart is initialized via the initChart prop which creates a SciChartSurface with a FastRectangleRenderableSeries. The implementation uses EColumnMode.StartEnd for precise column positioning and a custom palette provider for country-based coloring.
The component automatically animates between yearly ranking data using ColumnAnimation with easing functions. Data labels show player information, and the chart title updates dynamically. The flipped Y-axis properly displays rankings with #1 at the top.
The example demonstrates React best practices by encapsulating chart logic in the drawExample function. The SciChartReact component handles surface creation and cleanup automatically. For larger datasets, consider implementing virtualized data loading.

Create a React Histogram Chart with custom texture fills and patterns. Try the SciChartReact wrapper component for seamless React integration today.

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

Create a React 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 React Multi-Layer Map Example, using FastTriangleRenderableSeries with GeoJSON data-points using a constrained delaunay triangulation algorithm.

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

Build a React Waterfall Chart with dynamic coloring, multi-line data labels and responsive design, using the SciChartReact component for seamless integration.

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

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

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

Design a highly dynamic React 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 React Linear Gauge Chart example to combine rectangles & annotations. Create a linear gauge dashboard with animated indicators and custom scales.

The React 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 React HTML Annotations with SciChart. Use the advanced CSS container queries for responsive text layout and custom design. View demo now.

React 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.