JavaScript Polar Sunburst Chart

Creates a JavaScript Polar Sunburst Chart using SciChart.js, with the following features: DataLabels, Rounded corners, Gradient-palette fill, startup animations.

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.html

vanilla.ts

theme.ts

sunburstData.ts

SunburstMetadata.ts

Copy to clipboard
Minimise
Fullscreen
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};

See Also: Polar Charts (20 Demos)

JavaScript Polar Line Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Line Chart

JavaScript Polar Line Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Spline Line Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Spline Line Chart

JavaScript Polar Spline Line Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Line Temperature Average | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Line Temperature Average

JavaScript Polar Line Temperature Average demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Column Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Column Chart

JavaScript Polar Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Column Category Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Column Category Chart

JavaScript Polar Column Category Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Range Column Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Range Column Chart

JavaScript Polar Range Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Windrose Column Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Windrose Column Chart

JavaScript Windrose Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Radial Column Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Radial Column Chart

JavaScript Radial Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Stacked Radial Column Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Stacked Radial Column Chart

JavaScript Stacked Radial Column Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Mountain Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Mountain Chart

JavaScript Polar Mountain Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Stacked Mountain Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Stacked Mountain Chart

JavaScript Polar Stacked Mountain Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Band Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Band Chart

JavaScript Polar Band Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Scatter Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Scatter Chart

JavaScript Polar Scatter Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Radar Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Radar Chart

JavaScript Polar Radar Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Gauge Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Gauge Chart

JavaScript Polar Gauge Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Gauge Fifo Dashboard | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Gauge Fifo Dashboard

JavaScript Polar Gauge Fifo Dashboard demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Uniform Heatmap Chart | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Uniform Heatmap Chart

JavaScript Polar Uniform Heatmap Chart demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Ultrasound Heatmap | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Ultrasound Heatmap

JavaScript Polar Ultrasound Heatmap demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Partial Arc | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Partial Arc

JavaScript Polar Partial Arc demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

JavaScript Polar Label Modes | JavaScript Charts | SciChart.js | SciChart.js Demo

JavaScript Polar Label Modes

JavaScript Polar Label Modes demo by SciChart supports gradient fill and paletteproviders for more custom coloring options. Get your free demo now.

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.