From 0c082642e2c194431b321f957f883081969ef339 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Wed, 29 Apr 2026 13:52:21 +0800 Subject: [PATCH 1/2] feat: arc markpoint support animation. close VisActor/VChart#4572 --- ...-support-arc-animate_2026-04-29-05-51.json | 10 +++++ .../__tests__/unit/marker/point.test.ts | 43 ++++++++++++++++++- .../src/marker/animate/animate.ts | 2 +- .../src/marker/animate/call-in.ts | 13 +++--- .../src/marker/animate/clip-in.ts | 9 ++-- .../src/marker/animate/common.ts | 13 ++++-- .../src/marker/animate/fade-in.ts | 2 +- .../src/marker/animate/fade-out.ts | 2 +- packages/vrender-core/src/graphic/arc.ts | 8 ++-- packages/vrender-core/src/graphic/config.ts | 1 + .../vrender-core/src/interface/graphic/arc.ts | 4 ++ 11 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 common/changes/@visactor/vrender-components/feat-mark-point-support-arc-animate_2026-04-29-05-51.json diff --git a/common/changes/@visactor/vrender-components/feat-mark-point-support-arc-animate_2026-04-29-05-51.json b/common/changes/@visactor/vrender-components/feat-mark-point-support-arc-animate_2026-04-29-05-51.json new file mode 100644 index 000000000..cf9747280 --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-mark-point-support-arc-animate_2026-04-29-05-51.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": "feat: arc markpoint support animation. close VisAct", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file diff --git a/packages/vrender-components/__tests__/unit/marker/point.test.ts b/packages/vrender-components/__tests__/unit/marker/point.test.ts index 129f1ae51..8c9608fde 100644 --- a/packages/vrender-components/__tests__/unit/marker/point.test.ts +++ b/packages/vrender-components/__tests__/unit/marker/point.test.ts @@ -1,10 +1,11 @@ import type { Group, IGraphic, Stage } from '@visactor/vrender-core'; -import type { Tag, Segment } from '../../../src'; -import { MarkPoint } from '../../../src'; +import type { ArcSegment, Tag, Segment } from '../../../src'; +import { MarkPoint, registerMarkPointAnimate } from '../../../src'; import { createCanvas } from '../../util/dom'; import { createStage } from '../../util/vrender'; import { initBrowserEnv } from '@visactor/vrender-kits'; initBrowserEnv(); +registerMarkPointAnimate(); describe('Marker', () => { let stage: Stage; @@ -67,4 +68,42 @@ describe('Marker', () => { .text ).toBe('mark point label text'); }); + + it('MarkPoint arc line callIn animation', () => { + const markPoint = new MarkPoint({ + position: { + x: 100, + y: 250 + }, + itemLine: { + type: 'type-arc', + arcRatio: 0.8 + }, + itemContent: { + type: 'text', + offsetX: 100, + offsetY: 30, + style: { + text: 'mark point arc label text', + panel: { + visible: true + } + } + }, + animationEnter: { + type: 'callIn', + duration: 500, + easing: 'linear' + } + }); + stage.defaultLayer.add(markPoint as unknown as IGraphic); + stage.render(); + + const markPointContainer = markPoint.children[0] as unknown as Group; + const line = markPointContainer.children[0] as unknown as ArcSegment; + + expect(line.key).toBe('arc-segment'); + expect(line.line?.attribute.clipRange).toBe(0); + expect(line.line?.animates?.length).toBeGreaterThan(0); + }); }); diff --git a/packages/vrender-components/src/marker/animate/animate.ts b/packages/vrender-components/src/marker/animate/animate.ts index e4c9cacdc..3b29391d1 100644 --- a/packages/vrender-components/src/marker/animate/animate.ts +++ b/packages/vrender-components/src/marker/animate/animate.ts @@ -80,7 +80,7 @@ export function markArcAreaAnimate(area: IArc, label: Tag | Tag[], animationconf } export function markPointAnimate( - lines: [Segment, ILine], + lines: [Segment | ArcSegment, ILine], item: Tag | IRichText | ISymbol | IImage, animationconfig: any, state: MarkerAnimationState diff --git a/packages/vrender-components/src/marker/animate/call-in.ts b/packages/vrender-components/src/marker/animate/call-in.ts index b49f56c90..d2f0026aa 100644 --- a/packages/vrender-components/src/marker/animate/call-in.ts +++ b/packages/vrender-components/src/marker/animate/call-in.ts @@ -1,10 +1,10 @@ import type { EasingType, IImage, ILine, IRichText, ISymbol } from '@visactor/vrender-core'; -import type { Segment } from '../../segment'; +import type { ArcSegment, Segment } from '../../segment'; import type { Tag } from '../../tag'; -import { graphicFadeIn } from './common'; +import { getSegmentLineGraphics, graphicFadeIn } from './common'; export function pointCallIn( - itemLine: Segment, + itemLine: Segment | ArcSegment, decorativeLine: ILine, item: Tag | IRichText | ISymbol | IImage, duration: number, @@ -21,9 +21,10 @@ export function pointCallIn( graphicFadeIn(itemLine.startSymbol, delay, startSymbolDuration, easing); // line - itemLine.lines.forEach(line => line.setAttribute('clipRange', 0)); - itemLine.lines.forEach((l, index) => { - const stepDuration = lineDuration / itemLine.lines.length; + const lines = getSegmentLineGraphics(itemLine); + lines.forEach(line => line.setAttribute('clipRange', 0)); + lines.forEach((l, index) => { + const stepDuration = lineDuration / lines.length; l.animate() .wait(delay + startSymbolDuration + index * stepDuration) .to({ clipRange: 1 }, stepDuration, easing); diff --git a/packages/vrender-components/src/marker/animate/clip-in.ts b/packages/vrender-components/src/marker/animate/clip-in.ts index bcf8c3bcf..11320f729 100644 --- a/packages/vrender-components/src/marker/animate/clip-in.ts +++ b/packages/vrender-components/src/marker/animate/clip-in.ts @@ -1,7 +1,7 @@ import type { EasingType } from '@visactor/vrender-core'; import type { ArcSegment, Segment } from '../../segment'; import type { Tag } from '../../tag'; -import { graphicFadeIn } from './common'; +import { getSegmentLineGraphics, graphicFadeIn } from './common'; import { array } from '@visactor/vutils'; export function commonLineClipIn( @@ -20,9 +20,10 @@ export function commonLineClipIn( graphicFadeIn(line.startSymbol, delay, startSymbolDuration, easing); // line - line.lines.forEach(line => line.setAttribute('clipRange', 0)); - line.lines.forEach((l, index) => { - const stepDuration = lineDuration / line.lines.length; + const lines = getSegmentLineGraphics(line); + lines.forEach(line => line.setAttribute('clipRange', 0)); + lines.forEach((l, index) => { + const stepDuration = lineDuration / lines.length; l.animate() .wait(delay + startSymbolDuration + index * stepDuration) .to({ clipRange: 1 }, stepDuration, easing); diff --git a/packages/vrender-components/src/marker/animate/common.ts b/packages/vrender-components/src/marker/animate/common.ts index c80ec671f..7b8b19ea8 100644 --- a/packages/vrender-components/src/marker/animate/common.ts +++ b/packages/vrender-components/src/marker/animate/common.ts @@ -2,6 +2,13 @@ import type { EasingType, IGraphic } from '@visactor/vrender-core'; import type { ArcSegment, Segment } from '../../segment'; import type { Tag } from '../../tag'; +export function getSegmentLineGraphics(segment: Segment | ArcSegment): IGraphic[] { + if (!segment) { + return []; + } + return [...(segment.lines ?? []), (segment as ArcSegment).line].filter(Boolean) as IGraphic[]; +} + /** fade-in */ export function graphicFadeIn(graphic: IGraphic, delay: number, duration: number, easing: EasingType) { if (!graphic) { @@ -35,8 +42,7 @@ export function segmentFadeIn(segment: Segment, delay: number, duration: number, graphicFadeIn(segment.startSymbol, delay, duration, easing); // line - segment.lines.forEach(line => graphicFadeIn(line, delay, duration, easing)); - graphicFadeIn((segment as ArcSegment).line, delay, duration, easing); + getSegmentLineGraphics(segment).forEach(line => graphicFadeIn(line, delay, duration, easing)); // end symbol graphicFadeIn(segment.endSymbol, delay, duration, easing); @@ -77,8 +83,7 @@ export function segmentFadeOut(segment: Segment | ArcSegment, delay: number, dur graphicFadeOut(segment.startSymbol, delay, duration, easing); // line - segment.lines.forEach(line => graphicFadeOut(line, delay, duration, easing)); - graphicFadeOut((segment as ArcSegment).line, delay, duration, easing); + getSegmentLineGraphics(segment).forEach(line => graphicFadeOut(line, delay, duration, easing)); // end symbol graphicFadeOut(segment.endSymbol, delay, duration, easing); diff --git a/packages/vrender-components/src/marker/animate/fade-in.ts b/packages/vrender-components/src/marker/animate/fade-in.ts index a651b2079..192d77464 100644 --- a/packages/vrender-components/src/marker/animate/fade-in.ts +++ b/packages/vrender-components/src/marker/animate/fade-in.ts @@ -34,7 +34,7 @@ export function arcAreaFadeIn(area: IArc, label: Tag | Tag[], duration: number, } export function pointFadeIn( - itemLine: Segment, + itemLine: Segment | ArcSegment, decorativeLine: ILine, item: Tag | IRichText | ISymbol | IImage, duration: number, diff --git a/packages/vrender-components/src/marker/animate/fade-out.ts b/packages/vrender-components/src/marker/animate/fade-out.ts index 7ac460c29..141db5935 100644 --- a/packages/vrender-components/src/marker/animate/fade-out.ts +++ b/packages/vrender-components/src/marker/animate/fade-out.ts @@ -34,7 +34,7 @@ export function arcAreaFadeOut(area: IArc, label: Tag | Tag[], duration: number, } export function pointFadeOut( - itemLine: Segment, + itemLine: Segment | ArcSegment, decorativeLine: ILine, item: Tag | IRichText | ISymbol | IImage, duration: number, diff --git a/packages/vrender-core/src/graphic/arc.ts b/packages/vrender-core/src/graphic/arc.ts index 2e69dce91..8e27057d6 100644 --- a/packages/vrender-core/src/graphic/arc.ts +++ b/packages/vrender-core/src/graphic/arc.ts @@ -35,6 +35,7 @@ const ARC_UPDATE_TAG_KEY = [ 'cornerRadius', 'padAngle', 'padRadius', + 'clipRange', 'cap', ...GRAPHIC_UPDATE_TAG_KEY ]; @@ -146,15 +147,16 @@ export class Arc extends Graphic implements IArc { getParsedAngle() { const arcTheme = this.getGraphicTheme(); let { startAngle = arcTheme.startAngle, endAngle = arcTheme.endAngle } = this.attribute; - const { cap = arcTheme.cap } = this.attribute; + const { cap = arcTheme.cap, clipRange = arcTheme.clipRange } = this.attribute; const sign = endAngle - startAngle >= 0 ? 1 : -1; - const deltaAngle = endAngle - startAngle; + let deltaAngle = endAngle - startAngle; + deltaAngle *= Math.max(0, Math.min(clipRange, 1)); startAngle = clampAngleByRadian(startAngle); endAngle = startAngle + deltaAngle; - if (cap && abs(deltaAngle) < pi2 - epsilon) { + if (cap && abs(deltaAngle) > epsilon && abs(deltaAngle) < pi2 - epsilon) { let startCap = 1; let endCap = 1; if ((cap as boolean[]).length) { diff --git a/packages/vrender-core/src/graphic/config.ts b/packages/vrender-core/src/graphic/config.ts index b7ddc8e8a..b9bf2cc49 100644 --- a/packages/vrender-core/src/graphic/config.ts +++ b/packages/vrender-core/src/graphic/config.ts @@ -232,6 +232,7 @@ export const DefaultArcAttribute: Required = { cornerRadius: 0, padRadius: 0, padAngle: 0, + clipRange: 1, cap: false, forceShowCap: false }; diff --git a/packages/vrender-core/src/interface/graphic/arc.ts b/packages/vrender-core/src/interface/graphic/arc.ts index 6818430e7..3ab866e97 100644 --- a/packages/vrender-core/src/interface/graphic/arc.ts +++ b/packages/vrender-core/src/interface/graphic/arc.ts @@ -69,6 +69,10 @@ export type IArcAttribute = { * 当cap = true 并且 使用了渐变填充的时候,自动实现conical渐变,也就是环形的渐变 */ forceShowCap: boolean; + /** + * 按角度范围裁剪绘制比例,0 表示不绘制,1 表示完整绘制。 + */ + clipRange: number; }; /** * 内部缓存,用于存储一些内部变量 From 05249b380e45014662e56f60516790435a245c0a Mon Sep 17 00:00:00 2001 From: skie1997 Date: Wed, 29 Apr 2026 14:30:19 +0800 Subject: [PATCH 2/2] chore: test error --- .../__tests__/unit/marker/point.test.ts | 2 +- packages/vrender-components/src/marker/type.ts | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/vrender-components/__tests__/unit/marker/point.test.ts b/packages/vrender-components/__tests__/unit/marker/point.test.ts index 8c9608fde..eaf19dcef 100644 --- a/packages/vrender-components/__tests__/unit/marker/point.test.ts +++ b/packages/vrender-components/__tests__/unit/marker/point.test.ts @@ -104,6 +104,6 @@ describe('Marker', () => { expect(line.key).toBe('arc-segment'); expect(line.line?.attribute.clipRange).toBe(0); - expect(line.line?.animates?.length).toBeGreaterThan(0); + expect(line.line?.animates?.size).toBeGreaterThan(0); }); }); diff --git a/packages/vrender-components/src/marker/type.ts b/packages/vrender-components/src/marker/type.ts index af44ea090..406b1d952 100644 --- a/packages/vrender-components/src/marker/type.ts +++ b/packages/vrender-components/src/marker/type.ts @@ -195,14 +195,14 @@ export type BaseMarkerAnimation = { */ animationExit?: MarkerExitAnimation; }; -export type MarkerAnimation = MarkerUpdateAnimation | MarkerUpdateAnimation; +export type MarkerAnimation = MarkerUpdateAnimation | MarkerExitAnimation; export type MarkerUpdateAnimation = { /** * 设置动画的类型 */ type: T; -} & MarkerExitAnimation; +} & MarkerAnimationBase; export type MarkCommonLineAnimationType = 'clipIn' | 'fadeIn'; @@ -210,11 +210,7 @@ export type CommonMarkAreaAnimationType = 'fadeIn'; export type MarkPointAnimationType = 'callIn' | 'fadeIn'; -export type MarkerExitAnimation = { - /** - * 设置离场动画的类型为fadeOut,即淡出 - */ - type: 'fadeOut'; +export type MarkerAnimationBase = { /** * 动画的时长 */ @@ -229,6 +225,13 @@ export type MarkerExitAnimation = { easing?: EasingType; }; +export type MarkerExitAnimation = MarkerAnimationBase & { + /** + * 设置离场动画的类型为fadeOut,即淡出 + */ + type: 'fadeOut'; +}; + export type MarkerAnimationState = 'enter' | 'update' | 'exit'; /** state type */