UNPKG

maplair

Version:

JavaScript library for mobile-friendly interactive maps

133 lines (132 loc) • 5.3 kB
import { Point } from "../../geometry/Point.js"; import { Handler } from "../../core/Handler.js"; import { Draggable } from "../../dom/Draggable.js"; import { Bounds } from "../../geometry/Bounds.js"; import { LatLngBounds } from "../../geo/LatLngBounds.js"; //#region src/map/handler/DragHandler.js var DragHandler = class DragHandler extends Handler { constructor(...args) { super(...args); this.callInitHooks(DragHandler); } addHooks() { if (!this._draggable) { const map = this._map; this._draggable = new Draggable(map._mapPane, map._container); this._draggable.on({ dragstart: this._onDragStart, drag: this._onDrag, dragend: this._onDragEnd }, this); this._draggable.on("predrag", this._onPreDragLimit, this); if (map.options.worldCopyJump) { this._draggable.on("predrag", this._onPreDragWrap, this); map.on("zoomend", this._onZoomEnd, this); map.whenReady(this._onZoomEnd, this); } } this._map._container.classList.add("maplair-grab", "maplair-touch-drag"); this._draggable.enable(); this._positions = []; this._times = []; } removeHooks() { this._map._container.classList.remove("maplair-grab", "maplair-touch-drag"); this._draggable.disable(); } moved() { return this._draggable?._moved; } moving() { return this._draggable?._moving; } _onDragStart() { const map = this._map; map._stop(); if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) { const bounds = new LatLngBounds(this._map.options.maxBounds); this._offsetLimit = new Bounds(this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1), this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1).add(this._map.getSize())); this._viscosity = Math.min(1, Math.max(0, this._map.options.maxBoundsViscosity)); } else this._offsetLimit = null; map.fire("movestart").fire("dragstart"); if (map.options.inertia) { this._positions = []; this._times = []; } } _onDrag(e) { if (this._map.options.inertia) { const time = this._lastTime = Date.now(), pos = this._lastPos = this._draggable._absPos || this._draggable._newPos; this._positions.push(pos); this._times.push(time); this._prunePositions(time); } this._map.fire("move", e).fire("drag", e); } _prunePositions(time) { while (this._positions.length > 1 && time - this._times[0] > 50) { this._positions.shift(); this._times.shift(); } } _onZoomEnd() { const pxCenter = this._map.getSize().divideBy(2), pxWorldCenter = this._map.latLngToLayerPoint([0, 0]); this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x; this._worldWidth = this._map.getPixelWorldBounds().getSize().x; } _viscousLimit(value, threshold) { return value - (value - threshold) * this._viscosity; } _onPreDragLimit() { if (!this._viscosity || !this._offsetLimit) return; const offset = this._draggable._newPos.subtract(this._draggable._startPos); const limit = this._offsetLimit; if (offset.x < limit.min.x) offset.x = this._viscousLimit(offset.x, limit.min.x); if (offset.y < limit.min.y) offset.y = this._viscousLimit(offset.y, limit.min.y); if (offset.x > limit.max.x) offset.x = this._viscousLimit(offset.x, limit.max.x); if (offset.y > limit.max.y) offset.y = this._viscousLimit(offset.y, limit.max.y); this._draggable._newPos = this._draggable._startPos.add(offset); } _onPreDragWrap() { const worldWidth = this._worldWidth, halfWidth = Math.round(worldWidth / 2), dx = this._initialWorldOffset, x = this._draggable._newPos.x, newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx, newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx, newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2; this._draggable._absPos = new Point(this._draggable._newPos); this._draggable._newPos.x = newX; } _onDragEnd(e) { const map = this._map, options = map.options, noInertia = !options.inertia || e.noInertia || this._times.length < 2; map.fire("dragend", e); if (noInertia) map.fire("moveend"); else { this._prunePositions(Date.now()); const direction = this._lastPos.subtract(this._positions[0]), duration = (this._lastTime - this._times[0]) / 1e3, ease = options.easeLinearity, speedVector = direction.multiplyBy(ease / duration), speed = speedVector.distanceTo([0, 0]), limitedSpeed = Math.min(options.inertiaMaxSpeed, speed), limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed), decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease); let offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round(); if (!offset.x && !offset.y) map.fire("moveend"); else { offset = map._limitOffset(offset, map.options.maxBounds); requestAnimationFrame(() => { map.panBy(offset, { duration: decelerationDuration, easeLinearity: ease, noMoveStart: true, animate: true }); }); } } } static register(MaplairMap) { MaplairMap.mergeOptions({ dragging: true, inertia: true, inertiaDeceleration: 3400, inertiaMaxSpeed: Infinity, easeLinearity: .2, worldCopyJump: false, maxBoundsViscosity: 0 }); MaplairMap.addInitHook("addHandler", "dragging", DragHandler); } }; //#endregion export { DragHandler }; //# sourceMappingURL=DragHandler.js.map