Creates a Angular Polar Line Chart using SciChart.js, with the following features: DataLabels, Rounded corners, Gradient-palette fill, startup animations.
drawExample.ts
index.tsx
ChartGroupLoader.tsx
theme.ts
1import {
2 EAxisAlignment,
3 EllipsePointMarker,
4 EPolarAxisMode,
5 NumberRange,
6 PolarNumericAxis,
7 SciChartPolarSurface,
8 Thickness,
9 XyDataSeries,
10 PolarPanModifier,
11 PolarMouseWheelZoomModifier,
12 RadianLabelProvider,
13 PolarLineRenderableSeries,
14 PolarZoomExtentsModifier,
15 SweepAnimation,
16 DefaultPaletteProvider,
17 EStrokePaletteMode,
18 parseColorToUIntArgb,
19 EPolarGridlineMode,
20 BezierRenderDataTransform,
21 SplineLineRenderableSeries,
22 SplineRenderDataTransform,
23 EHorizontalTextPosition,
24 EVerticalTextPosition,
25 EDataLabelSkipMode,
26 PolarCursorModifier
27} from "scichart";
28import { appTheme } from "../../../theme";
29
30const COMMON_POLAR_SURFACE_OPTIONS = {
31 theme: appTheme.SciChartJsTheme,
32 padding: new Thickness(0, 0, 0, 0),
33 titleStyle: {
34 fontSize: 18,
35 },
36}
37
38const COMMON_ANGULAR_AXIS_OPTIONS = {
39 polarAxisMode: EPolarAxisMode.Angular,
40 axisAlignment: EAxisAlignment.Top,
41
42 drawMinorGridLines: false,
43 drawMinorTickLines: false,
44 drawMajorTickLines: false,
45
46 labelPrecision: 0,
47 useNativeText: true,
48}
49
50const COMMON_RADIAL_AXIS_OPTIONS = {
51 polarAxisMode: EPolarAxisMode.Radial,
52 axisAlignment: EAxisAlignment.Left,
53
54 drawMinorGridLines: false,
55 drawMinorTickLines: false,
56 drawMajorTickLines: false,
57
58 labelPrecision: 0,
59 useNativeText: true,
60
61 // zoomExtentsToInitialRange: true,
62};
63
64export const getChartsInitializationAPI = () => {
65 const line1 = async (rootElement: string | HTMLDivElement) => {
66 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
67 ...COMMON_POLAR_SURFACE_OPTIONS,
68 title: "Simple Polar Lines",
69 });
70
71 // Add the yAxis
72 const radialYAxis = new PolarNumericAxis(wasmContext, {
73 ...COMMON_RADIAL_AXIS_OPTIONS,
74
75 autoTicks: false,
76 majorDelta: 2,
77
78 startAngle: Math.PI / 2, // place labels at 12 o'clock
79 });
80 sciChartSurface.yAxes.add(radialYAxis);
81
82 // Add the xAxis
83 const angularXAxis = new PolarNumericAxis(wasmContext, {
84 ...COMMON_ANGULAR_AXIS_OPTIONS,
85
86 autoTicks: false,
87 majorDelta: 30,
88
89 visibleRange: new NumberRange(0, 360),
90 labelPostfix: "°",
91
92 startAngle: Math.PI / 2, // Start drawing at 12 o'clock
93 flippedCoordinates: true, // go clockwise
94
95 zoomExtentsToInitialRange: true, // make sure the visibleRange stays fixed, in `zoomExtents` event case
96 });
97 sciChartSurface.xAxes.add(angularXAxis);
98
99 // Add SERIES
100 const xValues = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300];
101 const polarLine1 = new PolarLineRenderableSeries(wasmContext, {
102 dataSeries: new XyDataSeries(wasmContext, {
103 xValues,
104 yValues: [0, 1, 2, 3, 4, 5, 6, 4, 5, 3, 3]
105 }),
106 stroke: appTheme.VividOrange,
107 strokeThickness: 4,
108 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
109 });
110
111 const polarLine2 = new PolarLineRenderableSeries(wasmContext, {
112 dataSeries: new XyDataSeries(wasmContext, {
113 xValues,
114 yValues: [2, 3, 4, 3, 2, 3, 4, 5, 6, 5, 4]
115 }),
116 stroke: appTheme.VividTeal + "88",
117 strokeThickness: 4,
118 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
119 });
120
121 sciChartSurface.renderableSeries.add(
122 polarLine1, polarLine2
123 );
124
125 sciChartSurface.chartModifiers.add(
126 new PolarPanModifier(),
127 new PolarZoomExtentsModifier(),
128 new PolarMouseWheelZoomModifier()
129 );
130
131 return { sciChartSurface, wasmContext };
132 };
133
134 const line2 = async (rootElement: string | HTMLDivElement) => {
135 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
136 ...COMMON_POLAR_SURFACE_OPTIONS,
137 title: "Line Function Traces",
138 });
139
140 // Add the yAxis
141 const radialYAxis = new PolarNumericAxis(wasmContext, {
142 ...COMMON_RADIAL_AXIS_OPTIONS,
143 drawLabels: false
144 });
145 sciChartSurface.yAxes.add(radialYAxis);
146
147 // Add the xAxis
148 const angularXAxis = new PolarNumericAxis(wasmContext, {
149 ...COMMON_ANGULAR_AXIS_OPTIONS,
150
151 visibleRange: new NumberRange(0, Math.PI * 2), // Full trigonometric circle
152
153 labelProvider: new RadianLabelProvider({
154 maxDenominator: 6
155 }),
156 autoTicks: false,
157 majorDelta: Math.PI / 6, // needed by RadianLabelProvider to show PI fractions
158 });
159 sciChartSurface.xAxes.add(angularXAxis);
160
161 function generatePolarTraces(numPoints: number = 300) {
162 const theta: number[] = Array.from({ length: numPoints }, (_, i) => (i / (numPoints - 1)) * (2 * Math.PI));
163
164 // Normalize function
165 function normalizeY(data: number[]) {
166 const minY = Math.min(...data);
167 const maxY = Math.max(...data);
168 return data.map(d => (d - minY) / (maxY - minY));
169 }
170
171 // Butterfly Curve
172 const butterfly = normalizeY(theta.map(t => Math.exp(Math.cos(t)) - 2 * Math.cos(4 * t) + Math.pow(Math.sin(t / 12), 5)));
173
174 // Rose Curve
175 const roseCurve = normalizeY(theta.map(t => Math.cos(12 * t)));
176
177 // Deltoid Curve
178 const deltoid = normalizeY(theta.map(t => 2 * (1 - Math.cos(2 * t))));
179
180 // Archimedean Spiral
181 const archimedeanSprial = normalizeY(theta.map(t => t / (2 * Math.PI)));
182
183 return {
184 xValues: theta,
185 data: [
186 {
187 name: "Rose",
188 yValues: roseCurve,
189 color: appTheme.VividTeal + "66"
190 },
191 {
192 name: "Butterfly",
193 yValues: butterfly,
194 color: appTheme.VividOrange,
195 },
196 // {
197 // name: "Deltoid",
198 // yValues: deltoid,
199 // color: appTheme.VividPink,
200 // },
201 // {
202 // name: "Archimedean Spiral",
203 // yValues: archimedeanSprial,
204 // color: appTheme.VividBlue,
205 // },
206 ]
207 };
208 }
209
210 // Add SERIES
211 const TRACES = generatePolarTraces();
212 TRACES.data.forEach((dataset, i) => {
213 const polarLine = new PolarLineRenderableSeries(wasmContext, {
214 dataSeries: new XyDataSeries(wasmContext, {
215 xValues: TRACES.xValues,
216 yValues: dataset.yValues,
217 dataSeriesName: dataset.name,
218 }),
219 stroke: dataset.color,
220 strokeThickness: 4,
221 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
222 });
223 sciChartSurface.renderableSeries.add(polarLine);
224 })
225
226 sciChartSurface.chartModifiers.add(
227 new PolarPanModifier(),
228 new PolarZoomExtentsModifier(),
229 new PolarMouseWheelZoomModifier()
230 );
231
232 return { sciChartSurface, wasmContext };
233 };
234
235 const line3 = async (rootElement: string | HTMLDivElement) => {
236 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
237 ...COMMON_POLAR_SURFACE_OPTIONS,
238 title: "Spiral Line",
239 });
240
241 const NR_POINTS = 31;
242 const OFFSET = 20
243
244 // Add the yAxis
245 const radialYAxis = new PolarNumericAxis(wasmContext, {
246 ...COMMON_RADIAL_AXIS_OPTIONS,
247
248 visibleRange: new NumberRange(0, NR_POINTS + OFFSET),
249 zoomExtentsToInitialRange: true,
250 drawLabels: false
251 });
252 sciChartSurface.yAxes.add(radialYAxis);
253
254 // Add the xAxis
255 const angularXAxis = new PolarNumericAxis(wasmContext, {
256 ...COMMON_ANGULAR_AXIS_OPTIONS,
257 zoomExtentsToInitialRange: true
258 });
259 sciChartSurface.xAxes.add(angularXAxis);
260
261 // Add SERIES
262 const xValues = Array.from({ length: NR_POINTS }, (_, i) => i % 10); // [0, 1, .., 9, 0, .., 9]
263
264 const polarLine = new PolarLineRenderableSeries(wasmContext, {
265 dataSeries: new XyDataSeries(wasmContext, {
266 xValues: xValues,
267 yValues: Array.from({ length: NR_POINTS }, (_, i) => i + OFFSET),
268 }),
269 stroke: appTheme.VividTeal + "88",
270 strokeThickness: 4,
271 pointMarker: new EllipsePointMarker(wasmContext, {
272 width: 7,
273 height: 7,
274 stroke: appTheme.VividTeal,
275 fill: appTheme.DarkIndigo,
276 }),
277 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
278 });
279 sciChartSurface.renderableSeries.add(polarLine);
280
281 sciChartSurface.chartModifiers.add(
282 new PolarPanModifier(),
283 new PolarZoomExtentsModifier(),
284 new PolarMouseWheelZoomModifier()
285 );
286
287 sciChartSurface.zoomExtents();
288
289 return { sciChartSurface, wasmContext };
290 };
291
292 const line4 = async (rootElement: string | HTMLDivElement) => {
293 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
294 ...COMMON_POLAR_SURFACE_OPTIONS,
295 title: "Palette Provider Polar Lines",
296 });
297
298 const TOTAL_DEGREES = 45;
299 const POINTS_PER_DEGREE = 2;
300
301 // Add the yAxis
302 const radialYAxis = new PolarNumericAxis(wasmContext, {
303 ...COMMON_RADIAL_AXIS_OPTIONS,
304 visibleRange: new NumberRange(0, 6),
305
306 zoomExtentsToInitialRange: true,
307 autoTicks: false,
308 majorDelta: 1,
309 innerRadius: 0.1,
310 });
311 sciChartSurface.yAxes.add(radialYAxis);
312
313 // Add the xAxis
314 const angularXAxis = new PolarNumericAxis(wasmContext, {
315 ...COMMON_ANGULAR_AXIS_OPTIONS,
316
317 autoTicks: false,
318 majorDelta: 5,
319
320 visibleRange: new NumberRange(0, TOTAL_DEGREES),
321 labelPostfix: "°",
322
323 flippedCoordinates: true, // go clockwise
324 startAngle: 0, // Start drawing at 12 o'clock, since flippedCoordinates == true
325 totalAngle: Math.PI / 2, // Quarter circle
326
327 zoomExtentsToInitialRange: true, // make sure the visibleRange stays fixed, in `zoomExtents` event case
328 });
329 sciChartSurface.xAxes.add(angularXAxis);
330
331 // Custom PaletteProvider for line series which colours datapoints under and above a threshold
332 class ThresholdLinePaletteProvider extends DefaultPaletteProvider {
333 private readonly stroke: number;
334 private readonly rule: (yValue: number) => boolean;
335
336 constructor(stroke: string, rule: (yValue: number) => boolean) {
337 super();
338 this.strokePaletteMode = EStrokePaletteMode.GRADIENT;
339 this.rule = rule;
340 this.stroke = parseColorToUIntArgb(stroke);
341 }
342
343 // This function is called for every data-point.
344 // Return undefined to use the default color for the line,
345 // else, return a custom colour as an ARGB color code, e.g. 0xFFFF0000 is red
346 overrideStrokeArgb(xValue: number, yValue: number, index: number, opacity: number, metadata: any) {
347 return this.rule(yValue) ? this.stroke : undefined;
348 }
349 }
350
351 // Add SERIES
352 const xValues = Array.from({ length: TOTAL_DEGREES * POINTS_PER_DEGREE }, (_, i) => i / POINTS_PER_DEGREE);
353
354 const polarLine1 = new PolarLineRenderableSeries(wasmContext, {
355 dataSeries: new XyDataSeries(wasmContext, {
356 xValues,
357 yValues: Array.from({ length: TOTAL_DEGREES * POINTS_PER_DEGREE }, (_, i) => {
358 return Math.sin(i * Math.PI / 12) + 4.5
359 }),
360 }),
361 stroke: appTheme.VividOrange,
362 strokeThickness: 4,
363 paletteProvider: new ThresholdLinePaletteProvider("white", (yValue) => (yValue > 4 && yValue < 5)),
364 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
365 });
366
367 const polarLine2 = new PolarLineRenderableSeries(wasmContext, {
368 dataSeries: new XyDataSeries(wasmContext, {
369 xValues,
370 yValues: Array.from({ length: TOTAL_DEGREES * POINTS_PER_DEGREE }, (_, i) => {
371 return Math.sin(i * Math.PI / 12) + 2.5
372 }),
373 }),
374 stroke: appTheme.VividTeal + "88",
375 strokeThickness: 4,
376 paletteProvider: new ThresholdLinePaletteProvider("white", (yValue) => (yValue > 2 && yValue < 3)),
377 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
378 });
379 sciChartSurface.renderableSeries.add(polarLine1, polarLine2);
380
381 sciChartSurface.chartModifiers.add(
382 new PolarPanModifier(),
383 new PolarZoomExtentsModifier(),
384 new PolarMouseWheelZoomModifier()
385 );
386
387 return { sciChartSurface, wasmContext };
388 };
389
390 const line5 = async (rootElement: string | HTMLDivElement) => {
391 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
392 ...COMMON_POLAR_SURFACE_OPTIONS,
393 title: "Line dataLabels",
394 });
395
396 // Add the yAxis
397 const radialYAxis = new PolarNumericAxis(wasmContext, {
398 ...COMMON_RADIAL_AXIS_OPTIONS,
399
400 // gridlineMode: EPolarGridlineMode.Polygons,
401 drawLabels: false,
402
403 autoTicks: false,
404 majorDelta: 1,
405 visibleRange: new NumberRange(0, 5),
406 zoomExtentsToInitialRange: true,
407 majorGridLineStyle: {
408 color: appTheme.DarkIndigo,
409 strokeThickness: 1,
410 }
411 });
412 sciChartSurface.yAxes.add(radialYAxis);
413
414 // Add the xAxis
415 const angularXAxis = new PolarNumericAxis(wasmContext, {
416 ...COMMON_ANGULAR_AXIS_OPTIONS,
417
418 visibleRange: new NumberRange(0, Math.PI * 2), // Full trigonometric circle
419 zoomExtentsToInitialRange: true,
420
421 labelProvider: new RadianLabelProvider({
422 maxDenominator: 4,
423 labelPrecision: 2
424 }),
425
426 majorGridLineStyle: {
427 color: appTheme.DarkIndigo,
428 strokeThickness: 1,
429 },
430 autoTicks: false,
431 majorDelta: Math.PI / 4, // needed by RadianLabelProvider to show PI fractions
432 });
433 sciChartSurface.xAxes.add(angularXAxis);
434
435 // Add line:
436 const line = new PolarLineRenderableSeries(wasmContext, {
437 dataSeries: new XyDataSeries(wasmContext, {
438 xValues: Array.from({ length: 9 }, (_, i) => i * Math.PI / 4),
439 yValues: [ 4, 4.2, 3.5, 1.6, 3.8, 4, 1.8, 4, 2 ]
440 }),
441 stroke: appTheme.VividOrange,
442 strokeThickness: 4,
443 dataLabels: {
444 color: "white",
445 style: {
446 fontSize: 10,
447 },
448 horizontalTextPosition: EHorizontalTextPosition.Center,
449 verticalTextPosition: EVerticalTextPosition.Center,
450 skipMode: EDataLabelSkipMode.ShowAll
451 },
452 pointMarker: new EllipsePointMarker(wasmContext, {
453 width: 18,
454 height: 18,
455 stroke: appTheme.VividOrange,
456 fill: appTheme.DarkIndigo,
457 strokeThickness: 1,
458 }),
459 animation: new SweepAnimation({ duration: 800, fadeEffect: true })
460 })
461 sciChartSurface.renderableSeries.add(line);
462
463 sciChartSurface.chartModifiers.add(
464 new PolarPanModifier(),
465 new PolarZoomExtentsModifier(),
466 new PolarMouseWheelZoomModifier(),
467 );
468
469 return { sciChartSurface, wasmContext };
470 };
471
472 const line6 = async (rootElement: string | HTMLDivElement) => {
473 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
474 ...COMMON_POLAR_SURFACE_OPTIONS,
475 title: "Palette Provider Sprial Line",
476 });
477
478 const NR_POINTS = 40;
479 const OFFSET = 30;
480
481 // Add the yAxis
482 const radialYAxis = new PolarNumericAxis(wasmContext, {
483 ...COMMON_RADIAL_AXIS_OPTIONS,
484
485 visibleRange: new NumberRange(0, NR_POINTS + OFFSET),
486 zoomExtentsToInitialRange: true,
487 drawLabels: false
488 });
489 sciChartSurface.yAxes.add(radialYAxis);
490
491 // Add the xAxis
492 const angularXAxis = new PolarNumericAxis(wasmContext, {
493 ...COMMON_ANGULAR_AXIS_OPTIONS,
494 zoomExtentsToInitialRange: true,
495 flippedCoordinates: true, // go clockwise
496 startAngle: Math.PI / 2, // Start drawing at 12 o'clock
497 });
498 sciChartSurface.xAxes.add(angularXAxis);
499
500 class XLinePaletteProvider extends DefaultPaletteProvider {
501 private readonly _colors = [
502 appTheme.VividOrange,
503 appTheme.VividTeal + "88",
504 ]
505
506 constructor() {
507 super();
508 this.strokePaletteMode = EStrokePaletteMode.SOLID;
509 }
510
511 // This function is called for every data-point.
512 // Return undefined to use the default color for the line,
513 // else, return a custom colour as an ARGB color code, e.g. 0xFFFF0000 is red
514 overrideStrokeArgb(xValue: number, yValue: number, index: number, opacity: number, metadata: any) {
515 return parseColorToUIntArgb(
516 this._colors[Math.min(Math.floor(index / 10)) % this._colors.length]
517 );
518 }
519 }
520
521 // Add SERIES
522 const polarLine = new PolarLineRenderableSeries(wasmContext, {
523 dataSeries: new XyDataSeries(wasmContext, {
524 xValues: Array.from({ length: NR_POINTS }, (_, i) => (i+1) % 10),
525 yValues: Array.from({ length: NR_POINTS }, (_, i) => i + OFFSET)
526 }),
527 stroke: appTheme.VividTeal,
528 strokeThickness: 4,
529 animation: new SweepAnimation({ duration: 800, fadeEffect: true }),
530 paletteProvider: new XLinePaletteProvider(),
531 });
532
533 sciChartSurface.renderableSeries.add(polarLine);
534
535 sciChartSurface.chartModifiers.add(
536 new PolarPanModifier(),
537 new PolarZoomExtentsModifier(),
538 new PolarMouseWheelZoomModifier(),
539 new PolarCursorModifier()
540 );
541
542 sciChartSurface.zoomExtents();
543
544 return { sciChartSurface, wasmContext };
545 };
546
547 return {
548 line1,
549 line2,
550 line3,
551 line4,
552 line5,
553 line6,
554 };
555};
556
Angular Polar Spline Line Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Line Temperature Average demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Column Category Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Range Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Windrose Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Sunburst Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Radial Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Stacked Radial Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Mountain Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Stacked Mountain Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Band Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Scatter Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Radar Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Gauge Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Gauge Fifo Dashboard demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Uniform Heatmap Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Ultrasound Heatmap demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Partial Arc demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.
Angular Polar Label Modes demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.