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