Skip to content

[Feature] hide axes when series is empty#4521

Open
xuefei1313 wants to merge 3 commits intodevelopfrom
010-hide-empty-axes
Open

[Feature] hide axes when series is empty#4521
xuefei1313 wants to merge 3 commits intodevelopfrom
010-hide-empty-axes

Conversation

@xuefei1313
Copy link
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

close #4490

🔗 Related PR link

🐞 Bugserver case id

💡 Background and solution

Add an opt-in hideWhenEmpty axis option for cartesian axes. The axis should hide when its bound series produce no collected axis data, while preserving existing behavior by default. The implementation will separate user-configured visibility from runtime empty-data visibility so the axis can auto-hide and reappear after updateData or updateSpec without requiring chart remake.

Language/Version: TypeScript 4.9.5
Primary Dependencies: @visactor/vchart, @visactor/vutils, @visactor/vrender-components
Storage: N/A
Testing: Jest
Target Platform: Web and cross-terminal chart runtimes supported by VChart
Project Type: Monorepo / Chart library
Performance Goals: No noticeable render or update regression; axis visibility recalculation should stay within existing axis domain update flow
Constraints: Cartesian axes only for this scope; must support runtime auto hide/show after data updates; must preserve existing behavior when option is unset
Scale/Scope: Public axis spec in packages/vchart and packages/vchart-types, axis runtime behavior in cartesian axis base flow, targeted unit regression coverage

📝 Changelog

Language Changelog
🇺🇸 English Add hideWhenEmpty for cartesian axes so empty bound-series axes can hide and reappear automatically after data updates.
🇨🇳 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 force-pushed the 010-hide-empty-axes branch from b3c51f2 to fd653c9 Compare March 20, 2026 08:05
Copy link
Contributor Author

@xuefei1313 xuefei1313 left a comment

Choose a reason for hiding this comment

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

本次 PR 实现了 Cartesian 轴的 hideWhenEmpty 配置项,允许坐标轴在关联系列数据为空时自动隐藏,并在数据更新后自动恢复。

主要改进点:

  1. 状态分离:通过 _specVisible_visible 的分离,优雅地处理了用户配置可见性与运行时可见性的关系。
  2. 生命周期集成:在 BandAxisMixinLinearAxisMixin 中集成了可见性刷新逻辑,确保数据驱动的准确性。
  3. 渲染健壮性:在 BaseMark 中增加了延迟初始化逻辑,解决了 Product 在隐藏期间可能被移除的问题。
  4. 性能考虑:在 AxisComponent 中优化了 collectData 的空值处理。

建议:

  • 确认 @since 2.0.20 版本号是否与当前发布计划一致。
  • 考虑到这是一个通用能力,未来可以评估是否扩展到极坐标轴。

总体代码质量很高,逻辑严密。

(!this._skipBeforeLayouted || this.getCompiler().getLayoutState() !== LayoutState.before)
) {
// A mark may lose its product when visibility toggles to false during compile.
// Later data/layout updates can make it visible again without triggering compile,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

这里在 render 时延迟初始化 product 是为了支持从隐藏转为显示的状态。需要确认 _initProduct() 在没有传入 group 参数时是否能正确挂载到父级容器中(默认为 RootGroup),特别是对于 Series 中的 Mark,可能需要挂载到 SeriesGroup 下。

protected _shouldComputeTickData() {
// 当轴被展示、或者强制要求计算 data 时再计算 data
return this.getVisible() || this._spec.forceInitTick;
return this._specVisible && (this.getVisible() || this._spec.forceInitTick || this._hideWhenEmpty);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

如果 _hideWhenEmpty 为 true,即使当前 getVisible() 为 false(因为数据为空),也会返回 true 从而触发 _initData()。这符合“保留 tick 数据以备后续显示”的设计,但要确保在数据量极大时不会产生不必要的计算开销。

protected _syncComponentVisibility() {
this._axisMark?.setVisible(this._visible);
this._gridMark?.setVisible(this._visible && this._spec.grid?.visible !== false);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

collectData(0) 会遍历所有关联的 series。在 BandAxisMixinLinearAxisMixin 的 domain 更新流中,此方法会被重复调用(一次用于 domain,一次用于 visibility)。建议考虑缓存 collect 结果或复用 domain 计算时的数据以优化性能。

Copy link
Contributor Author

@xuefei1313 xuefei1313 left a comment

Choose a reason for hiding this comment

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

对 PR #4521 (实现轴在数据为空时自动隐藏功能) 的深度 Review 总结:

变更点分析

  1. Spec 扩展:在 ICartesianAxisCommonSpec 中增加了 hideWhenEmpty 配置项。
  2. 可见性逻辑重构:将轴的可见性拆分为 _specVisible (用户配置) 和 _visible (实际运行状态),支持根据数据收集情况动态切换。
  3. 数据流集成:在 mixin (Band/Linear) 的 domain 更新阶段触发可见性检查,并强制触发 forceLayout 以重新分配图表空间。
  4. Mark 延迟初始化:在 BaseMarkrender 阶段增加了对 _product 的懒初始化,以支持从隐藏状态恢复时的图元创建。

发现的问题与改进建议

  1. 性能优化_refreshVisibilityByData 内部调用的 collectData(0) 在 domain 更新流程中会被重复执行。在大数据量或多系列场景下,建议缓存数据收集结果或复用 domain 计算时的数据统计信息。
  2. 渲染安全性BaseMark 在 render 时调用 _initProduct() 需确保其默认挂载逻辑(通常挂载至 RootGroup)符合业务 mark (如 Series 下的 Mark) 的层级要求。
  3. 类型严谨性:在 _syncComponentVisibility 中对 getComponent() 返回值转换为 IGroup 并调用 setAttributes 时,建议增加更严谨的类型校验。
  4. 测试覆盖:已提供的单元测试覆盖了初始渲染和数据更新场景,建议增加 updateSpec 切换 hideWhenEmpty 开关的测试用例。

总体实现方案符合 VChart 架构设计,逻辑清晰。建议关注上述性能及类型细节。详细评论已在代码行中列出。

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.

[Feature] hide axes when series is empty

1 participant