You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2026/05/02 03:45:49 UTC

(echarts) branch codex/issue-21133-sunburst-label-center-clean created (now 0f082e65d)

This is an automated email from the ASF dual-hosted git repository.

susiwen8 pushed a change to branch codex/issue-21133-sunburst-label-center-clean
in repository https://gitbox.apache.org/repos/asf/echarts.git


      at 0f082e65d Keep drilled sunburst root labels visually centered

This branch includes the following new commits:

     new 0f082e65d Keep drilled sunburst root labels visually centered

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


(echarts) 01/01: Keep drilled sunburst root labels visually centered

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

susiwen8 pushed a commit to branch codex/issue-21133-sunburst-label-center-clean
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 0f082e65da0dd074bf4bc56648b5c90be8ac9d11
Author: susiwen8 <su...@gmail.com>
AuthorDate: Sat May 2 11:02:09 2026 +0800

    Keep drilled sunburst root labels visually centered
    
    A drilled sunburst view root can become a full annular sector when rootToNode is triggered. In that state the label represents the centered root, not an angular slice, so the label should sit on the chart center without inheriting radial rotation.
    
    Constraint: Preserve existing radial and tangential rotation for ordinary sunburst sectors and outside labels.
    Rejected: Keep using the annulus midpoint | it leaves full-circle drilldown labels offset from the visual root.
    Rejected: Only adjust x/y | the label can remain rotated by the previous radial orientation.
    Confidence: high
    Scope-risk: narrow
    Directive: Do not reapply radial rotation to labels placed at the center of a full-circle sunburst sector.
    Tested: git diff --check
    Tested: eslint src/chart/sunburst/SunburstPiece.ts test/ut/spec/series/sunburst.test.ts
    Tested: tsc --noEmit
    Tested: jest --config test/ut/jest.config.cjs --coverage=false --runInBand test/ut/spec/series
    Not-tested: Full visual screenshot baseline suite
---
 src/chart/sunburst/SunburstPiece.ts  |  12 +++--
 test/ut/spec/series/sunburst.test.ts | 102 +++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/src/chart/sunburst/SunburstPiece.ts b/src/chart/sunburst/SunburstPiece.ts
index edff51730..cd8240373 100644
--- a/src/chart/sunburst/SunburstPiece.ts
+++ b/src/chart/sunburst/SunburstPiece.ts
@@ -220,6 +220,8 @@ class SunburstPiece extends graphic.Sector {
             const flipStartAngle = Math.PI * 0.5;
             const flipEndAngle = Math.PI * 1.5;
             const midAngleNormal = normalizeRadian(rotateType === 'tangential' ? Math.PI / 2 - midAngle : midAngle);
+            const isFullCircle = isRadianAroundZero(Math.abs(angle) - 2 * Math.PI);
+            let isLabelAtCenter = false;
 
             // For text that is up-side down, rotate 180 degrees to make sure
             // it's readable
@@ -233,9 +235,10 @@ class SunburstPiece extends graphic.Sector {
             }
             else {
                 if (!textAlign || textAlign === 'center') {
-                    // Put label in the center if it's a circle
-                    if (layout.r0 === 0 && isRadianAroundZero(angle - 2 * Math.PI)) {
+                    // Put label in the center if it's a full circle.
+                    if (isFullCircle) {
                         r = 0;
+                        isLabelAtCenter = true;
                     }
                     else {
                         r = (layout.r + layout.r0) / 2;
@@ -259,7 +262,10 @@ class SunburstPiece extends graphic.Sector {
             state.y = r * dy + layout.cy;
 
             let rotate = 0;
-            if (rotateType === 'radial') {
+            if (isLabelAtCenter) {
+                rotate = 0;
+            }
+            else if (rotateType === 'radial') {
                 rotate = normalizeRadian(-midAngle)
                     + (needsFlip ? Math.PI : 0);
             }
diff --git a/test/ut/spec/series/sunburst.test.ts b/test/ut/spec/series/sunburst.test.ts
new file mode 100644
index 000000000..cb9a8f6f7
--- /dev/null
+++ b/test/ut/spec/series/sunburst.test.ts
@@ -0,0 +1,102 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { EChartsType } from '@/src/echarts';
+import SunburstSeriesModel from '@/src/chart/sunburst/SunburstSeries';
+import { TreeNode } from '@/src/data/Tree';
+import { createChart, getECModel } from '../../core/utHelper';
+
+function findNodeByName(seriesModel: SunburstSeriesModel, name: string): TreeNode {
+    let targetNode: TreeNode;
+
+    seriesModel.getData().tree.root.eachNode(node => {
+        if (node.name === name) {
+            targetNode = node;
+        }
+    });
+
+    return targetNode;
+}
+
+describe('series/sunburst', function () {
+
+    let chart: EChartsType;
+
+    beforeEach(function () {
+        chart = createChart({
+            width: 400,
+            height: 400
+        });
+    });
+
+    afterEach(function () {
+        chart.dispose();
+    });
+
+    it('centers label when rootToNode makes an annular sector full circle', function () {
+        chart.setOption({
+            animation: false,
+            series: {
+                type: 'sunburst',
+                radius: [0, '80%'],
+                label: {
+                    show: true,
+                    align: 'center'
+                },
+                data: [
+                    {
+                        name: '华南',
+                        children: [
+                            {name: '广东', value: 2},
+                            {name: '广西', value: 1}
+                        ]
+                    },
+                    {
+                        name: '华北',
+                        children: [
+                            {name: '北京', value: 2},
+                            {name: '天津', value: 1}
+                        ]
+                    }
+                ]
+            }
+        });
+
+        let seriesModel = getECModel(chart).getSeriesByType('sunburst')[0] as SunburstSeriesModel;
+        const targetNode = findNodeByName(seriesModel, '华南');
+
+        chart.dispatchAction({
+            type: 'sunburstRootToNode',
+            targetNode: targetNode
+        });
+
+        seriesModel = getECModel(chart).getSeriesByType('sunburst')[0] as SunburstSeriesModel;
+        const viewRoot = seriesModel.getViewRoot();
+        const layout = viewRoot.getLayout();
+        const label = seriesModel.getData().getItemGraphicEl(viewRoot.dataIndex).getTextContent();
+
+        expect(viewRoot.name).toBe('华南');
+        expect(layout.r0).toBeGreaterThan(0);
+        expect(Math.abs(layout.endAngle - layout.startAngle)).toBeCloseTo(Math.PI * 2);
+        expect(label.x).toBeCloseTo(layout.cx);
+        expect(label.y).toBeCloseTo(layout.cy);
+        expect(label.rotation).toBeCloseTo(0);
+    });
+
+});


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org