Creates a Angular Polar Sunburst Chart using SciChart.js, with multiple levels and interaction driven animations.
Also Known As: Radial Treemap, Circular Treemap.
drawExample.ts
angular.ts
theme.ts
sunburstData.ts
SunburstMetadata.ts
SunburstPaletteProvider.ts
1import {
2 PolarColumnRenderableSeries,
3 PolarNumericAxis,
4 SciChartPolarSurface,
5 EPolarAxisMode,
6 NumberRange,
7 EAxisAlignment,
8 EPolarLabelMode,
9 PolarCursorModifier,
10 TCursorTooltipDataTemplate,
11 SeriesInfo,
12 PolarDataPointSelectionModifier,
13 TSciChart,
14 EColumnMode,
15 XyxDataSeries,
16 EMultiLineAlignment,
17 EColumnDataLabelPosition,
18 EDataPointWidthMode,
19 GenericAnimation,
20 easing,
21 DoubleAnimator,
22} from "scichart";
23import { appTheme } from "../../../theme";
24import { SunburstMetadata } from "./SunburstMetadata";
25import { SunburstPaletteProvider } from "./SunburstPaletteProvider";
26import { getDataById, getElementById, TLevelDataForChart } from "./sunburstData";
27
28const drawSeriesFn = (
29 wasmContext: TSciChart,
30 xAxis: PolarNumericAxis,
31 yAxis: PolarNumericAxis,
32 sciChartSurface: SciChartPolarSurface,
33 polarLabelMode: EPolarLabelMode,
34 dataPointSelectionModifier: PolarDataPointSelectionModifier,
35 nodeId: number[],
36 selectedElStartX: number,
37 prevNodeId: number[]
38) => {
39 const startAngleDefault = -Math.PI / 2;
40
41 const clearSeriesFn = () => {
42 dataPointSelectionModifier.selectionChanged.unsubscribeAll();
43 sciChartSurface.renderableSeries.asArray().forEach((rs) => rs.delete());
44 sciChartSurface.renderableSeries.clear();
45 };
46
47 const level = nodeId.length - 1;
48 const prevLevel = prevNodeId.length - 1;
49 const prevXVisRangeDiff = xAxis.visibleRange.diff;
50
51 const polarColumnMode = EColumnMode.StartEnd;
52 const dataPointWidth = 0.5;
53 const paletteProvider = new SunburstPaletteProvider();
54
55 const createDataFn = (input$: TLevelDataForChart) => {
56 const [xValues$, yValues$, x1Values$] = input$.data;
57 return new XyxDataSeries(wasmContext, {
58 xValues: xValues$,
59 yValues: yValues$,
60 x1Values: x1Values$,
61 metadata: input$.metadata,
62 });
63 };
64
65 const levelData = getDataById(nodeId);
66 const rootNode = getElementById(nodeId);
67
68 const redrawSeriesFn = () => {
69 clearSeriesFn();
70 for (let i = 0; i < levelData.length; i++) {
71 const rs$ = new PolarColumnRenderableSeries(wasmContext, {
72 stroke: "black",
73 columnXMode: polarColumnMode,
74 dataLabels: {
75 style: {
76 fontSize: 16,
77 multiLineAlignment: EMultiLineAlignment.Center,
78 lineSpacing: 8,
79 },
80 color: "black",
81 precision: 2,
82 pointGapThreshold: 0,
83 skipNumber: 0,
84 polarLabelMode,
85 labelYPositionMode: EColumnDataLabelPosition.Position,
86 labelYPositionMultiplier: 0.5,
87 metaDataSelector: (metadata) => {
88 const md = metadata as SunburstMetadata;
89 return `${md.title} \n ${md.value}`;
90 },
91 },
92 dataSeries: createDataFn(levelData[i]),
93 strokeThickness: 2,
94 dataPointWidth,
95 dataPointWidthMode: EDataPointWidthMode.Range,
96 defaultY1: i,
97 paletteProvider: paletteProvider,
98 });
99 dataPointSelectionModifier.includeSeries(rs$, true);
100 sciChartSurface.renderableSeries.add(rs$);
101 }
102 };
103
104 const drillDownAnimationFn = (isReverse$: boolean, onCompleteFn$: () => void = () => undefined) => {
105 const xMin$ = 0; // always zero
106 const xMax0$ = prevXVisRangeDiff;
107 const xMax1$ = rootNode.value;
108
109 const startAngle0$ = isReverse$
110 ? startAngleDefault
111 : startAngleDefault + (2 * Math.PI * selectedElStartX) / xAxis.visibleRange.diff;
112 let startAngle1$: number;
113 if (isReverse$) {
114 const levelDiff$ = prevLevel - level;
115 const element$ = levelData[levelDiff$].metadata.find((a) => a.id.toString() === prevNodeId.toString());
116 startAngle1$ = startAngleDefault + (2 * Math.PI * element$.start) / rootNode.value;
117 } else {
118 startAngle1$ = startAngleDefault;
119 }
120
121 const yMin0$ = isReverse$ ? 0 : prevLevel - level;
122 const yMin1$ = isReverse$ ? level - prevLevel : 0;
123
124 const from$ = { x1: xMax0$, x2: startAngle0$, y1: yMin0$, y2: 0 };
125 const to$ = { x1: xMax1$, x2: startAngle1$, y1: yMin1$, y2: 0 };
126
127 const sweepAnimation = new GenericAnimation({
128 from: from$,
129 to: to$,
130 duration: 1000,
131 ease: easing.inOutSine,
132 onAnimate: (from, to, progress) => {
133 const xMaxCur = DoubleAnimator.interpolate(from.x1, to.x1, progress);
134 const startAngleCur = DoubleAnimator.interpolate(from.x2, to.x2, progress);
135 const yMinCur = DoubleAnimator.interpolate(from.y1, to.y1, progress);
136 const yMaxCur = yMinCur + 4;
137 xAxis.visibleRange = new NumberRange(xMin$, xMaxCur);
138 xAxis.startAngle = startAngleCur;
139 yAxis.visibleRange = new NumberRange(yMinCur, yMaxCur);
140 },
141 onCompleted: () => {
142 onCompleteFn$();
143 },
144 });
145 sciChartSurface.addAnimation(sweepAnimation);
146 };
147
148 const subscribeFn = () => {
149 dataPointSelectionModifier.selectionChanged.subscribe((args) => {
150 const selectedDataPoint = args.selectedDataPoints[0];
151 if (selectedDataPoint) {
152 const { yValue } = selectedDataPoint;
153 const md = selectedDataPoint?.metadata as SunburstMetadata;
154 const { id } = md;
155 const newId = [...id];
156 if (yValue === 1 && id.length > 1) {
157 newId.pop();
158 }
159 drawSeriesFn(
160 wasmContext,
161 xAxis,
162 yAxis,
163 sciChartSurface,
164 polarLabelMode,
165 dataPointSelectionModifier,
166 newId,
167 md.start,
168 nodeId
169 );
170 }
171 });
172 };
173
174 if (level < prevLevel) {
175 drillDownAnimationFn(true, () => {
176 redrawSeriesFn();
177 xAxis.startAngle = startAngleDefault;
178 yAxis.visibleRange = new NumberRange(0, 4);
179 subscribeFn();
180 });
181 } else if (level > prevLevel) {
182 redrawSeriesFn();
183 drillDownAnimationFn(false);
184 subscribeFn();
185 } else {
186 xAxis.startAngle = startAngleDefault;
187 xAxis.visibleRange = new NumberRange(0, rootNode.value);
188 yAxis.visibleRange = new NumberRange(0, 4);
189 redrawSeriesFn();
190 subscribeFn();
191 }
192};
193
194export const drawExample = async (rootElement: string | HTMLDivElement) => {
195 const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create(rootElement, {
196 theme: appTheme.SciChartJsTheme,
197 });
198
199 const startAngle = -Math.PI / 2;
200 const totalAngle = 2 * Math.PI;
201
202 const xAxis = new PolarNumericAxis(wasmContext, {
203 isVisible: false,
204 polarAxisMode: EPolarAxisMode.Angular,
205 axisAlignment: EAxisAlignment.Top,
206 visibleRange: new NumberRange(0, 65),
207 startAngle,
208 totalAngle,
209 });
210 xAxis.polarLabelMode = EPolarLabelMode.Parallel;
211 sciChartSurface.xAxes.add(xAxis);
212
213 const yAxis = new PolarNumericAxis(wasmContext, {
214 isVisible: false,
215 polarAxisMode: EPolarAxisMode.Radial,
216 axisAlignment: EAxisAlignment.Right,
217 visibleRange: new NumberRange(0, 6),
218 flippedCoordinates: false,
219 startAngle,
220 totalAngle,
221 });
222 sciChartSurface.yAxes.add(yAxis);
223
224 const dataPointSelectionModifier = new PolarDataPointSelectionModifier({
225 allowClickSelect: true,
226 allowDragSelect: false,
227 selectionStroke: "red",
228 selectionFill: "#ff879f33",
229 });
230
231 drawSeriesFn(
232 wasmContext,
233 xAxis,
234 yAxis,
235 sciChartSurface,
236 EPolarLabelMode.Parallel,
237 dataPointSelectionModifier,
238 [0],
239 0,
240 [0]
241 );
242
243 const tooltipDataTemplate: TCursorTooltipDataTemplate = (seriesInfos: SeriesInfo[], tooltipTitle: string) => {
244 const res: string[] = [];
245 seriesInfos.forEach((si) => {
246 if (si.isHit) {
247 const md = si.pointMetadata as SunburstMetadata;
248 res.push(`Name: ${md.title}`);
249 res.push(`Value: ${md.value}`);
250 }
251 });
252 return res;
253 };
254
255 sciChartSurface.chartModifiers.add(
256 dataPointSelectionModifier,
257 new PolarCursorModifier({
258 showTooltip: true,
259 showCircularLine: false,
260 showRadialLine: false,
261 tooltipDataTemplate,
262 })
263 );
264
265 return { sciChartSurface, wasmContext };
266};
267This Angular example demonstrates how to create a Polar Sunburst Chart using the ScichartAngularComponent. The chart visualizes hierarchical data through animated polar columns with interactive drill-down navigation.
The standalone Angular component imports ScichartAngularComponent and passes the drawExample function via input binding. The chart surface is created asynchronously using SciChartPolarSurface.create(). The recursive drawSeriesFn handles dynamic series generation for each hierarchy level.
The implementation features smooth animated transitions between hierarchy levels using GenericAnimation. Interactive selection is handled by PolarDataPointSelectionModifier. The custom SunburstMetadata class manages node-specific visual properties.
The example follows Angular best practices by using standalone components and proper dependency injection. The ScichartAngularComponent automatically manages chart lifecycle including WebAssembly resource cleanup.

