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]
