diff --git a/src/ui/bind_handlers.js b/src/ui/bind_handlers.js index 2b5d1a16cb1..7db2f41645e 100644 --- a/src/ui/bind_handlers.js +++ b/src/ui/bind_handlers.js @@ -18,7 +18,6 @@ module.exports = function bindHandlers(map: Map, options: {}) { const el = map.getCanvasContainer(); let contextMenuEvent = null; let mouseDown = false; - let tapped = null; for (const name in handlers) { (map: any)[name] = new handlers[name](map, options); @@ -105,19 +104,9 @@ module.exports = function bindHandlers(map: Map, options: {}) { map.stop(); - if (!e.touches || e.touches.length > 1) return; - - if (!tapped) { - tapped = setTimeout(onTouchTimeout, 300); - - } else { - clearTimeout(tapped); - tapped = null; - fireMouseEvent('dblclick', (e: any)); - } - map.dragPan.onDown(e); map.touchZoomRotate.onStart(e); + map.doubleClickZoom.onTouchStart(mapEvent); } function onTouchMove(e: TouchEvent) { @@ -132,17 +121,19 @@ module.exports = function bindHandlers(map: Map, options: {}) { fireTouchEvent('touchcancel', e); } - function onTouchTimeout() { - tapped = null; - } - function onClick(e: MouseEvent) { fireMouseEvent('click', e); } function onDblClick(e: MouseEvent) { - fireMouseEvent('dblclick', e); - e.preventDefault(); + const mapEvent = new MapMouseEvent('dblclick', map, e); + map.fire(mapEvent); + + if (mapEvent.defaultPrevented) { + return; + } + + map.doubleClickZoom.onDblClick(mapEvent); } function onContextMenu(e: MouseEvent) { diff --git a/src/ui/events.js b/src/ui/events.js index cc62f8b114d..b3b1793117e 100644 --- a/src/ui/events.js +++ b/src/ui/events.js @@ -57,6 +57,8 @@ class MapMouseEvent extends Event { * * On `mousedown` events, the behavior of {@link DragPanHandler} * * On `mousedown` events, the behavior of {@link DragRotateHandler} * * On `mousedown` events, the behavior of {@link BoxZoomHandler} + * * On `dblclick` events, the behavior of {@link DoubleClickZoomHandler} + * */ preventDefault() { this._defaultPrevented = true; @@ -134,6 +136,7 @@ class MapTouchEvent extends Event { * * * On `touchstart` events, the behavior of {@link DragPanHandler} * * On `touchstart` events, the behavior of {@link TouchZoomRotateHandler} + * */ preventDefault() { this._defaultPrevented = true; diff --git a/src/ui/handler/dblclick_zoom.js b/src/ui/handler/dblclick_zoom.js index 6973aa94862..39fbad307c6 100644 --- a/src/ui/handler/dblclick_zoom.js +++ b/src/ui/handler/dblclick_zoom.js @@ -3,15 +3,17 @@ const util = require('../../util/util'); import type Map from '../map'; +import type {MapMouseEvent, MapTouchEvent} from '../events'; /** * The `DoubleClickZoomHandler` allows the user to zoom the map at a point by - * double clicking. + * double clicking or double tapping. */ class DoubleClickZoomHandler { _map: Map; _enabled: boolean; _active: boolean; + _tapped: ?number; /** * @private @@ -51,7 +53,6 @@ class DoubleClickZoomHandler { */ enable() { if (this.isEnabled()) return; - this._map.on('dblclick', this._onDblClick); this._enabled = true; } @@ -63,11 +64,29 @@ class DoubleClickZoomHandler { */ disable() { if (!this.isEnabled()) return; - this._map.off('dblclick', this._onDblClick); this._enabled = false; } - _onDblClick(e: any) { + onTouchStart(e: MapTouchEvent) { + if (!this.isEnabled()) return; + if (e.points.length > 1) return; + + if (!this._tapped) { + this._tapped = setTimeout(() => { this._tapped = null; }, 300); + } else { + clearTimeout(this._tapped); + this._tapped = null; + this._zoom(e); + } + } + + onDblClick(e: MapMouseEvent) { + if (!this.isEnabled()) return; + e.originalEvent.preventDefault(); + this._zoom(e); + } + + _zoom(e: MapMouseEvent | MapTouchEvent) { this._active = true; this._map.on('zoomend', this._onZoomEnd); this._map.zoomTo( diff --git a/test/unit/ui/handler/dblclick_zoom.test.js b/test/unit/ui/handler/dblclick_zoom.test.js new file mode 100644 index 00000000000..999bbe1d132 --- /dev/null +++ b/test/unit/ui/handler/dblclick_zoom.test.js @@ -0,0 +1,27 @@ +'use strict'; + +const test = require('mapbox-gl-js-test').test; +const window = require('../../../../src/util/window'); +const Map = require('../../../../src/ui/map'); +const DOM = require('../../../../src/util/dom'); +const simulate = require('mapbox-gl-js-test/simulate_interaction'); + +function createMap() { + return new Map({ container: DOM.create('div', '', window.document.body) }); +} + +test('DoubleClickZoomHandler does not zoom if preventDefault is called on the dblclick event', (t) => { + const map = createMap(); + + map.on('dblclick', e => e.preventDefault()); + + const zoom = t.spy(); + map.on('zoom', zoom); + + simulate.dblclick(map.getCanvas()); + + t.equal(zoom.callCount, 0); + + map.remove(); + t.end(); +});