@wemap/providers 3.1.3 → 3.1.5

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 (58) hide show
  1. package/debug/Common.css +172 -0
  2. package/debug/MainComponent.jsx +51 -0
  3. package/debug/components/AbsolutePositionComponent.jsx +1 -1
  4. package/debug/components/GnssWifiComponent.jsx +1 -1
  5. package/debug/components/StartStopComponent.jsx +5 -3
  6. package/debug/components/Utils.js +4 -2
  7. package/debug/details/DetailsAttitudeComponent.jsx +128 -0
  8. package/debug/details/DetailsComponent.jsx +32 -0
  9. package/debug/details/DetailsPositionComponent.jsx +135 -0
  10. package/debug/details/ItineraryComponent.jsx +323 -0
  11. package/debug/index.js +28 -0
  12. package/debug/map/MapComponent.jsx +77 -0
  13. package/debug/map/MapHandler.js +53 -0
  14. package/debug/map/MapboxHelper.js +50 -0
  15. package/debug/map/helpers/ItineraryMapHandler.js +284 -0
  16. package/debug/map/helpers/MapClickHandler.js +119 -0
  17. package/debug/map/helpers/UserOnMapHandler.js +470 -0
  18. package/debug/stores/ItineraryStore.js +223 -0
  19. package/dist/assets/indoor-maps/bureaux-wemap-montpellier.geojson +7444 -0
  20. package/dist/{pose.html → index.html} +4 -1
  21. package/dist/js/providers-components.js +353 -209
  22. package/package.json +9 -7
  23. package/src/ProvidersInterface.js +5 -4
  24. package/src/providers/FakeProvider.spec.js +2 -7
  25. package/src/providers/MetaProvider.js +3 -1
  26. package/src/providers/Provider.js +19 -14
  27. package/src/providers/Provider.spec.js +21 -20
  28. package/src/providers/attitude/absolute/AbsoluteAttitudeFromBrowserProvider.js +2 -3
  29. package/src/providers/attitude/absolute/AbsoluteAttitudeProvider.js +3 -3
  30. package/src/providers/attitude/relative/RelativeAttitudeFromBrowserProvider.js +2 -3
  31. package/src/providers/attitude/relative/RelativeAttitudeFromEkfProvider.js +3 -4
  32. package/src/providers/attitude/relative/RelativeAttitudeFromInertialProvider.js +18 -12
  33. package/src/providers/imu/ImuProvider.js +2 -3
  34. package/src/providers/inclination/InclinationProvider.js +4 -3
  35. package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +1 -1
  36. package/src/providers/position/absolute/AbsolutePositionProvider.js +41 -26
  37. package/src/providers/position/absolute/GnssWifiProvider.js +2 -3
  38. package/src/providers/position/relative/ArCoreProvider.js +3 -4
  39. package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +2 -1
  40. package/src/providers/position/relative/GeoRelativePositionProvider.js +23 -20
  41. package/src/providers/position/relative/PdrProvider.js +4 -4
  42. package/src/providers/steps/StepDetectionProvider.js +2 -3
  43. package/src/smoothers/PositionSmoother.js +10 -2
  44. package/webpack/webpack.common.js +5 -5
  45. package/webpack/webpack.dev.js +7 -1
  46. package/debug/components/Common.css +0 -27
  47. package/debug/components/MapComponent.jsx +0 -366
  48. package/debug/components/PoseComponent.jsx +0 -169
  49. package/debug/components/index.js +0 -28
  50. package/src/events/Availability.js +0 -44
  51. package/src/providers/legacy/AbsolutePdrProvider.js +0 -258
  52. package/src/providers/legacy/ArCoreAbsoluteProvider.js +0 -230
  53. package/src/providers/legacy/GnssWifiPdrProvider.js +0 -217
  54. package/src/providers/legacy/MapMatchingProvider.js +0 -65
  55. package/src/providers/legacy/PdrProvider.old.js +0 -300
  56. package/src/providers/legacy/PoseProvider.js +0 -68
  57. package/src/providers/legacy/helpers/Smoother.js +0 -92
  58. package/src/providers/legacy/helpers/Smoother.spec.js +0 -426
