@wemap/providers 3.0.0

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.
Files changed (102) hide show
  1. package/babel.config.js +11 -0
  2. package/config.json +4 -0
  3. package/debug/absolute-attitude.html +16 -0
  4. package/debug/absolute-position.html +16 -0
  5. package/debug/attitude.html +16 -0
  6. package/debug/components/AbsoluteAttitudeComponent.jsx +142 -0
  7. package/debug/components/AbsolutePositionComponent.jsx +79 -0
  8. package/debug/components/AttitudeComponent.jsx +40 -0
  9. package/debug/components/Common.css +27 -0
  10. package/debug/components/GnssWifiComponent.jsx +53 -0
  11. package/debug/components/ImuComponent.jsx +53 -0
  12. package/debug/components/InclinationComponent.jsx +68 -0
  13. package/debug/components/MapComponent.jsx +366 -0
  14. package/debug/components/NavigationConfig.js +112 -0
  15. package/debug/components/PoseComponent.jsx +168 -0
  16. package/debug/components/RelativeAttitudeComponent.jsx +85 -0
  17. package/debug/components/StartStopComponent.jsx +45 -0
  18. package/debug/components/StepDetectionComponent.jsx +39 -0
  19. package/debug/components/Utils.js +216 -0
  20. package/debug/components/index.js +30 -0
  21. package/debug/components/old/PositioningComponent.jsx +29 -0
  22. package/debug/components/old/PositioningInclinationComponent.jsx +82 -0
  23. package/debug/components/old/PositioningPoseComponent.jsx +117 -0
  24. package/debug/gnss-wifi.html +16 -0
  25. package/debug/imu.html +16 -0
  26. package/debug/inclination.html +16 -0
  27. package/debug/pose.html +16 -0
  28. package/debug/positioning-legacy.html +16 -0
  29. package/debug/relative-attitude.html +16 -0
  30. package/debug/step-detection.html +16 -0
  31. package/index.js +7 -0
  32. package/package.json +67 -0
  33. package/src/Providers.js +80 -0
  34. package/src/ProvidersInterface.js +125 -0
  35. package/src/ProvidersOptions.js +29 -0
  36. package/src/errors/AskImuOnDesktopError.js +9 -0
  37. package/src/errors/ContainsIgnoredProviderError.js +9 -0
  38. package/src/errors/GeolocationApiMissingError.js +9 -0
  39. package/src/errors/GeolocationPermissionDeniedError.js +9 -0
  40. package/src/errors/GeolocationPositionUnavailableError.js +9 -0
  41. package/src/errors/IpResolveServerError.js +9 -0
  42. package/src/errors/MissingAccelerometerError.js +11 -0
  43. package/src/errors/MissingArCoreError.js +9 -0
  44. package/src/errors/MissingGyroscopeError.js +11 -0
  45. package/src/errors/MissingMagnetometerError.js +9 -0
  46. package/src/errors/MissingNativeInterfaceError.js +9 -0
  47. package/src/errors/MissingSensorError.js +14 -0
  48. package/src/errors/NoProviderFoundError.js +9 -0
  49. package/src/events/Availability.js +44 -0
  50. package/src/events/EventType.js +33 -0
  51. package/src/events/ProviderEvent.js +32 -0
  52. package/src/events/ProvidersLogger.js +83 -0
  53. package/src/providers/Constants.js +5 -0
  54. package/src/providers/FakeProvider.spec.js +57 -0
  55. package/src/providers/MetaProvider.js +42 -0
  56. package/src/providers/Provider.js +314 -0
  57. package/src/providers/Provider.spec.js +136 -0
  58. package/src/providers/ProviderState.js +5 -0
  59. package/src/providers/attitude/AttitudeProvider.js +63 -0
  60. package/src/providers/attitude/EkfAttitude.js +224 -0
  61. package/src/providers/attitude/EkfAttitude.spec.js +114 -0
  62. package/src/providers/attitude/absolute/AbsoluteAttitudeFromBrowserProvider.js +224 -0
  63. package/src/providers/attitude/absolute/AbsoluteAttitudeFromRelAttProvider.js +134 -0
  64. package/src/providers/attitude/absolute/AbsoluteAttitudeProvider.js +143 -0
  65. package/src/providers/attitude/relative/RelativeAttitudeFromBrowserProvider.js +89 -0
  66. package/src/providers/attitude/relative/RelativeAttitudeFromEkfProvider.js +114 -0
  67. package/src/providers/attitude/relative/RelativeAttitudeProvider.js +103 -0
  68. package/src/providers/imu/AccelerometerProvider.js +61 -0
  69. package/src/providers/imu/GyroscopeProvider.js +61 -0
  70. package/src/providers/imu/ImuProvider.js +122 -0
  71. package/src/providers/inclination/InclinationFromAccProvider.js +87 -0
  72. package/src/providers/inclination/InclinationFromAttitudeProvider.js +77 -0
  73. package/src/providers/inclination/InclinationProvider.js +69 -0
  74. package/src/providers/legacy/AbsolutePdrProvider.js +258 -0
  75. package/src/providers/legacy/ArCoreAbsoluteProvider.js +230 -0
  76. package/src/providers/legacy/GnssWifiPdrProvider.js +217 -0
  77. package/src/providers/legacy/MapMatchingProvider.js +65 -0
  78. package/src/providers/legacy/PdrProvider.old.js +300 -0
  79. package/src/providers/legacy/PoseProvider.js +68 -0
  80. package/src/providers/legacy/helpers/HeadingUnlocker.js +47 -0
  81. package/src/providers/legacy/helpers/HeadingUnlocker.spec.js +53 -0
  82. package/src/providers/legacy/helpers/Smoother.js +92 -0
  83. package/src/providers/legacy/helpers/Smoother.spec.js +426 -0
  84. package/src/providers/legacy/helpers/ThugDetector.js +37 -0
  85. package/src/providers/others/CameraNativeProvider.js +44 -0
  86. package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +109 -0
  87. package/src/providers/position/absolute/AbsolutePositionProvider.js +172 -0
  88. package/src/providers/position/absolute/GnssWifiProvider.js +122 -0
  89. package/src/providers/position/absolute/IpProvider.js +68 -0
  90. package/src/providers/position/relative/ArCoreProvider.js +197 -0
  91. package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +85 -0
  92. package/src/providers/position/relative/GeoRelativePositionProvider.js +66 -0
  93. package/src/providers/position/relative/PdrProvider.js +132 -0
  94. package/src/providers/steps/StepDetectionLadetto.js +67 -0
  95. package/src/providers/steps/StepDetectionMinMaxPeaks.js +80 -0
  96. package/src/providers/steps/StepDetectionMinMaxPeaks2.js +108 -0
  97. package/src/providers/steps/StepDetectionProvider.js +100 -0
  98. package/src/smoothers/PositionSmoother.js +86 -0
  99. package/src/smoothers/PositionSmoother.spec.js +55 -0
  100. package/webpack/webpack.common.js +20 -0
  101. package/webpack/webpack.dev.js +24 -0
  102. package/webpack/webpack.prod.js +15 -0
