UNPKG

leaflet

Version:

JavaScript library for mobile-friendly interactive maps

159 lines (126 loc) 4.23 kB
import {Handler} from '../../core/Handler.js'; import * as DomUtil from '../../dom/DomUtil.js'; import {Draggable} from '../../dom/Draggable.js'; import {Bounds} from '../../geometry/Bounds.js'; import {Point} from '../../geometry/Point.js'; /* * Handler.MarkerDrag is used internally by Marker to make the markers draggable. */ /* @namespace Marker * @section Interaction handlers * * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example: * * ```js * marker.dragging.disable(); * ``` * * @property dragging: Handler * Marker dragging handler. Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)). */ export class MarkerDrag extends Handler { initialize(marker) { this._marker = marker; } addHooks() { const icon = this._marker._icon; if (!this._draggable) { this._draggable = new Draggable(icon, icon, true); } this._draggable.on({ dragstart: this._onDragStart, predrag: this._onPreDrag, drag: this._onDrag, dragend: this._onDragEnd }, this).enable(); icon.classList.add('leaflet-marker-draggable'); } removeHooks() { this._draggable.off({ dragstart: this._onDragStart, predrag: this._onPreDrag, drag: this._onDrag, dragend: this._onDragEnd }, this).disable(); this._marker._icon?.classList.remove('leaflet-marker-draggable'); } moved() { return this._draggable?._moved; } _adjustPan(e) { const marker = this._marker, map = marker._map, speed = this._marker.options.autoPanSpeed, padding = this._marker.options.autoPanPadding, iconPos = DomUtil.getPosition(marker._icon), bounds = map.getPixelBounds(), origin = map.getPixelOrigin(); const panBounds = new Bounds( bounds.min._subtract(origin).add(padding), bounds.max._subtract(origin).subtract(padding) ); if (!panBounds.contains(iconPos)) { // Compute incremental movement const movement = new Point( (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) - (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x), (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) - (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y) ).multiplyBy(speed); map.panBy(movement, {animate: false}); this._draggable._newPos._add(movement); this._draggable._startPos._add(movement); DomUtil.setPosition(marker._icon, this._draggable._newPos); this._onDrag(e); this._panRequest = requestAnimationFrame(this._adjustPan.bind(this, e)); } } _onDragStart() { // @section Dragging events // @event dragstart: Event // Fired when the user starts dragging the marker. // @event movestart: Event // Fired when the marker starts moving (because of dragging). this._oldLatLng = this._marker.getLatLng(); // When using ES6 imports it could not be set when `Popup` was not imported as well this._marker.closePopup?.(); this._marker .fire('movestart') .fire('dragstart'); } _onPreDrag(e) { if (this._marker.options.autoPan) { cancelAnimationFrame(this._panRequest); this._panRequest = requestAnimationFrame(this._adjustPan.bind(this, e)); } } _onDrag(e) { const marker = this._marker, shadow = marker._shadow, iconPos = DomUtil.getPosition(marker._icon), latlng = marker._map.layerPointToLatLng(iconPos); // update shadow position if (shadow) { DomUtil.setPosition(shadow, iconPos); } marker._latlng = latlng; e.latlng = latlng; e.oldLatLng = this._oldLatLng; // @event drag: Event // Fired repeatedly while the user drags the marker. marker .fire('move', e) .fire('drag', e); } _onDragEnd(e) { // @event dragend: DragEndEvent // Fired when the user stops dragging the marker. cancelAnimationFrame(this._panRequest); // @event moveend: Event // Fired when the marker stops moving (because of dragging). delete this._oldLatLng; this._marker .fire('moveend') .fire('dragend', e); } }