@@ -0,0 +1,172 @@
1
+ html,
2
+ body {
3
+ margin: 0;
4
+ font-size: 14px;
5
+ height: 100%;
6
+ }
7
+
8
+ #app {
9
+ height: 100%
10
+ }
11
+
12
+ p {
13
+ margin-top: 0;
14
+ }
15
+
16
+ .title {
17
+ font-size: 18px;
18
+ font-weight: bold;
19
+ margin-top: 10px;
20
+ margin-bottom: 5px;
21
+ }
22
+
23
+ #map-container {
24
+ position: absolute;
25
+ height: 100%;
26
+ width: 100%;
27
+ }
28
+
29
+ #menu-container {
30
+ position: absolute;
31
+ background: #FFFFFFAA;
32
+ margin: 10px;
33
+ padding: 10px;
34
+ max-width: 250px;
35
+ min-width: 150px;
36
+ }
37
+
38
+ #details-container {
39
+ margin-top: 10px;
40
+ }
41
+
42
+ #show-hide-details {
43
+ cursor: pointer;
44
+ -webkit-user-select: none;
45
+ user-select: none;
46
+ -moz-user-select: none;
47
+ text-decoration: underline;
48
+ font-size: 16px;
49
+ }
50
+
51
+ #location-marker {
52
+ width: 14px;
53
+ height: 14px;
54
+ top: -7px;
55
+ left: -7px;
56
+ position: absolute;
57
+ border-radius: 50%;
58
+ background: #008DF1;
59
+ border:1px solid #000000AA;
60
+ }
61
+
62
+ #location-marker.inaccurate {
63
+ background: #AAAAAA;
64
+ }
65
+
66
+ #location-marker-compass {
67
+ width: 15px;
68
+ height: 15px;
69
+ border-radius: 50%;
70
+ z-index: 10000001;
71
+ position: absolute;
72
+ top: -14px;
73
+ left: -14px;
74
+ border: 7px solid;
75
+ border-color: transparent;
76
+ border-top-color: #008DF1;
77
+ opacity: 0.5;
78
+ }
79
+
80
+ #location-marker-accuracy {
81
+ position: absolute;
82
+ border-radius: 50%;
83
+ background: #008DF134;
84
+ border:1px solid #00000034;
85
+ }
86
+
87
+ #location-marker-accuracy.inaccurate {
88
+ background: #AAAAAA34;
89
+ }
90
+
91
+ .loader {
92
+ display: inline-block;
93
+ border: 3px solid #f3f3f3; /* Light grey */
94
+ border-top: 3px solid #3498db; /* Blue */
95
+ border-radius: 50%;
96
+ width: 3px;
97
+ height: 3px;
98
+ animation: spin 2s linear infinite;
99
+ }
100
+
101
+ @keyframes spin {
102
+ 0% { transform: rotate(0deg); }
103
+ 100% { transform: rotate(360deg); }
104
+ }
105
+
106
+ #wheelchair-icon {
107
+ width: 15px;
108
+ height: 15px;
109
+ content: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='iso-8859-1'%3F%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512;' xml:space='preserve'%3E%3Cg%3E%3Cg%3E%3Cpath d='M449.771,470.475L416.382,325.79c-3.722-14.89-17.047-25.287-32.394-25.287h-64.876 c-9.178-15.069-21.144-28.282-35.291-38.91v-94.647c0-25.164-26.951-40.553-48.323-29.868l-66.778,33.389 c-11.385,5.69-18.344,17.135-18.344,29.868v42.705c-0.207,0.071-0.417,0.094-0.622,0.174 c-53.773,21.003-88.521,71.886-88.521,129.632c0,76.713,62.409,139.122,139.122,139.122c77.23,0,142.093-63.95,138.875-144.687 h18.691l27.063,119.4c4.459,17.802,22.381,28.848,40.498,24.292C443.332,506.511,454.228,488.344,449.771,470.475z M200.353,478.579c-58.301,0-105.732-47.432-105.732-105.732c0-39.568,21.583-74.727,55.754-92.997v42.913 c0,18.412,14.866,33.389,33.278,33.389s33.389-14.977,33.389-33.389v-54.647c0.826,0.292,1.658,0.574,2.549,0.738 c50.116,9.205,86.495,52.942,86.495,103.994C306.085,431.147,258.654,478.579,200.353,478.579z'/%3E%3C/g%3E%3C/g%3E%3Cg%3E%3Cg%3E%3Cpath d='M256.002,0c-27.617,0-50.084,22.466-50.084,50.084s22.466,50.084,50.084,50.084s50.084-22.466,50.084-50.084 S283.619,0,256.002,0z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");
110
+ margin-left: 10px;
111
+ padding: 1px;
112
+ vertical-align: top;
113
+ border-width: 2px;
114
+ border-style: solid;
115
+ border-color: #66666666;
116
+ cursor: pointer;
117
+ }
118
+
119
+ #wheelchair-icon.selected {
120
+ border-color: blue;
121
+ }
122
+
123
+ .mapboxgl-ctrl button.mapboxgl-ctrl-geolocate-remove .mapboxgl-ctrl-icon {
124
+ background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23aaa'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")
125
+ }
126
+
127
+ .map-click-list-element {
128
+ cursor: pointer;
129
+ -webkit-user-select: none;
130
+ user-select: none;
131
+ -moz-user-select: none;
132
+ padding: 3px 10px 3px 25px;
133
+
134
+ background-position-x: 8px;
135
+ background-repeat: no-repeat;
136
+ background-size: auto 50%;
137
+ background-position-y: center;
138
+ }
139
+
140
+ .map-click-list-element:hover {
141
+ background-color: #00000033;
142
+ }
143
+
144
+
145
+ #navigate-to-this-point {
146
+ background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='iso-8859-1'%3F%3E%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512;' xml:space='preserve'%3E%3Cg%3E%3Cg%3E%3Cpath fill='%233366ff' d='M444.644,344.229L81.977,2.896c-0.116-0.108-0.288-0.102-0.408-0.204c-1.23-1.065-2.707-1.759-4.335-2.173 c-0.487-0.126-0.915-0.229-1.415-0.285C75.423,0.189,75.075,0,74.665,0c-1.496,0-2.914,0.318-4.206,0.872 c-0.008,0.004-0.016-0.001-0.016-0.001c-0.04,0.018-0.055,0.056-0.087,0.07c-1.667,0.74-2.98,1.975-4.066,3.413 c-0.273,0.361-0.499,0.684-0.724,1.076c-0.908,1.569-1.568,3.292-1.568,5.237v490.667c0,1.967,0.674,3.707,1.602,5.289 c0.227,0.391,0.451,0.714,0.724,1.073c1.129,1.478,2.499,2.751,4.241,3.478c0,0,0.01,0.012,0.017,0.014 C71.904,511.74,73.29,512,74.665,512c1.401,0,2.786-0.285,4.083-0.823c1.309-0.543,2.487-1.328,3.471-2.315l146.195-146.195 h208.917c4.375,0,8.302-2.667,9.917-6.74C448.863,351.865,447.832,347.229,444.644,344.229z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");
147
+ }
148
+
149
+ #start-from-there {
150
+ background-image: url("data:image/svg+xml,%3Csvg height='422pt' viewBox='-45 0 422 422' width='422pt' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='green' d='m203.136719 187.609375c30.636719-22.902344 71.796875-25.894531 105.425781-7.660156l24.15625 13.152343.027344-150.851562-30.824219-16.792969c-28.796875-15.621093-64.050781-13.058593-90.28125 6.566407-30.597656 22.902343-71.726563 25.894531-105.316406 7.660156l-23.953125-13.148438v150.851563l30.640625 16.789062c28.742187 15.625 63.953125 13.058594 90.125-6.566406zm0 0'/%3E%3Cpath d='m36.371094 0v408h-29.371094c-3.867188 0-7 3.132812-7 7s3.132812 7 7 7h90.601562c3.863282 0 7-3.132812 7-7s-3.136718-7-7-7h-29.230468v-408zm0 0'/%3E%3C/svg%3E");
151
+ }
152
+
153
+ #end-to-there {
154
+ background-image: url("data:image/svg+xml,%3Csvg height='422pt' viewBox='-45 0 422 422' width='422pt' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='red' d='m203.136719 187.609375c30.636719-22.902344 71.796875-25.894531 105.425781-7.660156l24.15625 13.152343.027344-150.851562-30.824219-16.792969c-28.796875-15.621093-64.050781-13.058593-90.28125 6.566407-30.597656 22.902343-71.726563 25.894531-105.316406 7.660156l-23.953125-13.148438v150.851563l30.640625 16.789062c28.742187 15.625 63.953125 13.058594 90.125-6.566406zm0 0'/%3E%3Cpath d='m36.371094 0v408h-29.371094c-3.867188 0-7 3.132812-7 7s3.132812 7 7 7h90.601562c3.863282 0 7-3.132812 7-7s-3.136718-7-7-7h-29.230468v-408zm0 0'/%3E%3C/svg%3E");
155
+ }
156
+
157
+
158
+ .mapboxgl-popup-content {
159
+ padding: 0;
160
+ padding-top: 17px;
161
+ padding-bottom: 10px;
162
+ }
163
+
164
+ @media screen and (max-width: 600px) {
165
+ html, body {
166
+ font-size: 12px;
167
+ }
168
+
169
+ .title {
170
+ font-size: 14px;
171
+ }
172
+ }
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+
3
+ import { ProvidersInterface } from '..';
4
+
5
+ import MapComponent from './map/MapComponent';
6
+ import DetailsComponent from './details/DetailsComponent';
7
+
8
+ import './Common.css';
9
+
10
+ class MainComponent extends React.Component {
11
+
12
+ started = false;
13
+
14
+ constructor(props, context) {
15
+ super(props, context);
16
+ this.state = {
17
+ details: true,
18
+ mapHandler: null
19
+ };
20
+
21
+ ProvidersInterface.logger = false;
22
+ }
23
+
24
+
25
+ render() {
26
+ return (
27
+ <>
28
+ <div id='map-container'>
29
+ <MapComponent
30
+ ref={map => (this.map = map)}
31
+ onMapLoaded={mapHandler => this.setState({ mapHandler })}
32
+ indoorMaps={['assets/indoor-maps/bureaux-wemap-montpellier.geojson']}
33
+ />
34
+ </div>
35
+ <div id='menu-container'>
36
+ <span id='show-hide-details'
37
+ onClick={() => this.setState({ details: !this.state.details })}>
38
+ {this.state.details ? 'Hide details' : 'Show details'}
39
+ </span>
40
+ {this.state.details ? (
41
+ <div id='details-container'>
42
+ <DetailsComponent mapHandler={this.state.mapHandler} />
43
+ </div>
44
+ ) : null}
45
+ </div>
46
+ </>
47
+ );
48
+ }
49
+ }
50
+
51
+ export default MainComponent;
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { AbsolutePosition } from '../../src/Providers';
4
4
  import Utils from './Utils';
