1 | import {Map} from '../Map';
|
2 | import {Handler} from '../../core/Handler';
|
3 | import {Draggable} from '../../dom/Draggable';
|
4 | import * as Util from '../../core/Util';
|
5 | import * as DomUtil from '../../dom/DomUtil';
|
6 | import {toLatLngBounds as latLngBounds} from '../../geo/LatLngBounds';
|
7 | import {toBounds} from '../../geometry/Bounds';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | Map.mergeOptions({
|
16 |
|
17 |
|
18 | dragging: true,
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | inertia: true,
|
27 |
|
28 |
|
29 |
|
30 | inertiaDeceleration: 3400,
|
31 |
|
32 |
|
33 |
|
34 | inertiaMaxSpeed: Infinity,
|
35 |
|
36 |
|
37 | easeLinearity: 0.2,
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | worldCopyJump: false,
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | maxBoundsViscosity: 0.0
|
53 | });
|
54 |
|
55 | export var Drag = Handler.extend({
|
56 | addHooks: function () {
|
57 | if (!this._draggable) {
|
58 | var map = this._map;
|
59 |
|
60 | this._draggable = new Draggable(map._mapPane, map._container);
|
61 |
|
62 | this._draggable.on({
|
63 | dragstart: this._onDragStart,
|
64 | drag: this._onDrag,
|
65 | dragend: this._onDragEnd
|
66 | }, this);
|
67 |
|
68 | this._draggable.on('predrag', this._onPreDragLimit, this);
|
69 | if (map.options.worldCopyJump) {
|
70 | this._draggable.on('predrag', this._onPreDragWrap, this);
|
71 | map.on('zoomend', this._onZoomEnd, this);
|
72 |
|
73 | map.whenReady(this._onZoomEnd, this);
|
74 | }
|
75 | }
|
76 | DomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
|
77 | this._draggable.enable();
|
78 | this._positions = [];
|
79 | this._times = [];
|
80 | },
|
81 |
|
82 | removeHooks: function () {
|
83 | DomUtil.removeClass(this._map._container, 'leaflet-grab');
|
84 | DomUtil.removeClass(this._map._container, 'leaflet-touch-drag');
|
85 | this._draggable.disable();
|
86 | },
|
87 |
|
88 | moved: function () {
|
89 | return this._draggable && this._draggable._moved;
|
90 | },
|
91 |
|
92 | moving: function () {
|
93 | return this._draggable && this._draggable._moving;
|
94 | },
|
95 |
|
96 | _onDragStart: function () {
|
97 | var map = this._map;
|
98 |
|
99 | map._stop();
|
100 | if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
|
101 | var bounds = latLngBounds(this._map.options.maxBounds);
|
102 |
|
103 | this._offsetLimit = toBounds(
|
104 | this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
|
105 | this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
|
106 | .add(this._map.getSize()));
|
107 |
|
108 | this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
|
109 | } else {
|
110 | this._offsetLimit = null;
|
111 | }
|
112 |
|
113 | map
|
114 | .fire('movestart')
|
115 | .fire('dragstart');
|
116 |
|
117 | if (map.options.inertia) {
|
118 | this._positions = [];
|
119 | this._times = [];
|
120 | }
|
121 | },
|
122 |
|
123 | _onDrag: function (e) {
|
124 | if (this._map.options.inertia) {
|
125 | var time = this._lastTime = +new Date(),
|
126 | pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
|
127 |
|
128 | this._positions.push(pos);
|
129 | this._times.push(time);
|
130 |
|
131 | this._prunePositions(time);
|
132 | }
|
133 |
|
134 | this._map
|
135 | .fire('move', e)
|
136 | .fire('drag', e);
|
137 | },
|
138 |
|
139 | _prunePositions: function (time) {
|
140 | while (this._positions.length > 1 && time - this._times[0] > 50) {
|
141 | this._positions.shift();
|
142 | this._times.shift();
|
143 | }
|
144 | },
|
145 |
|
146 | _onZoomEnd: function () {
|
147 | var pxCenter = this._map.getSize().divideBy(2),
|
148 | pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
|
149 |
|
150 | this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
|
151 | this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
|
152 | },
|
153 |
|
154 | _viscousLimit: function (value, threshold) {
|
155 | return value - (value - threshold) * this._viscosity;
|
156 | },
|
157 |
|
158 | _onPreDragLimit: function () {
|
159 | if (!this._viscosity || !this._offsetLimit) { return; }
|
160 |
|
161 | var offset = this._draggable._newPos.subtract(this._draggable._startPos);
|
162 |
|
163 | var limit = this._offsetLimit;
|
164 | if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
|
165 | if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
|
166 | if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
|
167 | if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
|
168 |
|
169 | this._draggable._newPos = this._draggable._startPos.add(offset);
|
170 | },
|
171 |
|
172 | _onPreDragWrap: function () {
|
173 |
|
174 | var worldWidth = this._worldWidth,
|
175 | halfWidth = Math.round(worldWidth / 2),
|
176 | dx = this._initialWorldOffset,
|
177 | x = this._draggable._newPos.x,
|
178 | newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
|
179 | newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
|
180 | newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
|
181 |
|
182 | this._draggable._absPos = this._draggable._newPos.clone();
|
183 | this._draggable._newPos.x = newX;
|
184 | },
|
185 |
|
186 | _onDragEnd: function (e) {
|
187 | var map = this._map,
|
188 | options = map.options,
|
189 |
|
190 | noInertia = !options.inertia || e.noInertia || this._times.length < 2;
|
191 |
|
192 | map.fire('dragend', e);
|
193 |
|
194 | if (noInertia) {
|
195 | map.fire('moveend');
|
196 |
|
197 | } else {
|
198 | this._prunePositions(+new Date());
|
199 |
|
200 | var direction = this._lastPos.subtract(this._positions[0]),
|
201 | duration = (this._lastTime - this._times[0]) / 1000,
|
202 | ease = options.easeLinearity,
|
203 |
|
204 | speedVector = direction.multiplyBy(ease / duration),
|
205 | speed = speedVector.distanceTo([0, 0]),
|
206 |
|
207 | limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
|
208 | limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
|
209 |
|
210 | decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
|
211 | offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
|
212 |
|
213 | if (!offset.x && !offset.y) {
|
214 | map.fire('moveend');
|
215 |
|
216 | } else {
|
217 | offset = map._limitOffset(offset, map.options.maxBounds);
|
218 |
|
219 | Util.requestAnimFrame(function () {
|
220 | map.panBy(offset, {
|
221 | duration: decelerationDuration,
|
222 | easeLinearity: ease,
|
223 | noMoveStart: true,
|
224 | animate: true
|
225 | });
|
226 | });
|
227 | }
|
228 | }
|
229 | }
|
230 | });
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | Map.addInitHook('addHandler', 'dragging', Drag);
|