Skip to content

fix: preserve final attributes for exit animations - #4646

Open
skie1997 wants to merge 1 commit into
developfrom
codex/fix-grow-height-exit-final-attrs
Open

fix: preserve final attributes for exit animations#4646
skie1997 wants to merge 1 commit into
developfrom
codex/fix-grow-height-exit-final-attrs

Conversation

@skie1997

@skie1997 skie1997 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

[中文版模板 / Chinese template]

🤔 This is a ...

  • New feature
  • Bug fix
  • TypeScript definition update
  • Bundle size optimization
  • Performance optimization
  • Enhancement feature
  • Refactoring
  • Update dependency
  • Code style optimization
  • Test Case
  • Branch merge
  • Release
  • Site / documentation update
  • Demo update
  • Workflow
  • Other (about what?)

🔗 Related issue link

🔗 Related PR link

🐞 Bugserver case id

💡 问题背景与修复方案

问题背景

当配置 animationAppear: false、同时保留默认退场动画时,如果将柱状图数据整体替换为一组不同的 key,退场动画执行期间会抛出以下异常:

TypeError: Cannot read properties of undefined (reading 'y')
    at growHeightOutIndividual

异常由以下生命周期触发:

  1. 初始入场动画被关闭,VRender 不会通过入场动画初始化图元的 finalAttribute
  2. 数据更新后,旧柱图图元进入 exit 状态。
  3. VChart 为退场图元重建 context 时,丢失了上一轮的 finalAttrs 属性快照。
  4. 退场图元不会再次执行 encoder,因此 AnimateExecutor 在执行 growHeightOut 前没有可同步的最终属性;随后读取 graphic.getFinalAttribute().y 时触发异常。

因此,该问题并非业务数据缺少 yField 或数据内容非法,而是 VChart 图元 diff 与退场动画之间的生命周期契约问题。

修复方案

在 mark 数据 diff 重建图元 context 时,保留上一轮的 context.finalAttrs。仍处于活动状态的 enter/update 图元会在后续 encoder 阶段覆盖这份快照;exit 图元则可以保留最后一次有效的编码属性,供退场动画使用。

该修复继续沿用已有的 context.finalAttrs -> setFinalAttributes -> growHeightOut 标准链路,无需在 VRender 的逐图元动画热路径中增加宽泛的运行时兜底。

验证结果

  • 新增回归测试,覆盖 animationAppear: false、保留默认退场动画以及柱图数据 key 全量替换的场景。
  • 验证该测试在修复前能够复现 undefined.y 异常,修复后正常通过。
  • VChart package pre-push 测试通过:76 个 test suite、399 个测试全部通过。
  • TypeScript 编译检查通过。

📝 Changelog

Language Changelog
🇺🇸 English
🇨🇳 Chinese

☑️ Self-Check before Merge

⚠️ Please check all items below before requesting a reviewing. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • TypeScript definition is updated/provided or not needed
  • Changelog is provided or not needed

🚀 Summary

copilot:summary

🔍 Walkthrough

copilot:walkthrough

@xuefei1313 xuefei1313 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦞 Aime Bot Review

这次改动主要做了三件事:一是在 BaseMark 复用旧 context 时补上 finalAttrs 继承,避免 exit 图元在关闭 appear 动画时丢失退场动画所需的最终属性;二是补了一组 manual-ticker 回归用例,验证 animationAppear: false 时更新数据不会抛错,且退出柱子的 y/y1 仍保持预期;三是补充了 changelog,整体链路比较完整。

代码层面看,修复点放在 packages/vchart/src/mark/base/base-mark.ts 的通用上下文继承逻辑上,方向是对的,不过它的影响面会比当前新增的 bar 用例更广。测试文件这次覆盖得比较聚焦,资源释放也完整,这部分没有额外问题。这里想请确认一下:是否还需要再补一组非 bar mark 的回归用例,或者在 PR 描述里补充说明已有其他测试/场景能够间接覆盖 animationAppear: false + exit diffState 这条通用路径?这样后续回归时会更容易判断这次修复的边界。

从当前 diff 来看,修复思路直接、风险也比较可控。如果上面这个覆盖范围已经确认,我这边倾向于可以合并。

@xuefei1313

Copy link
Copy Markdown
Contributor

🦞 Aime Bot Review

改动摘要

本次修复解决了在关闭入场动画(animationAppear: false)时,柱图退场动画(exit animation)无法拿到正确最终属性(finalAttrs)的问题。核心改动是在 BaseMark 为图元构建新 context 时,从旧 context 中继承 finalAttrs,确保退场图元在不重新执行 encoder 的情况下仍能用上一轮的最终属性驱动退场动画。

代码观察

  1. packages/vchart/src/mark/base/base-mark.ts:新增 finalAttrs: g.context?.finalAttrs,与已有的 reusingoriginalFieldX 等继承字段保持一致,改动最小且定位准确。由于退场图元不会再次执行 encoder,这里继承上一轮的最终属性是合理的;对于 enter/update 图元,encoder 执行后会覆盖该值,不会产生副作用。
  2. 测试用例:新增的 keeps bar final attributes for exit animation when appear animation is disabled 用例构造了 animationAppear: false 的柱图,通过 updateDataSync 触发 exit,并断言 diffState === 'exit' 以及 finalAttrs.y / y1 保持不变,同时验证更新过程不抛错。场景覆盖与回归目标一致,断言也比较到位。
  3. changelogcommon/changes 下新增了 patch 级别的 change 文件,符合变更规范。

小建议

  • 可选:当前修复位于 BaseMark,理论上对所有继承它的 mark 类型生效。如果后续发现 line/area 等其他图元也存在类似退场属性丢失的场景,可以补充对应回归用例进一步加固。

合并建议

改动清晰、范围可控,测试覆盖合理,建议合并 ✅。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants