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

susiwen8 pushed a commit to branch codex/issue-21199-radial-label
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit a3cf6771f58cec108417f042c93a05d4167f5651
Author: susiwen8 <[email protected]>
AuthorDate: Sat May 2 00:21:04 2026 +0800

    Make dense chord labels readable around the ring
    
    Chord labels accepted the shared label.rotate shape but rendered every node 
label horizontally. This wires radial rotation into the chord label placement 
path and keeps numeric rotation working through the same branch, with a 
regression test that inspects the rendered node text rotation.
    
    Constraint: Issue #21199 asks specifically for label.rotate: 'radial' on 
chord labels.
    
    Rejected: Reuse pie label layout wholesale | chord labels do not use pie 
guide-line collision layout and only need the sector-midline rotation rule.
    
    Confidence: high
    
    Scope-risk: narrow
    
    Directive: Keep chord radial rotation aligned with pie's upright text flip 
unless chord label geometry changes.
    
    Tested: npx jest --config test/ut/jest.config.cjs --runTestsByPath 
test/ut/spec/series/chord.test.ts --coverage=false
    
    Tested: npm test -- --runInBand --coverage=false
    
    Tested: npm run checktype
    
    Tested: npm run lint -- --no-cache src/chart/chord/ChordPiece.ts 
src/chart/chord/ChordSeries.ts
    
    Tested: npx eslint --no-cache test/ut/spec/series/chord.test.ts
    
    Tested: npx tsc -p test/ut/tsconfig.json --noEmit --moduleResolution node 
--skipLibCheck
    
    Not-tested: npm run checkheader currently fails on pre-existing header gaps 
in test/ut/coverage/*, test/line-area-empty-dimension-name.html, and 
test/visualmap-seriesTargets.html.
---
 src/chart/chord/ChordPiece.ts     | 16 +++++++--
 src/chart/chord/ChordSeries.ts    |  3 +-
 test/ut/spec/series/chord.test.ts | 68 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/src/chart/chord/ChordPiece.ts b/src/chart/chord/ChordPiece.ts
index 8844a41f7..b6a8c6f68 100644
--- a/src/chart/chord/ChordPiece.ts
+++ b/src/chart/chord/ChordPiece.ts
@@ -17,7 +17,7 @@
 * under the License.
 */
 
-import { extend, retrieve3 } from 'zrender/src/core/util';
+import { extend, isNumber, retrieve3 } from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
 import SeriesData from '../../data/SeriesData';
 import { getSectorCornerRadius } from '../helper/sectorHelper';
@@ -29,6 +29,8 @@ import type { BuiltinTextPosition } from 
'zrender/src/core/types';
 import { setStatesStylesFromModel, toggleHoverEmphasis } from 
'../../util/states';
 import { getECData } from '../../util/innerStore';
 
+const RADIAN = Math.PI / 180;
+
 export default class ChordPiece extends graphic.Sector {
 
     constructor(data: SeriesData, idx: number, startAngle: number) {
@@ -174,10 +176,19 @@ export default class ChordPiece extends graphic.Sector {
             ? normalLabelModel.get('verticalAlign') || 'middle'
             : (dy > 0 ? 'top' : 'bottom');
 
+        let labelRotate = 0;
+        const rotate = normalLabelModel.get('rotate');
+        if (rotate === 'radial') {
+            labelRotate = dx < 0 ? -midAngle + Math.PI : -midAngle;
+        }
+        else if (isNumber(rotate)) {
+            labelRotate = rotate * RADIAN;
+        }
+
         label.attr({
             x: dx * r + layout.cx,
             y: dy * r + layout.cy,
-            rotation: 0,
+            rotation: labelRotate,
             style: {
                 align,
                 verticalAlign
@@ -185,4 +196,3 @@ export default class ChordPiece extends graphic.Sector {
         });
     }
 }
-
diff --git a/src/chart/chord/ChordSeries.ts b/src/chart/chord/ChordSeries.ts
index 39464d113..c2ca70bfa 100644
--- a/src/chart/chord/ChordSeries.ts
+++ b/src/chart/chord/ChordSeries.ts
@@ -97,9 +97,10 @@ export interface ChordEdgeLineStyleOption extends 
LineStyleOption {
     curveness?: number
 }
 
-export interface ChordNodeLabelOption extends 
Omit<SeriesLabelOption<CallbackDataParams>, 'position'> {
+export interface ChordNodeLabelOption extends 
Omit<SeriesLabelOption<CallbackDataParams>, 'position' | 'rotate'> {
     silent?: boolean
     position?: SeriesLabelOption['position'] | 'outside'
+    rotate?: number | 'radial'
 }
 
 export interface ChordEdgeStateOption {
diff --git a/test/ut/spec/series/chord.test.ts 
b/test/ut/spec/series/chord.test.ts
new file mode 100644
index 000000000..88375a5c9
--- /dev/null
+++ b/test/ut/spec/series/chord.test.ts
@@ -0,0 +1,68 @@
+/*
+* 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 ChordSeriesModel from '@/src/chart/chord/ChordSeries';
+import { createChart, getECModel } from '../../core/utHelper';
+
+describe('series/chord', function () {
+
+    let chart: EChartsType;
+
+    beforeEach(function () {
+        chart = createChart();
+    });
+
+    afterEach(function () {
+        chart.dispose();
+    });
+
+    it('supports radial label rotation', function () {
+        chart.setOption({
+            series: {
+                type: 'chord',
+                startAngle: 0,
+                padAngle: 0,
+                label: {
+                    show: true,
+                    rotate: 'radial'
+                },
+                data: [
+                    {name: 'a'},
+                    {name: 'b'}
+                ],
+                edges: [{
+                    source: 'a',
+                    target: 'b',
+                    value: 1
+                }]
+            }
+        });
+
+        const seriesModel = getECModel(chart).getSeriesByType('chord')[0] as 
ChordSeriesModel;
+        const data = seriesModel.getData();
+        const textContent = data.getItemGraphicEl(0).getTextContent();
+        const layout = data.getItemLayout(0);
+        const midAngle = (layout.startAngle + layout.endAngle) / 2;
+        const expectedRotation = Math.cos(midAngle) < 0 ? -midAngle + Math.PI 
: -midAngle;
+
+        expect(textContent.rotation).toBeCloseTo(expectedRotation);
+    });
+
+});


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to