Skip to content

perf: move area ripple animation to overlay canvas - #809

Open
DinonowDev wants to merge 1 commit into
klinecharts:mainfrom
DinonowDev:fix/area-ripple-animation-cpu
Open

perf: move area ripple animation to overlay canvas#809
DinonowDev wants to merge 1 commit into
klinecharts:mainfrom
DinonowDev:fix/area-ripple-animation-cpu

Conversation

@DinonowDev

@DinonowDev DinonowDev commented Jul 24, 2026

Copy link
Copy Markdown

Summary

Test plan

  • pnpm run debug → switch candle type to Area with point.animation enabled
  • Confirm the last-price ripple still breathes visually
  • With stream off / static data, confirm CPU/paint cost no longer tracks a full main-layer repaint loop
  • Scroll / zoom while Area + animation are on → ripple stays on the last price
  • Switch back to Candle → animation stops
  • pnpm run code-lint / pnpm run type-check / pnpm run build

@DinonowDev
DinonowDev force-pushed the fix/area-ripple-animation-cpu branch from eb9db40 to 91b918c Compare July 24, 2026 05:37
Avoid full main-layer repaints at animation frame rate when
candle.area.point.animation is enabled. Fixes klinecharts#808.
@DinonowDev
DinonowDev force-pushed the fix/area-ripple-animation-cpu branch from 91b918c to 320062c Compare July 24, 2026 05:41
@NemeZZiZZ

Copy link
Copy Markdown
Contributor

Two regressions vs. main:

1. stopAnimation() drops the _animationFrameTime reset

// main
stopAnimation (): void {
  this._animationFrameTime = 0
  this._animation.cancel()
}

// this PR
stopAnimation (): void {
  this._animation.stop()
}

The reset to 0 is gone. Animation.stop() calls _doFrameCallback(this._options.duration) (src/common/Animation.ts:91), so on stop _animationFrameTime is set to animationDuration instead of 0. On the next animation start (e.g. candle → area → candle → area), the first painted ripple uses animationDuration before doFrame updates it, so the ripple briefly renders at the maximum radius instead of starting from radius.

2. The Math.min(progress, 1) clamp was removed

// main
const progress = Math.min(this._animationFrameTime / pointStyles.animationDuration, 1)
rippleRadius = pointStyles.radius + progress * (pointStyles.rippleRadius - pointStyles.radius)

// this PR (drawRipple)
rippleRadius = pointStyles.radius + this._animationFrameTime / pointStyles.animationDuration * (pointStyles.rippleRadius - pointStyles.radius)

Without the clamp, once _animationFrameTime reaches/exceeds animationDuration, the radius grows past pointStyles.rippleRadius. The current code caps progress at 1 to keep the ripple within [radius, rippleRadius].

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.

[Performance] Optimize high CPU usage when candle.area.point.animation is enabled (Suggest separating ripple animation to overlay layer)

2 participants