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
Member

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
Member 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@Pessimistress @chrisgervang thinking about this a little more.

The current list of mjolnir gestures feel complete. However, I agree this gesture is reusable, a new recognizer would simplify the controller.

I am propsing a new compound gestures section in mjolnir docs where this will be the first addition, and I can use thor.gl as a testing ground for new gestures off the touch surface. The gestures will work the same, just present them in the docs separately?

I can open a heavier RFC consolidating my thor interactivity ideas and start with this doubleTapDrag compound-gesture, but I wanted to use the existing thread here as a starting point of the idea.

Lmk

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.

This list seems like either incomplete or a different list from what I was expecting to see in the docs (admittedly, this is the first time I've looked at these docs)

The source differentiates between basic and gesture recognizers

https://github.com/visgl/mjolnir.js/blob/28609e190283cb767aee4fca4eef0a94fd163dac/src/event-manager.ts#L90

I expected to see "double click" and similar in the docs, but they don't seem to be included.

"double click drag" seems like another gesture recognizer to join the ranks of "pan drag" - so in that sense, yeah, I think I'm agreeing with you that there needs to be some new doc pages for all of the gesture recognizers, with "double click drag" among them.

Does that help give some direction?

Re: Thor, I have no strong opinion on where you'd like to test - I'd say for now the best path forward for deck 9.4 would be to refactor mjolnir so that we can simplify deck's controller class. The specific hope I have is that we can remove the short circuits in the pan recognizer callbacks on the deck level

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