Skip to content

Fix Line animation when interrupted with non-data related changes#6641

Merged
ckifer merged 1 commit intomainfrom
line-animation
Nov 18, 2025
Merged

Fix Line animation when interrupted with non-data related changes#6641
ckifer merged 1 commit intomainfrom
line-animation

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Nov 16, 2025

Description

We already had a nice handing for when an animation is interrupted by a change in the data. We did not have anything for when an animation is interrupted by a render that does not change the data which is what #6044 is about.

Related Issue

Fixes #6044

Some improvements are already in main since #6634

Screenshots (if appropriate):

This is what it looked like before #6634, same as in the original report in #6044:

strokewidth-before.mov

This is what is currently in the main branch, notice how the length suddenly jumps:

strokewidth-after.mov

After this PR:

strokewidth-after-after.mov

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or VR test, or extended an existing story or VR test to show my changes

Summary by CodeRabbit

  • Bug Fixes

    • Fixed line animations continuing from their previous position when strokeWidth or other properties change during playback, eliminating unwanted animation restarts.
  • Tests

    • Added test coverage for property changes occurring during line animation.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Walkthrough

This PR fixes an animation bug where updating React state during or after a chart animation would break the animation and restart it from the moment of state update. The fix introduces animation ID tracking and improves starting point calculation logic to be more robust to state changes and layout updates.

Changes

Cohort / File(s) Summary
Core animation fix
src/cartesian/Line.tsx
Introduces animationIdRef to track animation identity across re-renders; replaces single startingPoint with per-animation startingPointRef that persists until a new animation begins; adds guard logic to reset startingPointRef when animationId changes; consolidates previousPointsRef and longestAnimatedLengthRef updates to occur only when t > 0 and totalLength > 0, preventing initialization errors from Legend/Path layout calculations.
Storybook demonstration
storybook/stories/API/chart/LineChart.stories.tsx
Extends imports with useCallback and useState; adds local isHovered state with mouse event handlers; passes onMouseEnter, onMouseLeave to Line component; toggles strokeWidth between 8 and 4 based on hover state; sets animationDuration={5000} to demonstrate the fix with state updates during animation.
Animation continuity tests
test/cartesian/Line.animation.spec.tsx
Adds new test suite "when strokeWidth changes during the animation (issue #6044)" validating that strokeWidth changes mid-animation do not restart the animation; verifies animation progress continues from previous position; validates dasharray progression at multiple points (0.3 → 0.6); confirms progress is not reset across multiple strokeWidth toggles.

Sequence Diagram

sequenceDiagram
    actor User
    participant React as React<br/>(State Update)
    participant Line as Line Component<br/>Animation Logic
    participant Refs as Ref Tracking<br/>(animationIdRef,<br/>startingPointRef)

    Note over User,Refs: Before Fix: State change causes animation restart
    User->>React: Update state (e.g., hover)
    React->>Line: Re-render with same animationId
    Line->>Refs: startingPoint recalculated<br/>(lost progress)
    Note over Refs: Animation restarts from 0

    Note over User,Refs: After Fix: State change preserves animation progress
    User->>React: Update state (e.g., hover)
    React->>Line: Re-render with same animationId
    Line->>Refs: animationIdRef unchanged<br/>startingPointRef persists
    Note over Refs: Animation continues from current position
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Animation state management logic: Review the guard condition for animationIdRef change detection and ensure it correctly triggers reset only when animation truly changes
  • Ref persistence and timing: Verify that startingPointRef, previousPointsRef, and longestAnimatedLengthRef updates occur at the correct points in the animation lifecycle and don't introduce timing-dependent bugs
  • Edge cases: Confirm the fix handles rapid state updates, Legend height changes, and path length recalculations without visual glitches
  • Test coverage adequacy: Validate that new tests cover the specific scenarios from issue #6044 and prevent regression

Suggested reviewers

  • ckifer

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: addressing animation interruption caused by non-data-related prop changes (strokeWidth toggle in the storybook example).
Description check ✅ Passed The description includes all key template sections: problem statement, related issue link, context about prior improvements, visual evidence via screenshots, change type, and completed checklist items for tests and storybook coverage.
Linked Issues check ✅ Passed The PR directly addresses issue #6044 by fixing animation interruption from non-data-related state changes (e.g., strokeWidth updates), implementing guards to preserve animation continuity via animationIdRef and startingPointRef.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #6044: Line.tsx animation logic updates, storybook story enhancement with hover/strokeWidth test case, and targeted animation test suite additions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch line-animation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@PavelVanecek PavelVanecek requested a review from ckifer November 16, 2025 15:20
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
test/cartesian/Line.animation.spec.tsx (1)

