Skip to content

Fix pinch zoom drifting away from the fingers on touch screens - #4

Merged
pythonicode merged 1 commit into
feat/responsive-layoutfrom
fix/pinch-zoom-anchor
Oct 14, 2026
Merged

pythonicode merged 1 commit into
feat/responsive-layoutfrom
fix/pinch-zoom-anchor

Conversation

@pythonicode

Copy link
Copy Markdown
Owner

Summary

Fixes the touch-screen pinch zoom where the point being zoomed drifted away from the fingers.

Stacked on #3 (feat/responsive-layout). Its base is that branch, so the diff shows only this fix.

Cause

  • Competing stage drag. On the Pan tool, the canvas is a Konva draggable stage. A one-finger drag could still be running when a second finger landed, and the drag and the pinch then both moved the stage.
  • Anchor maths. The pinch added the finger movement a second time, so the anchor drifted each frame. The fallback path also mixed layer and map coordinates, which was wrong for rotated maps.

Fix

  • A pinch stops any running stage drag and restores it afterwards (onGestureStart / onGestureEnd in usePinchZoom).
  • The pinch starts from the stage's live transform, not the stored viewport.
  • The anchor step is one pure function, pinchViewport, which keeps the stage point under the previous centre under the new centre. It has unit tests for zoom, pan, clamping and rotation.

Testing

  • bun run test (28 pass, 4 new), bun run lint, bun run build pass.
  • In the browser, synthetic two-finger pinches on the phone layout show zero drift at rotations 0°, 30°, 45° and 90°, on both Select and Pan tools, with and without the stage already moved. A drag running at pinch start is stopped.
  • Not verified on a real phone. Synthetic pointer events can't reproduce the real finger timing. The on-device check is the one that matters.

🤖 Generated with Claude Code

Two things made the zoom point drift away from the fingers on touch screens:

- A one-finger pan (Konva stage drag, on the Pan tool) could still be running
  when a second finger landed. The drag and the pinch then both moved the
  stage. The stage drag now stops when a pinch starts and is restored after.
- The pinch anchor added the finger movement a second time, and the fallback
  path mixed layer and map coordinates for rotated maps. The step is now a
  single pure function (pinchViewport) that keeps the stage point under the
  previous centre under the new centre, starting from what is on screen.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
analysis Ready Ready Preview Oct 14, 2026 9:16am UTC

@pythonicode
pythonicode merged commit d527e75 into feat/responsive-layout Oct 14, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — 05e7e17c Deployed Oct 14, 2026 by vercel[bot]
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