leaflet
Version:
JavaScript library for mobile-friendly interactive maps
162 lines (129 loc) • 4.52 kB
JavaScript
import {Handler} from '../../core/Handler';
import * as DomUtil from '../../dom/DomUtil';
import {Draggable} from '../../dom/Draggable';
import {toBounds} from '../../geometry/Bounds';
import {toPoint} from '../../geometry/Point';
import {requestAnimFrame, cancelAnimFrame} from '../../core/Util';
/*
* L.Handler.MarkerDrag is used internally by L.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 (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).
*/
export var MarkerDrag = Handler.extend({
initialize: function (marker) {
this._marker = marker;
},
addHooks: function () {
var 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();
DomUtil.addClass(icon, 'leaflet-marker-draggable');
},
removeHooks: function () {
this._draggable.off({
dragstart: this._onDragStart,
predrag: this._onPreDrag,
drag: this._onDrag,
dragend: this._onDragEnd
}, this).disable();
if (this._marker._icon) {
DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
}
},
moved: function () {
return this._draggable && this._draggable._moved;
},
_adjustPan: function (e) {
var 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();
var panBounds = toBounds(
bounds.min._subtract(origin).add(padding),
bounds.max._subtract(origin).subtract(padding)
);
if (!panBounds.contains(iconPos)) {
// Compute incremental movement
var movement = toPoint(
(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 = requestAnimFrame(this._adjustPan.bind(this, e));
}
},
_onDragStart: function () {
// @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.closePopup();
this._marker
.fire('movestart')
.fire('dragstart');
},
_onPreDrag: function (e) {
if (this._marker.options.autoPan) {
cancelAnimFrame(this._panRequest);
this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
}
},
_onDrag: function (e) {
var 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: function (e) {
// @event dragend: DragEndEvent
// Fired when the user stops dragging the marker.
cancelAnimFrame(this._panRequest);
// @event moveend: Event
// Fired when the marker stops moving (because of dragging).
delete this._oldLatLng;
this._marker
.fire('moveend')
.fire('dragend', e);
}
});