Skip to content

fix: rAF-coalesce canvas pan for smoothness at low zoom#45

Merged
trmquang93 merged 1 commit intomainfrom
fix/canvas-pan-smoothness
Apr 27, 2026
Merged

fix: rAF-coalesce canvas pan for smoothness at low zoom#45
trmquang93 merged 1 commit intomainfrom
fix/canvas-pan-smoothness

Conversation

@trmquang93
Copy link
Copy Markdown
Collaborator

Summary

Fixes backlog 8.3 — canvas pan feels janky at low zoom (~20%) on flows with many screens.

  • Coalesce setPan into one call per animation frame for both space-drag pan (mousemove) and trackpad wheel pan. The latest delta wins; intermediate events are dropped, capping update rate to the display refresh rate.
  • Mirror panStart into a ref so the rAF callback never reads stale closures across renders.
  • Cancel pending rAFs on mouseup and on hook unmount to avoid leaks and "setState on unmounted component" warnings.
  • Drag, multi-drag, and pinch-zoom (cmd/ctrl + wheel) branches are untouched. Public hook signature unchanged.

Why this works: at low zoom more screens are visible, so each React render is heavier. Synchronous setPan per mousemove saturates the commit pipeline and frames stutter. rAF coalescing matches update rate to vsync and eliminates the back-pressure.

The pan delta math is in screen-space (CSS transform is translate(pan) scale(zoom), so pan is post-scale); no zoom-divide needed for cursor tracking. See plan §"Math Verification" for detail.

Scope is intentionally minimal (single file, src/hooks/useCanvas.js). Memoization, viewport culling, and connection-geometry decoupling are deferred to a follow-up perf epic.

Test plan

  • Smoothness at 20% zoom — open a flow with 20+ screens, hold space and drag in a smooth circle. Motion tracks the cursor with no perceptible stutter.
  • No regression at 100% zoom — frame-perfect tracking.
  • Mid-pan cursor reversal — direction changes are responsive.
  • Pan-tool mode (no space held) — same smoothness.
  • Trackpad two-finger pan at 20% zoom — smooth.
  • Pinch-zoom (cmd+scroll) — zoom focus point still correct.
  • Mid-pan release — no residual canvas drift after mouseup.
  • Single-screen drag at 20% zoom — screen still placed exactly under cursor.
  • Multi-select drag at 20% zoom — still works.
  • Navigate away mid-pan to #landing — no console warnings.
  • DevTools Performance — ≤1 React commit per frame during sustained pan.
  • npm run lint, npm run build, npm test all pass.

Pan and wheel-pan now coalesce setPan into a single call per animation
frame, capping update rate to the display refresh rate and eliminating
the back-pressure that produced stutter on heavy flows at low zoom
(20% with 20+ screens).

- Mirror panStart into a ref so the rAF callback reads the latest start
  position without stale-closure issues.
- Cancel pending rAFs on mouseup and on hook unmount.
- Drag, multi-drag, and pinch-zoom branches untouched.

Backlog 8.3.
@trmquang93 trmquang93 merged commit 9c94a60 into main Apr 27, 2026
1 check passed
@trmquang93 trmquang93 deleted the fix/canvas-pan-smoothness branch April 27, 2026 16:16
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.

1 participant