fix: rAF-coalesce canvas pan for smoothness at low zoom#45
Merged
trmquang93 merged 1 commit intomainfrom Apr 27, 2026
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes backlog 8.3 — canvas pan feels janky at low zoom (~20%) on flows with many screens.
setPaninto 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.panStartinto a ref so the rAF callback never reads stale closures across renders.mouseupand on hook unmount to avoid leaks and "setState on unmounted component" warnings.Why this works: at low zoom more screens are visible, so each React render is heavier. Synchronous
setPanpermousemovesaturates 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), sopanis 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
#landing— no console warnings.npm run lint,npm run build,npm testall pass.