[WIP] Refactor gesture handling & improve gesture support on mobile #9223
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.
This PR refactors the input gesture handling architecture to reduce bugs & improve extensibility. It also adds support for touch gestures to pan, zoom, rotate, and pitch the map.
This is work in progress; API(s) & gesture handling behavior is still subject to change.
Overview
Previously, individual handlers representing arguably-related groups of interactions (e.g.
TouchZoomRotateHandler
) managed both gesture detection and the resulting map animation simultaneously, which led to several problems including:The new architecture aims to better separate concerns between gesture detection and the animation of the map in response to these gestures. Furthermore, we now have a mechanism for managing conflicts between different gesture handlers, and controlling their hierarchy and mutual exclusivity.
HandlerManager
The module
src/ui/handler_manager.js
defines aHandlerManager
object, accessed through the map asmap.handlers
. The manager:Handler
objects (see below), with builtin handlers attached by defaultmap.handlers.touchPitch
.add()
and.remove()
methods to allow overriding builtin handlers and/or attaching custom handlers extending theHandler
class.list()
methodtouchstart
,mouseup
), allows enabled handlers to process these events, and receives "recommendations" for how to update the map from applicable handlers (see below)movestart
,zoomstart
) as neededEventually it will:
interactive
option(s) and enable/disable handlers accordinglymap.handlers.disableTouch()
Handler
classesHandler objects are responsible for processing relevant input events by calculating desired updates to the map & returning information describing those updates to the manager.
The
Handler
base class (src/ui/handler/handler.js
) provides methods common to all handlers, e.g..enable()
and.disable()
.Custom handlers can be implemented by extending the base
Handler
class and implementing event-processing methods for any relevant input events (e.g..mouseup(e)
,.keydown(e)
). Handlers are ideally small and single-purpose, focused on only one type of interaction.Upon detecting an input event (e.g.
touchmove
), the manager looks for a method with the same name on any enabled handlers (e.g.touchZoom.touchmove(e)
), calling each such method with the original input event.Handler event-processing methods may return an object specifying which map updates should be applied (e.g.
transform: { zoomDelta: -1 }
, and which output events should be fired (e.g.events: [ 'zoomstart', 'zoom']
).If a handler's method for a detected input event (e.g.
.touchmove(e)
) returns such an object to the manager, the manager may apply the specified update(s) to the map and fire the specified event(s), after all handlers have had a chance to process the input event and any conflicts have been resolved.See the
TouchPanHandler
,TouchZoomHandler
,TouchRotateHandler
, andTouchPitchHandler
classes insrc/ui/handler/touch.js
for examples.Changes to current API
Under the new architecture, the map's former mixed-concern handlers (e.g.
map.touchZoomRotate
) no longer exist as such. The old handler classes are either replaced or ported to the new architecture, and the oldbind_handlers
module has been removed in favor of the high-level control provided by theHandlerManager
.To avoid breaking changes, the current API can be shimmed to map existing properties/methods to the new handler architecture (e.g.
map.touchZoomRotate.disableRotation()
mapped tomap.touchRotate.disable()
).Next steps
mapboxgl-touch-zoom-rotate
) from managermap.handlers.disableRotation()
etc)Launch Checklist