From 581a9b4e2b13f90c20e583ff2cea7fa7ed98ea25 Mon Sep 17 00:00:00 2001 From: xile611 Date: Thu, 9 Apr 2026 12:01:39 +0800 Subject: [PATCH 1/2] fix: handle null start state in pie leap --- .../__tests__/unit/index.test.ts | 14 ++++++ .../src/customAnimates/pie-leap.ts | 50 ++++++++++++++++--- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/packages/vstory-animate/__tests__/unit/index.test.ts b/packages/vstory-animate/__tests__/unit/index.test.ts index 1f528a9a..23715381 100644 --- a/packages/vstory-animate/__tests__/unit/index.test.ts +++ b/packages/vstory-animate/__tests__/unit/index.test.ts @@ -1,5 +1,6 @@ import { BarBounce } from '../../src/customAnimates/bar-bounce'; import { BarLeap } from '../../src/customAnimates/bar-leap'; +import { PieLeap } from '../../src/customAnimates/pie-leap'; describe('custom bar animates', () => { it('should not crash when BarBounce receives a null from rect', () => { @@ -45,4 +46,17 @@ describe('custom bar animates', () => { expect(pathProxy.clear).toHaveBeenCalled(); expect(pathProxy.moveTo).toHaveBeenCalled(); }); + + it('should not crash when PieLeap receives a null from arc', () => { + const animate = new PieLeap(null, { x: 40, y: 60, innerRadius: 20, outerRadius: 80 }, 1000, 'linear' as any, {}); + const out: Record = {}; + + animate.onUpdate(false, 0.5, out); + + expect(animate.getFromProps()).toMatchObject({ x: 540, y: -440, innerRadius: 20, outerRadius: 50 }); + expect(animate.getEndProps()).toMatchObject({ x: 40, y: 60, innerRadius: 20, outerRadius: 80 }); + expect(Number.isFinite(out.x)).toBe(true); + expect(Number.isFinite(out.y)).toBe(true); + expect(Number.isFinite(out.outerRadius)).toBe(true); + }); }); diff --git a/packages/vstory-animate/src/customAnimates/pie-leap.ts b/packages/vstory-animate/src/customAnimates/pie-leap.ts index cefbcd60..f7ae13a5 100644 --- a/packages/vstory-animate/src/customAnimates/pie-leap.ts +++ b/packages/vstory-animate/src/customAnimates/pie-leap.ts @@ -1,6 +1,20 @@ import type { EasingType } from '@visactor/vrender'; import { ACustomAnimate, generatorPathEasingFunc } from '@visactor/vrender'; +interface IPieLeapAnimateProps { + y?: number; + x?: number; + innerRadius?: number; + outerRadius?: number; +} + +interface INormalizedPieLeapAnimateProps extends IPieLeapAnimateProps { + y: number; + x: number; + innerRadius: number; + outerRadius: number; +} + export const pieLeap1Str = 'M0,0 C0,0.301 0.256,1.032 0.607,1.033 0.763,1.033 0.752,0.983 0.86,0.983 0.978,0.983 0.972,1 1,1'; export const pieLeap2Str = @@ -9,6 +23,26 @@ export const pieLeap2Str = const pieLeap1 = generatorPathEasingFunc(pieLeap1Str); const pieLeap2 = generatorPathEasingFunc(pieLeap2Str); +function normalizePieLeapProps( + arc?: IPieLeapAnimateProps | null, + fallback?: IPieLeapAnimateProps | null +): INormalizedPieLeapAnimateProps { + const source = arc ?? {}; + const ref = fallback ?? {}; + + const innerRadius = source.innerRadius ?? ref.innerRadius ?? 0; + const outerRadius = source.outerRadius ?? ref.outerRadius ?? innerRadius; + + return { + ...ref, + ...source, + x: source.x ?? ref.x ?? 0, + y: source.y ?? ref.y ?? 0, + innerRadius, + outerRadius + }; +} + export class PieLeap extends ACustomAnimate<{ y: number; x: number; innerRadius: number; outerRadius: number }> { static label: string = 'pie-leap'; static delayPerTime: number = 50; @@ -17,19 +51,21 @@ export class PieLeap extends ACustomAnimate<{ y: number; x: number; innerRadius: declare valid: boolean; constructor( - from: { y: number; x: number; innerRadius: number; outerRadius: number }, - to: { y: number; x: number; innerRadius: number; outerRadius: number }, + from: { y: number; x: number; innerRadius: number; outerRadius: number } | null, + to: { y: number; x: number; innerRadius: number; outerRadius: number } | null, duration: number, easing: EasingType, params: any ) { + const target = normalizePieLeapProps(to, from); + const start = normalizePieLeapProps(from, target); const f = { - y: from.y - 500, - x: from.x + 500, - innerRadius: from.innerRadius, - outerRadius: (from.innerRadius + from.outerRadius) / 2 + y: start.y - 500, + x: start.x + 500, + innerRadius: start.innerRadius, + outerRadius: (start.innerRadius + start.outerRadius) / 2 }; - super(f, to, duration, easing, params); + super(f, target, duration, easing, params); } getEndProps(): Record { From 90888c4cf6b5f792bf9884fc857a3d2587272a3c Mon Sep 17 00:00:00 2001 From: xile611 Date: Thu, 9 Apr 2026 15:45:27 +0800 Subject: [PATCH 2/2] Update packages/vstory-animate/__tests__/unit/index.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/vstory-animate/__tests__/unit/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vstory-animate/__tests__/unit/index.test.ts b/packages/vstory-animate/__tests__/unit/index.test.ts index 23715381..d41d2ee2 100644 --- a/packages/vstory-animate/__tests__/unit/index.test.ts +++ b/packages/vstory-animate/__tests__/unit/index.test.ts @@ -2,7 +2,7 @@ import { BarBounce } from '../../src/customAnimates/bar-bounce'; import { BarLeap } from '../../src/customAnimates/bar-leap'; import { PieLeap } from '../../src/customAnimates/pie-leap'; -describe('custom bar animates', () => { +describe('custom animates', () => { it('should not crash when BarBounce receives a null from rect', () => { const animate = new BarBounce(null, { x: 20, x1: 60, y: 10, y1: 110 }, 1000, 'linear' as any, {}); const out: Record = {};