UNPKG

mapbox-gl

Version:
140 lines (117 loc) 3.86 kB
// @flow import { bindAll } from '../../util/util'; import type Map from '../map'; import type {MapMouseEvent, MapTouchEvent} from '../events'; import type Point from '@mapbox/point-geometry'; // maximum distance between two tap Points for them to qualify as a double-tap const maxDist = 30; /** * The `DoubleClickZoomHandler` allows the user to zoom the map at a point by * double clicking or double tapping. */ class DoubleClickZoomHandler { _map: Map; _enabled: boolean; _active: boolean; _tapped: ?TimeoutID; _tappedPoint: ?Point; /** * @private */ constructor(map: Map) { this._map = map; bindAll([ '_onDblClick', '_onZoomEnd' ], this); } /** * Returns a Boolean indicating whether the "double click to zoom" interaction is enabled. * * @returns {boolean} `true` if the "double click to zoom" interaction is enabled. */ isEnabled() { return !!this._enabled; } /** * Returns a Boolean indicating whether the "double click to zoom" interaction is active, i.e. currently being used. * * @returns {boolean} `true` if the "double click to zoom" interaction is active. */ isActive() { return !!this._active; } /** * Enables the "double click to zoom" interaction. * * @example * map.doubleClickZoom.enable(); */ enable() { if (this.isEnabled()) return; this._enabled = true; } /** * Disables the "double click to zoom" interaction. * * @example * map.doubleClickZoom.disable(); */ disable() { if (!this.isEnabled()) return; this._enabled = false; } onTouchStart(e: MapTouchEvent) { if (!this.isEnabled()) return; if (e.points.length > 1) return; if (!this._tapped) { this._tappedPoint = e.points[0]; this._tapped = setTimeout(() => { this._tapped = null; this._tappedPoint = null; }, 300); } else { const newTap = e.points[0]; const firstTap = this._tappedPoint; if (firstTap && firstTap.dist(newTap) <= maxDist) { e.originalEvent.preventDefault(); // prevent duplicate zoom on dblclick const onTouchEnd = () => { // ignore the touchend event, as it has no point we can zoom to if (this._tapped) { // make sure we are still within the timeout window this._zoom(e); // pass the original touchstart event, with the tapped point } this._map.off('touchcancel', onTouchCancel); this._resetTapped(); }; const onTouchCancel = () => { this._map.off('touchend', onTouchEnd); this._resetTapped(); }; this._map.once('touchend', onTouchEnd); this._map.once('touchcancel', onTouchCancel); } else { // touches are too far apart, don't zoom this._resetTapped(); } } } _resetTapped() { clearTimeout(this._tapped); this._tapped = null; this._tappedPoint = null; } 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( this._map.getZoom() + (e.originalEvent.shiftKey ? -1 : 1), {around: e.lngLat}, e ); } _onZoomEnd() { this._active = false; this._map.off('zoomend', this._onZoomEnd); } } export default DoubleClickZoomHandler;