1723-1810: Stroke-width interruption tests accurately capture issue #6044 behavior

The new suite exercises exactly the problematic scenario (mid‑animation strokeWidth changes, including multiple toggles) and asserts dasharray continuity and final rendering, aligning well with the intended fix. As an optional enhancement, you could also assert the stroke-width attribute after each click to prove the prop change took effect, but the current expectations are already sufficient to guard the regression.

storybook/stories/API/chart/LineChart.stories.tsx (1)

1-1: Interactive hover story cleanly exercises strokeWidth changes during animation

The added isHovered state plus onMouseEnter/onMouseLeave wired into <Line> give a clear, manual reproduction of mid‑animation strokeWidth changes and leverage a long animationDuration to make the effect visible. The implementation is straightforward and idiomatic. If you want to trim boilerplate, the handlers could be simple inline functions without useCallback, but that’s purely stylistic for a Storybook example.

Also applies to: 15-24, 28-34

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d92152 and 05bdd04.

📒 Files selected for processing (3)
  • src/cartesian/Line.tsx (3 hunks)
  • storybook/stories/API/chart/LineChart.stories.tsx (2 hunks)
  • test/cartesian/Line.animation.spec.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
storybook/stories/API/chart/LineChart.stories.tsx (2)
storybook/stories/API/props/EventHandlers.ts (2)
  • onMouseEnter (106-106)
  • onMouseLeave (107-107)
src/cartesian/Line.tsx (1)
  • Line (822-822)
test/cartesian/Line.animation.spec.tsx (4)
test/helper/createSelectorTestCase.tsx (1)
  • createSelectorTestCase (78-139)
test/_data.ts (1)
  • PageData (4-11)
test/helper/assertNotNull.ts (1)
  • assertNotNull (1-5)
test/helper/expectLine.ts (1)
  • expectLines (11-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build, Test, Pack
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
src/cartesian/Line.tsx (2)

393-446: Animation ID & starting point tracking correctly separate new animations from cosmetic re-renders

Using animationIdRef together with startingPointRef to derive startingPoint only when animationId changes is a solid way to:

  • continue interrupted length animations from longestAnimatedLengthRef.current, and
  • avoid restarting the length animation on non‑data re-renders (like strokeWidth/color changes, as in issue #6044).

The ref-based approach keeps this logic local to CurveWithAnimation without extra renders, and the behavior aligns with the surrounding tests.


475-510: Deferring previous-points and longest-length updates avoids Legend/layout-induced glitches

The new if (t > 0 && totalLength > 0) block that updates previousPointsRef.current and longestAnimatedLengthRef.current only after the animation has a valid totalLength neatly addresses the “path jumps after Legend/layout init” problem documented in the comments. It ensures:

  • we don’t snapshot previous points before pathRef and Legend height are settled, and
  • longestAnimatedLengthRef only tracks real path lengths, so subsequent animations start from the true furthest length.

The extra per-frame work is minimal and consistent with the existing animation loop.

@codecov
Copy link

codecov bot commented Nov 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.17%. Comparing base (7d92152) to head (05bdd04).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6641   +/-   ##
=======================================
  Coverage   94.17%   94.17%           
=======================================
  Files         494      494           
  Lines       41666    41672    +6     
  Branches     4823     4822    -1     
=======================================
+ Hits        39240    39246    +6     
  Misses       2421     2421           
  Partials        5        5           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codecov
Copy link

codecov bot commented Nov 16, 2025

Bundle Report

Changes will increase total bundle size by 2.21kB (0.08%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.13MB 1.06kB (0.09%) ⬆️
recharts/bundle-es6 979.8kB 1.04kB (0.11%) ⬆️
recharts/bundle-umd 513.67kB 109 bytes (0.02%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
cartesian/Line.js 1.06kB 25.89kB 4.28%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
cartesian/Line.js 1.04kB 24.34kB 4.45%
view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 109 bytes 513.67kB 0.02%

@ckifer
Copy link
Member

ckifer commented Nov 18, 2025

looks way better noice

@ckifer ckifer merged commit f34bda0 into main Nov 18, 2025
28 of 29 checks passed
@ckifer ckifer deleted the line-animation branch November 18, 2025 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Updating a state breaks chart animation

2 participants