Explore the React Polar Line Chart example to create data labels, line interpolation, gradient palette stroke and startup animations. Try the SciChart Demo.

Try the Angular Polar Spline Line Chart example to see SciChart's GPU-accelerated rendering in action. Choose a cubic spline or polar interpolation. View demo.

Create an Angular Multi-Cycle Polar Chart to plot data over multiple cycles and visualize patterns over time. This example shows surface temperature by month.

Try the Angular Polar Bar Chart example to render bars in a polar layout with gradient fills and animations. Use SciChart for seamless integration.

Create an Angular Polar Colum Category chart visualizing UK consumer price changes. Try the demo with a custom positive/negative threshold fill and stroke.

Create an Angular Polar Range Column Chart with SciChart. This example displays monthly minimum and maximum temperatures within a Polar layout. Try the demo.

View the Angular Windrose Chart example to display directional data with stacked columns in a polar layout. Try the polar chart demo with customizable labels.

View the Angular Radial Column Chart example to see the difference that SciChart has to offer. Switch radial and angular axes and add interactive modifiers.

This Angular Stacked Radial Bar Chart example shows Olympic medal data by country. Try the demo for yourself with async initialization and theme application.

The Angular Polar Area Chart example, also known as Nightingale Rose Chart, renders an area series with polar coordinates with interactive legend controls.

