@wemap/providers 3.1.2 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug/Common.css +172 -0
- package/debug/MainComponent.jsx +64 -0
- package/debug/components/AbsolutePositionComponent.jsx +1 -1
- package/debug/components/GnssWifiComponent.jsx +1 -1
- package/debug/components/StartStopComponent.jsx +5 -3
- package/debug/components/Utils.js +4 -2
- package/debug/details/DetailsAttitudeComponent.jsx +121 -0
- package/debug/details/DetailsComponent.jsx +42 -0
- package/debug/details/DetailsPositionComponent.jsx +127 -0
- package/debug/details/ItineraryComponent.jsx +323 -0
- package/debug/index.js +28 -0
- package/debug/map/MapComponent.jsx +84 -0
- package/debug/map/MapHandler.js +53 -0
- package/debug/map/MapboxHelper.js +50 -0
- package/debug/map/helpers/ItineraryMapHandler.js +284 -0
- package/debug/map/helpers/MapClickHandler.js +119 -0
- package/debug/map/helpers/UserOnMapHandler.js +489 -0
- package/debug/stores/ItineraryStore.js +223 -0
- package/dist/assets/indoor-maps/bureaux-wemap-montpellier.geojson +7444 -0
- package/dist/{pose.html → index.html} +4 -1
- package/dist/js/providers-components.js +353 -209
- package/package.json +9 -7
- package/src/ProvidersInterface.js +5 -4
- package/src/providers/MetaProvider.js +3 -1
- package/src/providers/attitude/relative/RelativeAttitudeFromInertialProvider.js +1 -1
- package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +1 -1
- package/src/providers/position/absolute/AbsolutePositionProvider.js +27 -16
- package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +2 -1
- package/src/providers/position/relative/PdrProvider.js +2 -1
- package/src/smoothers/PositionSmoother.js +10 -2
- package/webpack/webpack.common.js +5 -5
- package/webpack/webpack.dev.js +7 -1
- package/debug/components/Common.css +0 -27
- package/debug/components/MapComponent.jsx +0 -366
- package/debug/components/PoseComponent.jsx +0 -169
- package/debug/components/index.js +0 -28
- package/src/providers/legacy/AbsolutePdrProvider.js +0 -258
- package/src/providers/legacy/ArCoreAbsoluteProvider.js +0 -230
- package/src/providers/legacy/GnssWifiPdrProvider.js +0 -217
- package/src/providers/legacy/MapMatchingProvider.js +0 -65
- package/src/providers/legacy/PdrProvider.old.js +0 -300
- package/src/providers/legacy/PoseProvider.js +0 -68
- package/src/providers/legacy/helpers/Smoother.js +0 -92
- package/src/providers/legacy/helpers/Smoother.spec.js +0 -426
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import mapboxgl from 'mapbox-gl';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Attitude, UserPosition, Constants
|
|
5
|
+
} from '@wemap/geo';
|
|
6
|
+
import { deg2rad } from '@wemap/maths';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
PositionSmoother, ProvidersInterface, EventType
|
|
10
|
+
} from '../../..';
|
|
11
|
+
|
|
12
|
+
import ItineraryStore from '../../stores/ItineraryStore';
|
|
13
|
+
import MapboxHelper from '../MapboxHelper';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimum size of accuracy circle radius
|
|
17
|
+
*/
|
|
18
|
+
const MIN_ACCURACY_CIRCLE_RADIUS = 18;
|
|
19
|
+
|
|
20
|
+
class UserOnMapHandler {
|
|
21
|
+
|
|
22
|
+
positioningStarted = false;
|
|
23
|
+
|
|
24
|
+
trackUserLocation = true;
|
|
25
|
+
trackUserLocationFirst = true;
|
|
26
|
+
|
|
27
|
+
attitude = null;
|
|
28
|
+
attitudeDirty = false;
|
|
29
|
+
renderedAttitude = null;
|
|
30
|
+
|
|
31
|
+
position = null;
|
|
32
|
+
positionDirty = false;
|
|
33
|
+
renderedPosition = null;
|
|
34
|
+
|
|
35
|
+
positionAccuracy = null;
|
|
36
|
+
positionAccuracyDirty = false;
|
|
37
|
+
renderAccuracy = false;
|
|
38
|
+
|
|
39
|
+
positionForCameraDirty = false;
|
|
40
|
+
levelForPositionDirty = false;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {mapboxgl.Map} map
|
|
44
|
+
* @param {HTMLDivElement} mapContainer
|
|
45
|
+
*/
|
|
46
|
+
constructor(map, mapContainer) {
|
|
47
|
+
if (!map) {
|
|
48
|
+
throw new TypeError('map cannot be null');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.map = map;
|
|
52
|
+
this.mapContainer = mapContainer;
|
|
53
|
+
this.itineraryStore = ItineraryStore.instance;
|
|
54
|
+
|
|
55
|
+
map.on('zoom', () => (this.positionAccuracyDirty = true));
|
|
56
|
+
map.on('dragstart', () => (this.trackUserLocation = false));
|
|
57
|
+
map.on('level', () => (this.levelForPositionDirty = true));
|
|
58
|
+
|
|
59
|
+
this.createDomPosition();
|
|
60
|
+
this.createButtons();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
componentDidMount() {
|
|
65
|
+
this.renderPositionLoop();
|
|
66
|
+
this.renderPositionAccuracyLoop();
|
|
67
|
+
this.renderOrientationLoop();
|
|
68
|
+
this.renderCameraCenterLoop();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
componentWillUnmount() {
|
|
72
|
+
cancelAnimationFrame(this.renderPositionLoopId);
|
|
73
|
+
cancelAnimationFrame(this.renderPositionAccuracyLoopId);
|
|
74
|
+
cancelAnimationFrame(this.renderOrientationLoopId);
|
|
75
|
+
cancelAnimationFrame(this.renderCameraCenterLoopId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Geo location logic
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
startPositioning() {
|
|
84
|
+
|
|
85
|
+
if (this.positioningStarted) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.positioningStarted = true;
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Attitude
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
this.attitudeProvidersId = ProvidersInterface.addEventListener(
|
|
96
|
+
EventType.AbsoluteAttitude,
|
|
97
|
+
attitude => this.updateAttitude(attitude)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// There is no sense to show the last known attitude on the map
|
|
101
|
+
// this.updateAttitude(ProvidersInterface.getLastKnown(EventType.AbsoluteAttitude));
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Position
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
this.smoother = new PositionSmoother(position => this.updatePosition(position));
|
|
109
|
+
|
|
110
|
+
let firstPositionFound = false;
|
|
111
|
+
|
|
112
|
+
const firstPositionFn = () => {
|
|
113
|
+
this.buttonLocateMe.classList.remove('mapboxgl-ctrl-geolocate-waiting');
|
|
114
|
+
this.blueDot.classList.remove('inaccurate');
|
|
115
|
+
this.accuracyCircle.classList.remove('inaccurate');
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
this.positionProvidersId = ProvidersInterface.addEventListener(
|
|
119
|
+
EventType.AbsolutePosition,
|
|
120
|
+
position => {
|
|
121
|
+
this.smoother.feed(position);
|
|
122
|
+
|
|
123
|
+
if (!firstPositionFound) {
|
|
124
|
+
firstPositionFn();
|
|
125
|
+
firstPositionFound = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
this.updatePosition(ProvidersInterface.getLastKnown(EventType.AbsolutePosition));
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Itinerary
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
this.onItineraryChanged = itinerary => {
|
|
138
|
+
if (!itinerary) {
|
|
139
|
+
this.stopPositioning();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
this.itineraryStore.on(ItineraryStore.Events.ItineraryChanged, this.onItineraryChanged);
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* UI
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
this.buttonLocateMe.classList.add('mapboxgl-ctrl-geolocate-active');
|
|
150
|
+
this.buttonLocateMe.classList.add('mapboxgl-ctrl-geolocate-waiting');
|
|
151
|
+
this.buttonStopNav.style.display = 'block';
|
|
152
|
+
|
|
153
|
+
this.blueDot.classList.add('inaccurate');
|
|
154
|
+
this.accuracyCircle.classList.add('inaccurate');
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
stopPositioning() {
|
|
159
|
+
|
|
160
|
+
if (!this.positioningStarted) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this.positioningStarted = false;
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Attitude
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
ProvidersInterface.removeEventListener(this.attitudeProvidersId);
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Position
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
ProvidersInterface.removeEventListener(this.positionProvidersId);
|
|
178
|
+
this.smoother.clear();
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Itinerary
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
this.itineraryStore.off(ItineraryStore.Events.ItineraryChanged, this.onItineraryChanged);
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* UI
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
this.buttonLocateMe.classList.remove('mapboxgl-ctrl-geolocate-active');
|
|
193
|
+
this.buttonLocateMe.classList.remove('mapboxgl-ctrl-geolocate-waiting');
|
|
194
|
+
|
|
195
|
+
this.buttonStopNav.style.display = 'none';
|
|
196
|
+
|
|
197
|
+
this.position = null;
|
|
198
|
+
this.positionDirty = true;
|
|
199
|
+
this.positionAccuracy = null;
|
|
200
|
+
this.positionAccuracyDirty = true;
|
|
201
|
+
this.attitude = null;
|
|
202
|
+
this.attitudeDirty = true;
|
|
203
|
+
this.renderPosition();
|
|
204
|
+
this.renderOrientation();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {UserPosition} position
|
|
209
|
+
*/
|
|
210
|
+
updatePosition = position => {
|
|
211
|
+
|
|
212
|
+
if (this.position === position) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.positionDirty = true;
|
|
217
|
+
this.positionForCameraDirty = true;
|
|
218
|
+
this.position = position;
|
|
219
|
+
|
|
220
|
+
const newAccuracy = !position ? null : position.accuracy;
|
|
221
|
+
if (this.positionAccuracy !== newAccuracy) {
|
|
222
|
+
this.positionAccuracy = newAccuracy;
|
|
223
|
+
this.positionAccuracyDirty = true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @param {Attitude} attitude
|
|
230
|
+
*/
|
|
231
|
+
updateAttitude = attitude => {
|
|
232
|
+
|
|
233
|
+
if (this.attitude === attitude) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this.attitudeDirty = true;
|
|
238
|
+
this.attitude = attitude;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Render loops
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
renderPositionLoop = () => {
|
|
247
|
+
this.renderPosition();
|
|
248
|
+
this.renderPositionLoopId = requestAnimationFrame(this.renderPositionLoop);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
renderPosition() {
|
|
252
|
+
|
|
253
|
+
if (!this.positionDirty && !this.levelForPositionDirty) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let position;
|
|
258
|
+
if (this.position !== null
|
|
259
|
+
&& (this.map.getLevel() === null
|
|
260
|
+
|| this.position.level === null
|
|
261
|
+
|| this.map.getLevel() === this.position.level.val
|
|
262
|
+
)
|
|
263
|
+
) {
|
|
264
|
+
position = this.position;
|
|
265
|
+
} else {
|
|
266
|
+
position = null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (position && !this.renderedPosition) {
|
|
270
|
+
|
|
271
|
+
this.mapMarker = MapboxHelper.createMarker({
|
|
272
|
+
dom: this.positionIcon,
|
|
273
|
+
iconAnchor: [0, 0],
|
|
274
|
+
latitude: position.lat,
|
|
275
|
+
longitude: position.lng
|
|
276
|
+
}).addTo(this.map);
|
|
277
|
+
|
|
278
|
+
} else if (!position && this.renderPosition) {
|
|
279
|
+
this.mapMarker.remove();
|
|
280
|
+
} else if (position) {
|
|
281
|
+
this.mapMarker.setLngLat([position.lng, position.lat]);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
this.renderedPosition = position;
|
|
285
|
+
this.positionDirty = false;
|
|
286
|
+
this.levelForPositionDirty = false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
renderPositionAccuracyLoop = () => {
|
|
290
|
+
this.renderPositionAccuracy();
|
|
291
|
+
this.renderPositionAccuracyLoopId = requestAnimationFrame(this.renderPositionAccuracyLoop);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
renderPositionAccuracy() {
|
|
295
|
+
|
|
296
|
+
if (!this.positionAccuracyDirty) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
let accuracyToSmall = false;
|
|
301
|
+
if (this.positionAccuracy !== null) {
|
|
302
|
+
|
|
303
|
+
// https://wiki.openstreetmap.org/wiki/Zoom_levels
|
|
304
|
+
const lengthOfATileInMeters = Constants.CIRCUMFERENCE * Math.cos(deg2rad(this.position.lat)) / (2 ** this.map.getZoom());
|
|
305
|
+
const lengthOfAPixel = lengthOfATileInMeters / this.map.transform.tileSize;
|
|
306
|
+
const radiusInPx = this.position.accuracy / lengthOfAPixel;
|
|
307
|
+
|
|
308
|
+
if (radiusInPx < MIN_ACCURACY_CIRCLE_RADIUS) {
|
|
309
|
+
accuracyToSmall = true;
|
|
310
|
+
} else {
|
|
311
|
+
this.accuracyCircle.style.width = `${radiusInPx * 2}px`;
|
|
312
|
+
this.accuracyCircle.style.height = `${radiusInPx * 2}px`;
|
|
313
|
+
this.accuracyCircle.style.top = `-${radiusInPx}px`;
|
|
314
|
+
this.accuracyCircle.style.left = `-${radiusInPx}px`;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const renderAccuracy = this.positionAccuracy !== null && !accuracyToSmall;
|
|
319
|
+
|
|
320
|
+
if (renderAccuracy && !this.renderAccuracy) {
|
|
321
|
+
this.positionIcon.appendChild(this.accuracyCircle);
|
|
322
|
+
} else if (!renderAccuracy && this.renderAccuracy) {
|
|
323
|
+
this.positionIcon.removeChild(this.accuracyCircle);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
this.renderAccuracy = renderAccuracy;
|
|
327
|
+
this.positionAccuracyDirty = false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
renderOrientationLoop = () => {
|
|
331
|
+
this.renderOrientation();
|
|
332
|
+
this.renderOrientationLoopId = requestAnimationFrame(this.renderOrientationLoop);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
renderOrientation() {
|
|
336
|
+
|
|
337
|
+
if (!this.attitudeDirty || !this.positionIcon) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!this.renderedAttitude && this.attitude) {
|
|
342
|
+
this.positionIcon.appendChild(this.compassIcon);
|
|
343
|
+
} else if (this.renderedAttitude && !this.attitude) {
|
|
344
|
+
this.positionIcon.removeChild(this.compassIcon);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (this.attitude) {
|
|
348
|
+
this.positionIcon.style.transform = 'rotate(' + this.attitude.headingDegrees + 'deg)';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.renderedAttitude = this.attitude;
|
|
352
|
+
this.attitudeDirty = false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
renderCameraCenterLoop = () => {
|
|
356
|
+
this.renderCameraCenter();
|
|
357
|
+
this.renderCameraCenterLoopId = requestAnimationFrame(this.renderCameraCenterLoop);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
renderCameraCenter() {
|
|
362
|
+
|
|
363
|
+
if (!this.positionForCameraDirty || !this.trackUserLocation || !this.position) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const center = new mapboxgl.LngLat(this.position.lng, this.position.lat);
|
|
368
|
+
|
|
369
|
+
let transform;
|
|
370
|
+
if (this.trackUserLocationFirst) {
|
|
371
|
+
|
|
372
|
+
transform = this.map.cameraForBounds(
|
|
373
|
+
center.toBounds(this.position.accuracy),
|
|
374
|
+
{
|
|
375
|
+
bearing: this.map.getBearing(),
|
|
376
|
+
maxZoom: 21,
|
|
377
|
+
padding: 100
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
this.trackUserLocationFirst = false;
|
|
382
|
+
|
|
383
|
+
} else {
|
|
384
|
+
transform = { center };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
this.map.jumpTo(transform);
|
|
388
|
+
|
|
389
|
+
if (this.position && this.position.level && !this.position.level.isRange
|
|
390
|
+
&& this.position.level.val !== this.map.getLevel()) {
|
|
391
|
+
this.map.setLevel(this.position.level.val);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
this.positionForCameraDirty = false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Styling
|
|
400
|
+
*/
|
|
401
|
+
|
|
402
|
+
createDomPosition() {
|
|
403
|
+
|
|
404
|
+
// Main element
|
|
405
|
+
this.positionIcon = document.createElement('div');
|
|
406
|
+
|
|
407
|
+
// Accuracy circle
|
|
408
|
+
this.accuracyCircle = document.createElement('div');
|
|
409
|
+
this.accuracyCircle.id = 'location-marker-accuracy';
|
|
410
|
+
this.positionIcon.appendChild(this.accuracyCircle);
|
|
411
|
+
|
|
412
|
+
// Blue dot
|
|
413
|
+
this.blueDot = document.createElement('div');
|
|
414
|
+
this.blueDot.id = 'location-marker';
|
|
415
|
+
this.positionIcon.appendChild(this.blueDot);
|
|
416
|
+
|
|
417
|
+
// Compass cone
|
|
418
|
+
this.compassIcon = document.createElement('div');
|
|
419
|
+
this.compassIcon.id = 'location-marker-compass';
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
createButtons() {
|
|
425
|
+
|
|
426
|
+
const topRightContainer = document.getElementsByClassName('mapboxgl-ctrl-top-right')[0];
|
|
427
|
+
|
|
428
|
+
const userLocationContainer = document.createElement('div');
|
|
429
|
+
userLocationContainer.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
|
|
430
|
+
userLocationContainer.id = 'user-location-container';
|
|
431
|
+
topRightContainer.appendChild(userLocationContainer);
|
|
432
|
+
|
|
433
|
+
this.createLocateMeButton(userLocationContainer);
|
|
434
|
+
this.createStopNavButton(userLocationContainer);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @param {HTMLDivElement} container
|
|
439
|
+
*/
|
|
440
|
+
createLocateMeButton(container) {
|
|
441
|
+
|
|
442
|
+
const buttonLocateMe = document.createElement('button');
|
|
443
|
+
this.buttonLocateMe = buttonLocateMe;
|
|
444
|
+
|
|
445
|
+
buttonLocateMe.type = 'button';
|
|
446
|
+
buttonLocateMe.title = 'Find my location';
|
|
447
|
+
buttonLocateMe.className = 'mapboxgl-ctrl-geolocate';
|
|
448
|
+
container.appendChild(buttonLocateMe);
|
|
449
|
+
|
|
450
|
+
const span = document.createElement('span');
|
|
451
|
+
span.className = 'mapboxgl-ctrl-icon';
|
|
452
|
+
buttonLocateMe.appendChild(span);
|
|
453
|
+
|
|
454
|
+
buttonLocateMe.onclick = () => {
|
|
455
|
+
this.trackUserLocation = true;
|
|
456
|
+
this.positionForCameraDirty = true;
|
|
457
|
+
this.trackUserLocationFirst = true;
|
|
458
|
+
this.renderCameraCenter();
|
|
459
|
+
|
|
460
|
+
if (!this.positioningStarted) {
|
|
461
|
+
this.startPositioning();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* @param {HTMLDivElement} container
|
|
469
|
+
*/
|
|
470
|
+
createStopNavButton(container) {
|
|
471
|
+
|
|
472
|
+
const buttonStopNav = document.createElement('button');
|
|
473
|
+
this.buttonStopNav = buttonStopNav;
|
|
474
|
+
buttonStopNav.type = 'button';
|
|
475
|
+
buttonStopNav.title = 'Remove my location';
|
|
476
|
+
buttonStopNav.className = 'mapboxgl-ctrl-geolocate-remove';
|
|
477
|
+
buttonStopNav.style.display = 'none';
|
|
478
|
+
container.appendChild(buttonStopNav);
|
|
479
|
+
|
|
480
|
+
const span = document.createElement('span');
|
|
481
|
+
span.className = 'mapboxgl-ctrl-icon';
|
|
482
|
+
buttonStopNav.appendChild(span);
|
|
483
|
+
|
|
484
|
+
buttonStopNav.onclick = () => {
|
|
485
|
+
this.stopPositioning();
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
export default UserOnMapHandler;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { Coordinates } from '@wemap/geo';
|
|
2
|
+
import { Itinerary } from '@wemap/graph';
|
|
3
|
+
import { OsrmUtils } from '@wemap/osm';
|
|
4
|
+
import { Evented } from '@wemap/utils';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ProvidersInterface, EventType
|
|
8
|
+
} from '../..';
|
|
9
|
+
|
|
10
|
+
const Events = {
|
|
11
|
+
StartChanged: 'itinerary.start.changed',
|
|
12
|
+
EndChanged: 'itinerary.end.changed',
|
|
13
|
+
ItineraryChanged: 'itinerary.changed',
|
|
14
|
+
ItineraryNotFound: 'itinerary.not.found',
|
|
15
|
+
ItineraryComputing: 'itinerary.computing',
|
|
16
|
+
ItineraryServerChanged: 'itinerary.server.changed',
|
|
17
|
+
ServerError: 'itinerary.server.error',
|
|
18
|
+
UseStairsChanged: 'itinerary.use.stairs.changed'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const Servers = {
|
|
22
|
+
Indoor: {
|
|
23
|
+
name: 'Indoor',
|
|
24
|
+
routingUrl: 'https://osmrouter.getwemap.com'
|
|
25
|
+
},
|
|
26
|
+
Outdoor: {
|
|
27
|
+
name: 'Outdoor',
|
|
28
|
+
routingUrl: 'https://routingdev.maaap.it'
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
class ItineraryStore extends Evented {
|
|
33
|
+
|
|
34
|
+
_start = null;
|
|
35
|
+
_end = null;
|
|
36
|
+
_itinerary = null;
|
|
37
|
+
_itineraryServer = Servers.Outdoor;
|
|
38
|
+
_useStairs = true;
|
|
39
|
+
|
|
40
|
+
static Events = Events;
|
|
41
|
+
static Servers = Servers;
|
|
42
|
+
|
|
43
|
+
static instance = new ItineraryStore();
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {Coordinates} start
|
|
47
|
+
*/
|
|
48
|
+
set start(start) {
|
|
49
|
+
this._start = start;
|
|
50
|
+
this.fire(Events.StartChanged, start);
|
|
51
|
+
|
|
52
|
+
if (start !== null && start.level !== null && this.itineraryServer !== Servers.Indoor) {
|
|
53
|
+
this.itineraryServer = Servers.Indoor;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @returns {Coordinates}
|
|
59
|
+
*/
|
|
60
|
+
get start() {
|
|
61
|
+
return this._start;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @returns {Promise}
|
|
66
|
+
*/
|
|
67
|
+
retrieveStartFromUserLocation() {
|
|
68
|
+
|
|
69
|
+
const userPosition = ProvidersInterface.getLastKnown(EventType.AbsolutePosition);
|
|
70
|
+
if (userPosition) {
|
|
71
|
+
this.start = userPosition;
|
|
72
|
+
return Promise.resolve();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
|
|
77
|
+
let providerId;
|
|
78
|
+
|
|
79
|
+
const rejectFn = () => {
|
|
80
|
+
ProvidersInterface.removeEventListener(providerId);
|
|
81
|
+
reject();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
this.on(Events.StartChanged, rejectFn);
|
|
85
|
+
|
|
86
|
+
providerId = ProvidersInterface.addEventListener(EventType.AbsolutePosition,
|
|
87
|
+
position => {
|
|
88
|
+
this.off(Events.StartChanged, rejectFn);
|
|
89
|
+
ProvidersInterface.removeEventListener(providerId);
|
|
90
|
+
this.start = position;
|
|
91
|
+
resolve();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {Coordinates} end
|
|
98
|
+
*/
|
|
99
|
+
set end(end) {
|
|
100
|
+
this._end = end;
|
|
101
|
+
this.fire(Events.EndChanged, end);
|
|
102
|
+
|
|
103
|
+
if (end !== null && end.level !== null && this.itineraryServer !== Servers.Indoor) {
|
|
104
|
+
this.itineraryServer = Servers.Indoor;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @returns {Coordinates}
|
|
110
|
+
*/
|
|
111
|
+
get end() {
|
|
112
|
+
return this._end;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @returns {Itinerary}
|
|
117
|
+
*/
|
|
118
|
+
get itinerary() {
|
|
119
|
+
return this._itinerary;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @returns {Boolean}
|
|
124
|
+
*/
|
|
125
|
+
get isComputing() {
|
|
126
|
+
return this.itineraryComputing;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {Object}
|
|
131
|
+
*/
|
|
132
|
+
set itineraryServer(itineraryServer) {
|
|
133
|
+
this._itineraryServer = itineraryServer;
|
|
134
|
+
this.fire(Events.ItineraryServerChanged, itineraryServer);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @return {Object}
|
|
139
|
+
*/
|
|
140
|
+
get itineraryServer() {
|
|
141
|
+
return this._itineraryServer;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @param {Boolean}
|
|
146
|
+
*/
|
|
147
|
+
set useStairs(useStairs) {
|
|
148
|
+
this._useStairs = useStairs;
|
|
149
|
+
this.fire(Events.UseStairsChanged, useStairs);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @return {Boolean}
|
|
154
|
+
*/
|
|
155
|
+
get useStairs() {
|
|
156
|
+
return this._useStairs;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
compute() {
|
|
160
|
+
|
|
161
|
+
const start = this.start;
|
|
162
|
+
const end = this.end;
|
|
163
|
+
|
|
164
|
+
if (!start || !end) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const computingFn = (bool) => {
|
|
169
|
+
this.itineraryComputing = bool;
|
|
170
|
+
this.fire(Events.ItineraryComputing, bool);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
computingFn(true);
|
|
174
|
+
|
|
175
|
+
const isIndoor = this._itineraryServer === Servers.Indoor;
|
|
176
|
+
const useStartLevel = isIndoor && start.level !== null;
|
|
177
|
+
const useEndLevel = isIndoor && end.level !== null;
|
|
178
|
+
const useStairs = !isIndoor || this.useStairs;
|
|
179
|
+
|
|
180
|
+
const url = this._itineraryServer.routingUrl
|
|
181
|
+
+ '/route/v1/walking/'
|
|
182
|
+
+ start.lng + ',' + start.lat + (useStartLevel ? ',' + start.level : '')
|
|
183
|
+
+ ';'
|
|
184
|
+
+ end.lng + ',' + end.lat + (useEndLevel ? ',' + end.level : '')
|
|
185
|
+
+ '?geometries=geojson&overview=full'
|
|
186
|
+
+ (isIndoor ? '&useAltitude=false' : '')
|
|
187
|
+
+ (!useStairs ? '&useStairs=false' : '');
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
fetch(url)
|
|
191
|
+
.then(response => response.json())
|
|
192
|
+
.catch(error => {
|
|
193
|
+
computingFn(false);
|
|
194
|
+
this.fire(Events.ServerError, error);
|
|
195
|
+
})
|
|
196
|
+
.then(json => {
|
|
197
|
+
if (json.code !== 'Ok') {
|
|
198
|
+
computingFn(false);
|
|
199
|
+
this.remove();
|
|
200
|
+
this.fire(Events.ItineraryNotFound);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const itinerary = OsrmUtils.createItineraryFromJson(json, start, end);
|
|
204
|
+
|
|
205
|
+
this.itineraryComputing = false;
|
|
206
|
+
this.fire(Events.ItineraryComputing, false);
|
|
207
|
+
|
|
208
|
+
this._itinerary = itinerary;
|
|
209
|
+
this.fire(Events.ItineraryChanged, itinerary);
|
|
210
|
+
|
|
211
|
+
ProvidersInterface.feed(EventType.Network, itinerary);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
remove() {
|
|
216
|
+
this._itinerary = null;
|
|
217
|
+
this.fire(Events.ItineraryChanged, null);
|
|
218
|
+
ProvidersInterface.feed(EventType.Network, null);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export default ItineraryStore;
|