5
5
  import NavigationConfig from './NavigationConfig';
6
- import MapComponent from './MapComponent';
6
+ import MapComponent from '../map/MapComponent';
7
7
 
8
8
 
9
9
  class AbsolutePositionComponent extends React.Component {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import Utils from './Utils';
4
- import MapComponent from './MapComponent';
4
+ import MapComponent from '../map/MapComponent';
5
5
  import ProvidersLogger from '../../src/events/ProvidersLogger';
6
6
  import { GnssWifi } from '../../src/Providers';
7
7
 
@@ -6,9 +6,11 @@ class StartStopComponent extends React.Component {
6
6
  static propTypes = {
7
7
  onStart: PropTypes.func.isRequired,
8
8
  onStop: PropTypes.func.isRequired,
9
- errored: PropTypes.bool.isRequired
9
+ errored: PropTypes.bool
10
10
  };
11
11
 
12
+ static defaultProps = { errored: false };
13
+
12
14
  constructor(props, context) {
13
15
  super(props, context);
14
16
  this.state = { started: false };
@@ -26,7 +28,7 @@ class StartStopComponent extends React.Component {
26
28
 
27
29
  render() {
28
30
  return (
29
- <div>
31
+ <span>
30
32
  <button onClick={() => this.start()}
31
33
  disabled={(this.state.started && !this.props.errored)}>
32
34
  Start
@@ -35,7 +37,7 @@ class StartStopComponent extends React.Component {
35
37
  disabled={!(this.state.started && !this.props.errored)}>
36
38
  Stop
37
39
  </button>
38
- </div>
40
+ </span>
39
41
 
40
42
  );
41
43
  }
@@ -10,6 +10,8 @@ const NOT_AVAILABLE_STR = 'Not available';
10
10
 
11
11
  class Utils {
12
12
 
13
+ static NOT_AVAILABLE_STR = NOT_AVAILABLE_STR;
14
+
13
15
  static renderAttitudeEvent(event) {
14
16
 
15
17
  if (!event) {
@@ -40,7 +42,7 @@ class Utils {
40
42
  return (
41
43
  <div>
42
44
  <p>
43
- Quaternion: [{w}, {x}, {y}, {z}]<br />
45
+ Quat: [{w}, {x}, {y}, {z}]<br />
44
46
  Eulers: [{yaw}, {pitch}, {roll}]<br />
45
47
  Heading: {heading}<br />
46
48
  Time: {attitude.time.toFixed(2)}<br />
@@ -188,7 +190,7 @@ class Utils {
188
190
  }
189
191
 
190
192
  static renderError(error) {
191
- return (<span><strong>[{error.constructor.name}]</strong> {error.message}</span>);
193
+ return (<div style={{ maxWidth: '180px' }}><strong>[{error.constructor.name}]</strong><br />{error.message}</div>);
192
194
  }
193
195
 
194
196
  static renderFromStack(providersStack) {
@@ -0,0 +1,128 @@
1
+ import noop from 'lodash.noop';
2
+ import React from 'react';
3
+
4
+ import { AbsoluteHeading } from '@wemap/geo';
5
+ import {
6
+ deg2rad, rad2deg
7
+ } from '@wemap/maths';
8
+ import { TimeUtils } from '@wemap/utils';
9
+
10
+ import {
11
+ ProvidersInterface, EventType
12
+ } from '../..';
13
+
14
+ const Orientations = [
15
+ {
16
+ name: 'QR Code Wemap (lvl 2)',
17
+ heading: 191.9
18
+ },
19
+ {
20
+ name: 'Gare de Lyon (RER-A)',
21
+ heading: 41.6
22
+ }
23
+ ];
24
+
25
+ const fps = 10;
26
+
27
+ class DetailsAttitudeComponent extends React.PureComponent {
28
+
29
+ attitude = null;
30
+ attitudeDirty = true;
31
+
32
+ componentDidMount() {
33
+
34
+ this.attitude = ProvidersInterface.getLastKnown(EventType.AbsoluteAttitude);
35
+
36
+ this.providersId = ProvidersInterface.addEventListener(
37
+ EventType.AbsoluteAttitude,
38
+ attitude => {
39
+ this.attitudeDirty = true;
40
+ this.attitude = attitude;
41
+ },
42
+ noop,
43
+ true
44
+ );
45
+
46
+ this.renderLoop();
47
+ }
48
+
49
+ componentWillUnmount() {
50
+ if (this.timeoutLoopId) {
51
+ clearTimeout(this.timeoutLoopId);
52
+ }
53
+ cancelAnimationFrame(this.renderLoopId);
54
+ ProvidersInterface.removeEventListener(this.providersId);
55
+ }
56
+
57
+ renderLoop = () => {
58
+ this.renderAttitude();
59
+ this.timeoutLoopId = setTimeout(() => {
60
+ this.timeoutLoopId = null;
61
+ this.renderLoopId = requestAnimationFrame(this.renderLoop);
62
+ }, 1000 / fps);
63
+ }
64
+
65
+ renderAttitude = () => {
66
+
67
+ if (!this.attitudeDirty) {
68
+ return;
69
+ }
70
+
71
+ const attitude = this.attitude;
72
+ if (attitude) {
73
+ const q = attitude.quaternion;
74
+ this.refs.quaternion.innerHTML = `[${q[0].toFixed(3)}, ${q[1].toFixed(3)}, ${q[2].toFixed(3)}, ${q[3].toFixed(3)}]`;
75
+
76
+ const euler = attitude.eulerAnglesDegrees;
77
+ this.refs.euler.innerHTML = `[${euler[0].toFixed(2)}°, ${euler[1].toFixed(2)}°, ${euler[2].toFixed(2)}°]`;
78
+
79
+ this.refs.heading.innerHTML = `${attitude.headingDegrees.toFixed(2)}°`;
80
+
81
+ this.refs.accuracy.innerHTML = `${rad2deg(attitude.accuracy).toFixed(1)}°`;
82
+ this.refs.time.innerHTML = `${attitude.time.toFixed(2)}s`;
83
+ }
84
+
85
+ this.attitudeDirty = false;
86
+ }
87
+
88
+ render() {
89
+ return (
90
+ <div>
91
+ <div className="title">Attitude</div>
92
+ <p>
93
+ Quat: <span ref='quaternion'></span><br />
94
+ Euler: <span ref='euler'></span><br />
95
+ Heading: <span ref='heading'></span><br />
96
+ Accuracy: <span ref='accuracy'></span><br />
97
+ Time: <span ref='time'></span>
98
+ </p>
99
+ <div>
100
+ <select ref='select'>
101
+ {Orientations.map((option, index) =>
102
+ <option key={index}
103
+ value={index}>
104
+ {option.name}
105
+ </option>
106
+ )}
107
+ </select>
108
+ <button
109
+ style={{ marginLeft: '5px' }}
110
+ onClick={() => this.handleForceOrientation()}>
111
+ Force
112
+ </button>
113
+ </div>
114
+ </div>
115
+ );
116
+ }
117
+
118
+ handleForceOrientation() {
119
+ const heading = new AbsoluteHeading(
120
+ deg2rad(Orientations[this.refs.select.value].heading),
121
+ TimeUtils.preciseTime / 1e3,
122
+ 0
123
+ );
124
+ ProvidersInterface.feed(EventType.AbsoluteHeading, heading);
125
+ }
126
+ }
127
+
128
+ export default DetailsAttitudeComponent;
@@ -0,0 +1,32 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+
4
+ import '../Common.css';
5
+ import MapHandler from '../map/MapHandler';
6
+ import DetailsPositionComponent from './DetailsPositionComponent';
7
+ import DetailsAttitudeComponent from './DetailsAttitudeComponent';
8
+ import ItineraryComponent from './ItineraryComponent';
9
+
10
+
11
+ class DetailsComponent extends React.Component {
12
+
13
+ static propTypes = { mapHandler: PropTypes.instanceOf(MapHandler) };
14
+
15
+ render() {
16
+
17
+ return (
18
+ <>
19
+
20
+ <DetailsPositionComponent />
21
+
22
+ <DetailsAttitudeComponent />
23
+
24
+ <ItineraryComponent mapHandler={this.props.mapHandler} />
25
+
26
+ </>
27
+ );
28
+ }
29
+
30
+ }
31
+
32
+ export default DetailsComponent;
@@ -0,0 +1,135 @@
1
+ import isNumber from 'lodash.isnumber';
2
+ import noop from 'lodash.noop';
3
+ import React from 'react';
4
+
5
+ import {
6
+ Level, UserPosition
7
+ } from '@wemap/geo';
8
+ import { rad2deg } from '@wemap/maths';
9
+ import { TimeUtils } from '@wemap/utils';
10
+
11
+ import {
12
+ ProvidersInterface, EventType
13
+ } from '../..';
14
+
15
+ import Utils from '../components/Utils';
16
+
17
+
18
+ const NOT_AVAILABLE_STR = Utils.NOT_AVAILABLE_STR;
19
+
20
+ const Positions = [
21
+ {
22
+ name: 'Wemap (outdoor)',
23
+ coords: new UserPosition(43.6091955, 3.8841255, 1.5)
24
+ },
25
+ {
26
+ name: 'QR Code Wemap (lvl 2)',
27
+ coords: new UserPosition(43.6091812, 3.8841376, 1.5, new Level(2))
28
+ },
29
+ {
30
+ name: 'Gare de Lyon (RER-A)',
31
+ coords: new UserPosition(48.8442365, 2.3728267, 1.5, new Level(-2))
32
+ }
33
+ ];
34
+
35
+ const fps = 10;
36
+
37
+ class DetailsPositionComponent extends React.PureComponent {
38
+
39
+ position = null;
40
+ positionDirty = true;
41
+
42
+ componentDidMount() {
43
+
44
+ this.position = ProvidersInterface.getLastKnown(EventType.AbsolutePosition);
45
+
46
+ this.providersId = ProvidersInterface.addEventListener(
47
+ EventType.AbsolutePosition,
48
+ position => {
49
+ this.positionDirty = true;
50
+ this.position = position;
51
+ },
52
+ noop,
53
+ true
54
+ );
55
+
56
+ this.renderLoop();
57
+ }
58
+
59
+ componentWillUnmount() {
60
+ if (this.timeoutLoopId) {
61
+ clearTimeout(this.timeoutLoopId);
62
+ }
63
+ cancelAnimationFrame(this.renderLoopId);
64
+ ProvidersInterface.removeEventListener(this.providersId);
65
+ }
66
+
67
+ renderLoop = () => {
68
+ this.renderPosition();
69
+ this.timeoutLoopId = setTimeout(() => {
70
+ this.timeoutLoopId = null;
71
+ this.renderLoopId = requestAnimationFrame(this.renderLoop);
72
+ }, 1000 / fps);
73
+ }
74
+
75
+ renderPosition = () => {
76
+
77
+ if (!this.positionDirty) {
78
+ return;
79
+ }
80
+
81
+ const position = this.position;
82
+ if (position) {
83
+ this.refs.latitude.innerHTML = `${position.lat.toFixed(7)}°`;
84
+ this.refs.longitude.innerHTML = `${position.lng.toFixed(7)}°`;
85
+ this.refs.altitude.innerHTML = position.alt ? `${position.alt.toFixed(2)}m` : NOT_AVAILABLE_STR;
86
+ this.refs.level.innerHTML = position.level ? position.level.toString() : NOT_AVAILABLE_STR;
87
+ this.refs.bearing.innerHTML = isNumber(position.bearing) ? `${rad2deg(position.bearing).toFixed(2)}°` : NOT_AVAILABLE_STR;
88
+ this.refs.accuracy.innerHTML = `${position.accuracy.toFixed(2)}m`;
89
+ this.refs.time.innerHTML = `${position.time.toFixed(2)}s`;
90
+ }
91
+
92
+ this.positionDirty = false;
93
+ }
94
+
95
+ render() {
96
+ return (
97
+ <div>
98
+ <div className="title">Position</div>
99
+ <p>
100
+ Latitude: <span ref='latitude'></span><br />
101
+ Longitude: <span ref='longitude'></span><br />
102
+ Altitude: <span ref='altitude'></span><br />
103
+ Level: <span ref='level'></span><br />
104
+ Bearing: <span ref='bearing'></span><br />
105
+ Accuracy: <span ref='accuracy'></span><br />
106
+ Time: <span ref='time'></span>
107
+ </p>
108
+ <div>
109
+ <select ref='select'>
110
+ {Positions.map((option, index) =>
111
+ <option key={index}
112
+ value={index}>
113
+ {option.name}
114
+ </option>
115
+ )}
116
+ </select>
117
+ <button
118
+ style={{ marginLeft: '5px' }}
119
+ onClick={() => this.handleForcePosition()}>
120
+ Force
121
+ </button>
122
+ </div>
123
+ </div>
124
+ );
125
+ }
126
+
127
+ handleForcePosition() {
128
+ const position = Positions[this.refs.select.value].coords.clone();
129
+ position.time = TimeUtils.preciseTime / 1e3;
130
+ position.accuracy = 0;
131
+ ProvidersInterface.feed(EventType.AbsolutePosition, position);
132
+ }
133
+ }
134
+
135
+ export default DetailsPositionComponent;