Try the Angular Stacked Radial Mountain Chart example to show multiple datasets on a polar layout with a stacked mountain series and animated transitions.

Create an Angular Polar Chart with regular and interpolated error bands. Enhance a standard chart with shaded areas to show upper and lower data boundaries.

Build a Angular Polar Scatter Chart with this example to render multiple scatter series on radial and angular axes. Try the flexible SciChart demo today.

View the Angular Polar Radar Chart example. Also known as the Spider Radar Chart, view the scalability and stability that SciChart has to offer. Try demo.

Create Angular Gauge Charts, including an Angular Circular Gauge Dashboard, with a friendly initialization and responsive design. Give the SciChart demo a go.

View Angular Arc Gauge Charts alongside FIFO Scrolling Charts, all on the same dashboard with real-time, high-performance data rendering. Try the demo.

Try SciChart's Angular Polar Heatmap example to combine a polar heatmap with a legend component. Supports responsive design and chart and legend separation.

No description available for this example yet

Create an Angular Polar Partial Arc that bends from a full Polar Circle to a Cartesian-like arc. Try the demo to display an arc segment with Polar coordinates.

Create an Angular Polar Axis Label with SciChart. This demo shows the various label modes for Polar Axes – all optimised for pan, zoom, and mouse wheel.

View the React Polar Map Example using the SciChartReact component. Display geographic data as color-coded triangles on a polar coordinate system. Try demo.