Skip to content

feat(core): doubleClickDragZoom gesture#10327

Merged
chrisgervang merged 8 commits into
visgl:masterfrom
NEW-HEAT:codex/touch-double-tap-zoom
Jun 11, 2026
Merged

feat(core): doubleClickDragZoom gesture#10327
chrisgervang merged 8 commits into
visgl:masterfrom
NEW-HEAT:codex/touch-double-tap-zoom

Conversation

@charlieforward9

@charlieforward9 charlieforward9 commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a Google/Apple Maps-style one-finger double-click/tap-and-drag zoom gesture for touch users, exposed as its own controller option:

controller: {
  doubleClickDragZoom: true
}

The gesture lets users:

  1. Tap once.
  2. Tap again and hold.
  3. Drag vertically with the same finger to zoom continuously.

This gives mobile users a precise one-handed zoom path without requiring pinch zoom, on-screen controls, or desktop double-click zoom behavior.

Comparison Videos

Apple Maps Reference

trim.DD19513B-5915-4050-8865-99E128A9E9A0.MOV

deck.gl GlobeController Demo

trim.31AA42AB-9ACB-4104-8629-9C7557592B20.MOV

The deck.gl demo uses the same one-finger sequence against a GlobeView controller path, matching the mobile map interaction model users already expect.

Why

One-handed mobile map navigation currently has a gap: users can pan with one finger, but controlled zoom generally requires either a second finger or visible zoom controls. The double-click/tap-and-drag gesture is a standard mobile map pattern and lets users zoom in or out while keeping their thumb on the map.

While validating on iOS Safari, repeated touch gestures could also trigger page-level selection/callout affordances over the canvas. This PR keeps the gesture path inside deck.gl while leaving browser UI guard CSS to app developers, with reusable guidance documented for apps using deck.gl controllers.

What Changed

  • Adds the doubleClickDragZoom controller option, defaulting to true.
  • Adds a DOUBLE_CLICK_DRAG pointer-event gesture path through pointer down, move, up, and cancel handling.
  • Promotes a stored tap into a one-finger zoom session when the second tap lands within the timing and distance thresholds.
  • Maps vertical drag distance to zoom using DOUBLE_CLICK_DRAG_PIXELS_PER_ZOOM = 120.
  • Suppresses the trailing dblclick after the drag gesture so release does not apply a second zoom.
  • Short-circuits pan handling while a double-click-drag zoom session is active.
  • Hardens the website GlobeView example with app-owned mobile touch CSS and canvas-scoped browser UI event guards.
  • Documents doubleClickDragZoom in the Controller API.
  • Moves the mobile browser touch UI docs to developer-guide/tips-and-tricks.md#optimization-for-mobile and links to that guidance from controller.md.
  • Leaves default Deck canvas styling unchanged so apps opt into browser UI guards themselves.

Behavior Notes

  • doubleClickDragZoom controls this gesture independently from doubleClickZoom and touchZoom.
  • Works when doubleClickZoom: false, because the gesture is continuous pointer-driven zoom rather than double-click zoom.
  • Works when pinch touchZoom is disabled, because this is a distinct one-finger gesture.
  • Keeps desktop mouse and keyboard behavior unchanged.
  • Uses the shared controller path, so controllers can opt into the same gesture behavior.
  • Avoids app-level pointer propagation changes, preserving the existing deck.gl event manager and context-menu behavior.
  • Keeps the local satellite GlobeView comparison demo out of the PR; only reusable core behavior plus docs/example hardening is included.

Validation

  • Added MapController supports double-click drag zoom when double click and touch zoom are disabled, covering the full pointer sequence and release behavior.
  • Added MapController disables double-click drag zoom, covering the new controller option gate.
  • Focused local test:
yarn test -- test/modules/core/controllers/controllers.spec.ts test/modules/core/lib/deck.spec.ts
  • Commit hook validation ran repository lint/prettier checks and node smoke tests. Existing lint warnings were reported, with no errors.
  • git diff --check
  • Local Docusaurus dev server compiled and served the docs at http://127.0.0.1:3000/ with placeholder map API env vars; only dependency source-map warnings from arc were reported.
  • Local mobile demo validation was run against a satellite GlobeView setup to compare the gesture against Apple Maps-style interaction. That demo was intentionally kept out of this PR to avoid adding example bloat.

Merge Notes

This is intentionally scoped to the reusable one-finger double-click/tap-and-drag zoom gesture, the dedicated controller option, and app-owned docs/example interaction hardening discovered during mobile validation. GlobeView pointer anchoring/parity work is handled separately in #10307, and the local comparison demo combined the two branches only for manual mobile validation.

Adds the Google Maps-style touch zoom: a quick tap followed by a
press-and-drag with the same finger zooms in/out continuously without
ever using the second finger. Useful for one-handed touch interaction.

- New DOUBLE_TAP_DRAG event channel routed through pointerdown/move/up.
- Tap timing constants tuned for snap response without false triggers.
- _onPointerDown promotes a stored single tap to a one-finger zoom
  session when the second tap lands close enough in time and space.
- _onPointerMove drives controllerState.zoom relative to vertical drag;
  _onPointerUp finalizes and suppresses the trailing dblclick.
- pan handlers short-circuit while a one-finger zoom is active.
@charlieforward9 charlieforward9 force-pushed the codex/touch-double-tap-zoom branch from 7cea955 to b1e6a61 Compare May 22, 2026 21:49
@coveralls

coveralls commented May 22, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 83.386%. remained the same — NEW-HEAT:codex/touch-double-tap-zoom into visgl:master

Comment thread modules/core/src/controllers/controller.ts Outdated
Comment thread modules/core/src/controllers/controller.ts Outdated
Comment thread modules/core/src/controllers/controller.ts Outdated
Comment thread modules/core/src/lib/deck.ts Outdated
@chrisgervang chrisgervang changed the title feat(core): one-finger double-tap-drag zoom gesture feat(core): one-finger double-click-drag zoom gesture Jun 10, 2026
@charlieforward9 charlieforward9 changed the title feat(core): one-finger double-click-drag zoom gesture feat(core): doubleClickDragZoom gesture Jun 10, 2026
@charlieforward9 charlieforward9 self-assigned this Jun 10, 2026
Comment on lines +273 to +279
case 'pointerdown':
return this._onDoubleClickDragPointerDown(event);
case 'pointermove':
return this._onDoubleClickDragPointerMove(event);
case 'pointerup':
case 'pointercancel':
return this._onDoubleClickDragPointerUp(event);

@chrisgervang chrisgervang Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For follow up, does mjoinir need a 'dblclickmove'? There isn't a second up pointer event so I'm not sure

@chrisgervang chrisgervang merged commit 1518c7f into visgl:master Jun 11, 2026
5 checks passed
PINCH: ['pinchstart', 'pinchmove', 'pinchend'],
MULTI_PAN: ['multipanstart', 'multipanmove', 'multipanend'],
DOUBLE_CLICK: ['dblclick'],
DOUBLE_CLICK_DRAG: ['pointerdown', 'pointermove', 'pointerup', 'pointercancel'],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Pessimistress suggested a good refactor would be to implement a new recognizer in mjolnir for this. It'd simplify the controller compared to using raw pointer events.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Id like to gain some perspective on how platforms like  OS organize their gesture recognition across mobile, mouse, and Vision Pro, I strongly agree gesture recognition should be managed within mjolnir.

@chrisgervang chrisgervang mentioned this pull request Jun 11, 2026
55 tasks
@chrisgervang chrisgervang added this to the v9.4 milestone Jun 11, 2026
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.

3 participants