import {Map} from '../Map'; import {Handler} from '../../core/Handler'; import * as DomEvent from '../../dom/DomEvent'; import * as Util from '../../core/Util'; import * as DomUtil from '../../dom/DomUtil'; import * as Browser from '../../core/Browser'; /* * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers. */ // @namespace Map // @section Interaction Options Map.mergeOptions({ // @section Touch interaction options // @option touchZoom: Boolean|String = * // Whether the map can be zoomed by touch-dragging with two fingers. If // passed `'center'`, it will zoom to the center of the view regardless of // where the touch events (fingers) were. Enabled for touch-capable web // browsers except for old Androids. touchZoom: Browser.touch && !Browser.android23, // @option bounceAtZoomLimits: Boolean = true // Set it to false if you don't want the map to zoom beyond min/max zoom // and then bounce back when pinch-zooming. bounceAtZoomLimits: true }); export var TouchZoom = Handler.extend({ addHooks: function () { DomUtil.addClass(this._map._container, 'leaflet-touch-zoom'); DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this); }, removeHooks: function () { DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom'); DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this); }, _onTouchStart: function (e) { var map = this._map; if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; } var p1 = map.mouseEventToContainerPoint(e.touches[0]), p2 = map.mouseEventToContainerPoint(e.touches[1]); this._centerPoint = map.getSize()._divideBy(2); this._startLatLng = map.containerPointToLatLng(this._centerPoint); if (map.options.touchZoom !== 'center') { this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2)); } this._startDist = p1.distanceTo(p2); this._startZoom = map.getZoom(); this._moved = false; this._zooming = true; map._stop(); DomEvent.on(document, 'touchmove', this._onTouchMove, this); DomEvent.on(document, 'touchend', this._onTouchEnd, this); DomEvent.preventDefault(e); }, _onTouchMove: function (e) { if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; } var map = this._map, p1 = map.mouseEventToContainerPoint(e.touches[0]), p2 = map.mouseEventToContainerPoint(e.touches[1]), scale = p1.distanceTo(p2) / this._startDist; this._zoom = map.getScaleZoom(scale, this._startZoom); if (!map.options.bounceAtZoomLimits && ( (this._zoom < map.getMinZoom() && scale < 1) || (this._zoom > map.getMaxZoom() && scale > 1))) { this._zoom = map._limitZoom(this._zoom); } if (map.options.touchZoom === 'center') { this._center = this._startLatLng; if (scale === 1) { return; } } else { // Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint); if (scale === 1 && delta.x === 0 && delta.y === 0) { return; } this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom); } if (!this._moved) { map._moveStart(true, false); this._moved = true; } Util.cancelAnimFrame(this._animRequest); var moveFn = Util.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}); this._animRequest = Util.requestAnimFrame(moveFn, this, true); DomEvent.preventDefault(e); }, _onTouchEnd: function () { if (!this._moved || !this._zooming) { this._zooming = false; return; } this._zooming = false; Util.cancelAnimFrame(this._animRequest); DomEvent.off(document, 'touchmove', this._onTouchMove); DomEvent.off(document, 'touchend', this._onTouchEnd); // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate. if (this._map.options.zoomAnimation) { this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap); } else { this._map._resetView(this._center, this._map._limitZoom(this._zoom)); } } }); // @section Handlers // @property touchZoom: Handler // Touch zoom handler. Map.addInitHook('addHandler', 'touchZoom', TouchZoom);