@@ -0,0 +1,366 @@
1
+ import React from 'react';
2
+ import mapboxgl from 'mapbox-gl';
3
+ import 'mapbox-gl/dist/mapbox-gl.css';
4
+ import PropTypes from 'prop-types';
5
+
6
+ import {
7
+ Attitude, UserPosition, Constants
8
+ } from '@wemap/geo';
9
+ import { Network } from '@wemap/graph';
10
+
11
+ mapboxgl.accessToken
12
+ = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA';
13
+
14
+ const COMPASS_STYLE = {
15
+ width: '15px',
16
+ height: '15px',
17
+ 'border-radius': '50%',
18
+ 'z-index': '10000001',
19
+ position: 'absolute',
20
+ top: '-14px',
21
+ left: '-14px',
22
+ border: '7px solid',
23
+ 'border-color': 'transparent',
24
+ 'border-top-color': '#008DF1',
25
+ opacity: 0.5
26
+ };
27
+
28
+ const POSITION_STYLE = {
29
+ width: '15px',
30
+ height: '15px',
31
+ top: '-7px',
32
+ left: '-7px',
33
+ position: 'absolute',
34
+ 'border-radius': '50%',
35
+ background: '#008DF1'
36
+ };
37
+
38
+ class MapComponent extends React.Component {
39
+ static propTypes = {
40
+ network: PropTypes.instanceOf(Network),
41
+ positionRenderFrequency: PropTypes.number,
42
+ centerCameraFrequency: PropTypes.number,
43
+ maxZoom: PropTypes.number
44
+ };
45
+
46
+ static defaultProps = {
47
+ maxZoom: 22,
48
+ positionRenderFrequency: 60,
49
+ centerCameraFrequency: 1
50
+ };
51
+
52
+ userAccuracySource = {
53
+ 'type': 'geojson',
54
+ 'data': {
55
+ 'type': 'FeatureCollection',
56
+ 'features': []
57
+ }
58
+ };
59
+
60
+ followUser = true;
61
+ positionDirty = false;
62
+ positionForCameraDirty = false;
63
+
64
+ componentDidMount() {
65
+ this.map = new mapboxgl.Map({
66
+ container: this.mapContainer,
67
+ style: 'mapbox://styles/mapbox/streets-v9',
68
+ maxZoom: this.props.maxZoom
69
+ });
70
+
71
+ this.createFollowingUser();
72
+ this.map.on('load', () => {
73
+ this.createUserAccuracyLayer();
74
+ });
75
+ this.renderNetwork();
76
+
77
+ this.positionRenderLoopId = setInterval(this.positionRenderLoop, 1e3 / this.props.positionRenderFrequency);
78
+ this.centerCameraRenderLoopId = setInterval(this.centerCameraRenderLoop, 1e3 / this.props.centerCameraFrequency);
79
+ }
80
+
81
+ componentWillUnmount() {
82
+ clearInterval(this.positionRenderLoopId);
83
+ clearInterval(this.centerCameraRenderLoopId);
84
+ this.map.remove();
85
+ }
86
+
87
+ createMarker(options) {
88
+ var elem, marker;
89
+
90
+ elem = document.createElement('div');
91
+ elem.style.marginLeft = '-' + options.iconAnchor[0] + 'px';
92
+ elem.style.marginTop = '-' + options.iconAnchor[1] + 'px';
93
+ elem.style.width = 0;
94
+ elem.style.height = 0;
95
+ elem.appendChild(options.dom);
96
+
97
+ marker = new mapboxgl.Marker(elem);
98
+ marker.setLngLat([options.longitude, options.latitude]);
99
+ return marker;
100
+ }
101
+
102
+ createPositionMarker(position) {
103
+ const coreIcon = document.createElement('div');
104
+ this.applyStyleToDomElement(coreIcon, POSITION_STYLE);
105
+
106
+ this.positionIcon = document.createElement('div');
107
+ this.positionIcon.appendChild(coreIcon);
108
+
109
+ return this.createMarker({
110
+ dom: this.positionIcon,
111
+ iconAnchor: [0, 0],
112
+ latitude: position[1],
113
+ longitude: position[0]
114
+ });
115
+ }
116
+
117
+ createCompassElement() {
118
+ if (!this.positionIcon) {
119
+ throw new Error('createPositionMarker() should be called before');
120
+ }
121
+ this.compassIcon = document.createElement('div');
122
+ this.applyStyleToDomElement(this.compassIcon, COMPASS_STYLE);
123
+ this.positionIcon.appendChild(this.compassIcon);
124
+ }
125
+
126
+ applyStyleToDomElement(domElement, style) {
127
+ for (const key in style) {
128
+ if (style.hasOwnProperty(key)) {
129
+ domElement.style[key] = style[key];
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @param {UserPosition} position
136
+ */
137
+ updatePosition(position) {
138
+ if (this.position !== position) {
139
+ this.positionDirty = true;
140
+ this.positionForCameraDirty = true;
141
+ }
142
+ this.position = position;
143
+ }
144
+
145
+ positionRenderLoop = () => {
146
+
147
+ if (!this.positionDirty) {
148
+ return;
149
+ }
150
+
151
+ if (this.position === null) {
152
+ if (this.mapMarker) {
153
+ this.mapMarker.remove();
154
+ this.mapMarker = null;
155
+ }
156
+ this.map.setLayoutProperty('user-accuracy', 'visibility', 'none');
157
+ this.positionIcon = null;
158
+ this.compassIcon = null;
159
+ return;
160
+ }
161
+
162
+ const lngLat = [this.position.lng, this.position.lat];
163
+
164
+ if (!this.mapMarker) {
165
+ this.mapMarker = this.createPositionMarker(lngLat).addTo(this.map);
166
+ } else {
167
+ this.mapMarker.setLngLat(lngLat);
168
+ }
169
+
170
+ if (this.position.accuracy) {
171
+ this.userAccuracySource.data.features = [{
172
+ 'type': 'Feature',
173
+ 'geometry': {
174
+ 'type': 'Polygon',
175
+ 'coordinates': [this.constructor.createGeoJSONCircle(lngLat, this.position.accuracy / 1e3)]
176
+ }
177
+ }];
178
+ this.map.setLayoutProperty('user-accuracy', 'visibility', 'visible');
179
+ } else {
180
+ this.userAccuracySource.data.features = [];
181
+ }
182
+
183
+ const userAccuracySource = this.map.getSource('user-accuracy');
184
+ if (userAccuracySource) {
185
+ userAccuracySource.setData(this.userAccuracySource.data);
186
+ }
187
+ }
188
+
189
+ centerCameraRenderLoop = () => {
190
+
191
+ if (!this.positionForCameraDirty || !this.followUser || !this.position) {
192
+ return;
193
+ }
194
+
195
+ this.positionForCameraDirty = false;
196
+
197
+ const center = [this.position.lng, this.position.lat];
198
+ let zoom = this.props.maxZoom;
199
+ if (this.position.accuracy) {
200
+ zoom = Math.min(Math.round(Math.log2(
201
+ Constants.R_MAJOR * Math.cos(this.position.lat / 180 * Math.PI)
202
+ / this.position.accuracy
203
+ / 256
204
+ * Math.min(this.mapContainer.offsetWidth, this.mapContainer.offsetHeight)
205
+ )), this.props.maxZoom);
206
+ }
207
+
208
+ this.map.easeTo({
209
+ center,
210
+ zoom
211
+ });
212
+ }
213
+
214
+ updateAttitude(attitude) {
215
+ if (!this.positionIcon) {
216
+ return;
217
+ }
218
+
219
+ if (!(attitude instanceof Attitude)) {
220
+ if (this.compassIcon) {
221
+ this.positionIcon.removeChild(this.compassIcon);
222
+ }
223
+ return;
224
+ }
225
+
226
+ if (!this.compassIcon) {
227
+ this.createCompassElement();
228
+ }
229
+
230
+ this.positionIcon.style.transform
231
+ = 'rotate(' + attitude.headingDegrees + 'deg)';
232
+ }
233
+
234
+ renderNetwork() {
235
+ if (!this.map) {
236
+ return;
237
+ }
238
+
239
+ const network = this.props.network;
240
+
241
+ if (network === this.previousNetwork) {
242
+ return;
243
+ }
244
+ this.previousNetwork = network;
245
+
246
+ if (!network) {
247
+ if (this.networkLayer) {
248
+ this.map.removeLayer(this.networkLayer);
249
+ this.networkLayer = null;
250
+ }
251
+ return;
252
+ }
253
+
254
+ const layer = {
255
+ id: 'network',
256
+ type: 'line',
257
+ source: {
258
+ type: 'geojson',
259
+ data: {
260
+ type: 'Feature',
261
+ properties: {},
262
+ geometry: {
263
+ type: 'MultiLineString',
264
+ coordinates: []
265
+ }
266
+ }
267
+ },
268
+ paint: {
269
+ 'line-color': '#0000FF',
270
+ 'line-width': 3
271
+ }
272
+ };
273
+
274
+ for (let i = 0; i < network.edges.length; i++) {
275
+ layer.source.data.geometry.coordinates.push([
276
+ [network.edges[i].node1.coords.lng, network.edges[i].node1.coords.lat],
277
+ [network.edges[i].node2.coords.lng, network.edges[i].node2.coords.lat]
278
+ ]);
279
+ }
280
+
281
+ this.networkLayer = this.map.addLayer(layer);
282
+ }
283
+
284
+ createUserAccuracyLayer() {
285
+ this.map.addSource('user-accuracy', this.userAccuracySource);
286
+ this.map.addLayer({
287
+ 'id': 'user-accuracy',
288
+ 'type': 'fill',
289
+ 'source': 'user-accuracy',
290
+ 'layout': {},
291
+ 'paint': {
292
+ 'fill-color': 'blue',
293
+ 'fill-opacity': 0.1
294
+ }
295
+ });
296
+ }
297
+
298
+ // https://stackoverflow.com/a/39006388/2239938
299
+ static createGeoJSONCircle(center, radiusInKm, points) {
300
+ if (!points) {
301
+ points = 64;
302
+ }
303
+
304
+ var coords = {
305
+ latitude: center[1],
306
+ longitude: center[0]
307
+ };
308
+
309
+ var km = radiusInKm;
310
+
311
+ var ret = [];
312
+ var distanceX = km / (111.320 * Math.cos(coords.latitude * Math.PI / 180));
313
+ var distanceY = km / 110.574;
314
+
315
+ var theta, x, y;
316
+ for (let i = 0; i < points; i++) {
317
+ theta = (i / points) * (2 * Math.PI);
318
+ x = distanceX * Math.cos(theta);
319
+ y = distanceY * Math.sin(theta);
320
+
321
+ ret.push([coords.longitude + x, coords.latitude + y]);
322
+ }
323
+ ret.push(ret[0]);
324
+ return ret;
325
+ }
326
+
327
+ createFollowingUser() {
328
+
329
+ const topRightContainer = document.getElementsByClassName('mapboxgl-ctrl-top-right')[0];
330
+
331
+ const container = document.createElement('div');
332
+ container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
333
+ topRightContainer.appendChild(container);
334
+
335
+ const button = document.createElement('button');
336
+ button.type = 'button';
337
+ button.title = 'Find my location';
338
+ button.className = 'mapboxgl-ctrl-geolocate';
339
+ container.appendChild(button);
340
+
341
+ const span = document.createElement('span');
342
+ span.className = 'mapboxgl-ctrl-icon';
343
+ button.appendChild(span);
344
+
345
+ button.onclick = () => {
346
+ this.followUser = true;
347
+ this.positionForCameraDirty = true;
348
+ this.centerCameraRenderLoop();
349
+ };
350
+
351
+ this.map.on('dragstart', () => (this.followUser = false));
352
+ }
353
+
354
+ render() {
355
+ this.renderNetwork();
356
+ return (
357
+ <div ref={map => (this.mapContainer = map)}
358
+ style={{
359
+ width: '100%',
360
+ height: '100%'
361
+ }} />
362
+ );
363
+ }
364
+ }
365
+
366
+ export default MapComponent;
@@ -0,0 +1,112 @@
1
+ import React from 'react'; // eslint-disable-line no-unused-vars
2
+
3
+ import {
4
+ AbsoluteHeading, UserPosition, Level
5
+ } from '@wemap/geo';
6
+ import { Itinerary } from '@wemap/graph';
7
+ import { deg2rad } from '@wemap/maths';
8
+ import { TimeUtils } from '@wemap/utils';
9
+
10
+ const datasets = {};
11
+
12
+ // Wemap Office
13
+ const wemapOffice = {
14
+ get initialPosition() {
15
+ return new UserPosition(43.6091955, 3.8841255, 1.5, null, TimeUtils.preciseTime / 1e3, 0);
16
+ },
17
+ get initialHeading() {
18
+ return new AbsoluteHeading(deg2rad(191.9), TimeUtils.preciseTime / 1e3, 0);
19
+ }
20
+ };
21
+ wemapOffice.itinerary = Itinerary.fromOrderedPointsArray(
22
+ [
23
+ [wemapOffice.initialPosition.lat, wemapOffice.initialPosition.lng],
24
+ [43.6091883, 3.8841242],
25
+ [43.6091709, 3.8842382],
26
+ [43.6091288, 3.884226],
27
+ [43.6091461, 3.884112]
28
+ ],
29
+ [wemapOffice.initialPosition.lat, wemapOffice.initialPosition.lng],
30
+ [43.6091461, 3.884112]
31
+ );
32
+
33
+ // Wemap Office Multi-level
34
+ const wemapOfficeMulti = {
35
+ get initialPosition() {
36
+ return new UserPosition(43.6091965, 3.8841285, 1.5, new Level(2), TimeUtils.preciseTime / 1e3, 0);
37
+ },
38
+ get initialHeading() {
39
+ return new AbsoluteHeading(deg2rad(191.9), TimeUtils.preciseTime / 1e3, 0);
40
+ }
41
+ };
42
+ wemapOfficeMulti.itinerary = Itinerary.fromOrderedPointsArray(
43
+ [
44
+ [43.6091888, 3.8841263, new Level(2)],
45
+ [43.6091749, 3.8842173, new Level(2)],
46
+ [43.6092935, 3.8842518, new Level(2)],
47
+ [43.6093022, 3.8842702, new Level(2)],
48
+ [43.6093123, 3.8842731, new Level(2)],
49
+ [43.6093234, 3.8842009, new Level(2)],
50
+ [43.6093629, 3.8842127, new Level(1, 2)],
51
+ [43.6093597, 3.8842336, new Level(1, 2)],
52
+ [43.6093202, 3.8842218, new Level(1)],
53
+ [43.6093123, 3.8842731, new Level(1)],
54
+ [43.6092681, 3.8842604, new Level(1)]
55
+ ],
56
+ [wemapOfficeMulti.initialPosition.lat, wemapOffice.initialPosition.lng, wemapOfficeMulti.initialPosition.level],
57
+ [43.6092602, 3.8842669, new Level(1)]
58
+ );
59
+
60
+ // Gare de Lyon RER A
61
+ const gareDeLyonRerA = {
62
+ get initialPosition() {
63
+ return new UserPosition(48.8442365, 2.3728267, 1.5, new Level(-2), TimeUtils.preciseTime / 1e3, 0);
64
+ },
65
+ get initialHeading() {
66
+ return new AbsoluteHeading(deg2rad(41.6), TimeUtils.preciseTime / 1e3, 0);
67
+ }
68
+ };
69
+ gareDeLyonRerA.itinerary = Itinerary.fromOrderedPointsArray(
70
+ [
71
+ [48.8442368, 2.3728274, new Level(-2)],
72
+ [48.8442378, 2.3728257, new Level(-2)],
73
+ [48.8443732, 2.3726023, new Level(-1)],
74
+ [48.8443864, 2.3726195, new Level(-1)],
75
+ [48.8444032, 2.3726407, new Level(-1)]
76
+ ],
77
+ [gareDeLyonRerA.initialPosition.lat, gareDeLyonRerA.initialPosition.lng, gareDeLyonRerA.initialPosition.level],
78
+ [48.8444315, 2.3726809, new Level(-1)]
79
+ );
80
+
81
+
82
+ datasets['wemap-office'] = wemapOffice;
83
+ datasets['wemap-office-multi'] = wemapOfficeMulti;
84
+ datasets['gare-de-lyon-rer-a'] = gareDeLyonRerA;
85
+
86
+ class NavigationConfig {
87
+
88
+ static dataset = wemapOffice;
89
+
90
+ static load(datasetName) {
91
+ const dataset = datasets[datasetName];
92
+ if (!dataset) {
93
+ throw new Error('Unknown ' + datasetName);
94
+ }
95
+ this.dataset = dataset;
96
+ }
97
+
98
+ static get INITIAL_POSITION() {
99
+ return this.dataset.initialPosition;
100
+ }
101
+
102
+ static get INITIAL_HEADING() {
103
+ return this.dataset.initialHeading;
104
+ }
105
+
106
+ static get ITINERARY() {
107
+ return this.dataset.itinerary;
108
+ }
109
+
110
+ }
111
+
112
+ export default NavigationConfig;
@@ -0,0 +1,168 @@
1
+ import React from 'react';
2
+
3
+ import {
4
+ PositionSmoother, ProvidersInterface, EventType
5
+ } from '../..';
6
+
7
+ import Utils from './Utils';
8
+ import MapComponent from './MapComponent';
9
+ import NavigationConfig from './NavigationConfig';
10
+
11
+ import './Common.css';
12
+ import StartStopComponent from './StartStopComponent';
13
+
14
+
15
+ class PoseComponent extends React.Component {
16
+
17
+ started = false;
18
+
19
+ constructor(props, context) {
20
+ super(props, context);
21
+ this.state = {
22
+ position: null,
23
+ attitude: null
24
+ };
25
+
26
+ this.smoother = new PositionSmoother(position => {
27
+ if (this.map && this.started) {
28
+ this.map.updatePosition(position);
29
+ }
30
+ });
31
+
32
+ ProvidersInterface.logger = true;
33
+ }
34
+
35
+ componentWillUnmount() {
36
+ this.onStop();
37
+ }
38
+
39
+ onStart = () => {
40
+ this.started = true;
41
+ this.onAttitudeEvent(ProvidersInterface.getLastKnown(EventType.AbsoluteAttitude));
42
+ this.attitudeProviderId = ProvidersInterface.addEventListener(
43
+ EventType.AbsoluteAttitude,
44
+ this.onAttitudeEvent,
45
+ this.onAttitudeError
46
+ );
47
+
48
+ this.onPositionEvent(ProvidersInterface.getLastKnown(EventType.AbsolutePosition));
49
+ this.positionProviderId = ProvidersInterface.addEventListener(
50
+ EventType.AbsolutePosition,
51
+ this.onPositionEvent,
52
+ this.onPositionError
53
+ );
54
+ }
55
+
56
+ onStop = () => {
57
+ this.started = false;
58
+ ProvidersInterface.removeEventListener(this.attitudeProviderId);
59
+ ProvidersInterface.removeEventListener(this.positionProviderId);
60
+ this.map.updatePosition(null);
61
+ this.map.updateAttitude(null);
62
+ }
63
+
64
+ onPositionEvent = position => {
65
+ if (!position) {
66
+ return;
67
+ }
68
+ this.setState({ position });
69
+ this.smoother.feed(position);
70
+ };
71
+
72
+ onPositionError = error => {
73
+ this.setState({ position: error });
74
+ };
75
+
76
+ onAttitudeEvent = attitude => {
77
+ if (!attitude) {
78
+ return;
79
+ }
80
+ this.setState({ attitude });
81
+ if (this.map && this.started) {
82
+ this.map.updateAttitude(attitude);
83
+ }
84
+ };
85
+
86
+ onAttitudeError = error => {
87
+ this.setState({ attitude: error });
88
+ };
89
+
90
+ handleHeadingButton() {
91
+ ProvidersInterface.feed(EventType.AbsoluteHeading, NavigationConfig.INITIAL_HEADING);
92
+ }
93
+
94
+ handlePosButton() {
95
+ ProvidersInterface.feed(EventType.AbsolutePosition, NavigationConfig.INITIAL_POSITION);
96
+ }
97
+
98
+ handleItinerary() {
99
+ const itinerary = NavigationConfig.ITINERARY;
100
+ ProvidersInterface.feed(EventType.Network, itinerary);
101
+ this.setState({ itinerary });
102
+ }
103
+
104
+
105
+ render() {
106
+
107
+ const errored = this.state.attitude instanceof Error
108
+ && this.state.position instanceof Error;
109
+
110
+ return (
111
+ <div style={{
112
+ display: 'flex',
113
+ flexFlow: 'column',
114
+ height: 'calc(100% - 16px)',
115
+ padding: '8px'
116
+ }}>
117
+
118
+ <StartStopComponent
119
+ onStart={this.onStart}
120
+ onStop={this.onStop}
121
+ errored={errored}
122
+ />
123
+
124
+ <div style={{ marginTop: '10px' }}>
125
+ <input type="button"
126
+ onClick={() => this.handlePosButton()}
127
+ value="Send Wemap position" />
128
+ <input type="button"
129
+ style={{ marginLeft: '10px' }}
130
+ onClick={() => this.handleHeadingButton()}
131
+ value="Send heading" />
132
+ <input type="button"
133
+ value="Add itinerary"
134
+ style={{ marginLeft: '10px' }}
135
+ onClick={() => this.handleItinerary()} />
136
+ </div>
137
+
138
+ <div style={{
139
+ display: 'flex',
140
+ flexFlow: 'row'
141
+ }}>
142
+ <div style={{ width: '50%' }}>
143
+ <div className="title">Position</div>
144
+ {Utils.renderPositionEvent(this.state.position)}
145
+ </div>
146
+ <div style={{ width: '50%' }}>
147
+ <div className="title">Attitude</div>
148
+ {Utils.renderAttitudeEvent(this.state.attitude)}
149
+ </div>
150
+ </div>
151
+
152
+ <div className="title">Map</div>
153
+ <div style={{
154
+ flexGrow: 1,
155
+ minHeight: '300px'
156
+ }}>
157
+ <MapComponent
158
+ ref={map => (this.map = map)}
159
+ network={this.state.itinerary}
160
+ />
161
+ </div>
162
+ </div >
163
+
164
+ );
165
+ }
166
+ }
167
+
168
+ export default PoseComponent;