mobility-toolbox-js 3.0.0-beta.2 → 3.0.0-beta.21
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/api/HttpAPI.d.ts +20 -0
- package/api/HttpAPI.js +0 -11
- package/api/RealtimeAPI.d.ts +404 -0
- package/api/RealtimeAPI.js +342 -276
- package/api/RoutingAPI.d.ts +47 -0
- package/api/RoutingAPI.js +17 -7
- package/api/StopsAPI.d.ts +44 -0
- package/api/StopsAPI.js +16 -10
- package/api/WebSocketAPI.d.ts +147 -0
- package/api/WebSocketAPI.js +164 -164
- package/api/index.d.ts +3 -0
- package/api/index.js +1 -1
- package/api/typedefs.d.ts +76 -0
- package/api/typedefs.js +27 -42
- package/common/controls/StopFinderControlCommon.d.ts +53 -0
- package/common/controls/StopFinderControlCommon.js +31 -31
- package/common/index.d.ts +2 -0
- package/common/index.js +1 -1
- package/common/mixins/RealtimeLayerMixin.d.ts +267 -0
- package/common/mixins/RealtimeLayerMixin.js +401 -393
- package/common/styles/index.d.ts +4 -0
- package/common/styles/realtimeDefaultStyle.d.ts +36 -0
- package/common/styles/realtimeDefaultStyle.js +6 -6
- package/common/styles/realtimeDelayStyle.d.ts +12 -0
- package/common/styles/realtimeHeadingStyle.d.ts +12 -0
- package/common/styles/realtimeHeadingStyle.js +5 -5
- package/common/styles/realtimeSimpleStyle.d.ts +4 -0
- package/common/typedefs.d.ts +219 -0
- package/common/typedefs.js +7 -1
- package/common/utils/compareDepartures.d.ts +10 -0
- package/common/utils/compareDepartures.js +2 -2
- package/common/utils/constants.d.ts +5 -0
- package/common/utils/createCanvas.d.ts +10 -0
- package/common/utils/createDefaultCopyrightElt.d.ts +5 -0
- package/common/utils/createDefaultStopFinderElt.d.ts +5 -0
- package/common/utils/createRealtimeFilters.d.ts +12 -0
- package/common/utils/debounceDeparturesMessages.d.ts +12 -0
- package/common/utils/debounceWebsocketMessages.d.ts +11 -0
- package/common/utils/getLayersAsFlatArray.d.ts +3 -0
- package/common/utils/getLayersAsFlatArray.js +5 -1
- package/common/utils/getMapGlCopyrights.d.ts +17 -0
- package/common/utils/getMapGlCopyrights.js +3 -3
- package/common/utils/getRealtimeModeSuffix.d.ts +10 -0
- package/common/utils/getRealtimeModeSuffix.js +1 -0
- package/common/utils/getUrlWithParams.d.ts +8 -0
- package/common/utils/getVehiclePosition.d.ts +17 -0
- package/common/utils/getVehiclePosition.js +9 -3
- package/common/utils/index.d.ts +16 -0
- package/common/utils/realtimeConfig.d.ts +64 -0
- package/common/utils/removeDuplicate.d.ts +9 -0
- package/common/utils/renderTrajectories.d.ts +16 -0
- package/common/utils/renderTrajectories.js +6 -6
- package/common/utils/sortAndFilterDepartures.d.ts +15 -0
- package/common/utils/sortAndFilterDepartures.js +1 -1
- package/common/utils/sortByDelay.d.ts +3 -0
- package/common/utils/sortByDelay.js +5 -1
- package/common/utils/timeUtils.d.ts +23 -0
- package/common/utils/toMercatorExtent.d.ts +5 -0
- package/iife.d.ts +2 -0
- package/index.d.ts +9 -0
- package/maplibre/controls/CopyrightControl.d.ts +35 -0
- package/maplibre/controls/index.d.ts +1 -0
- package/maplibre/index.d.ts +5 -0
- package/maplibre/layers/Layer.d.ts +28 -0
- package/maplibre/layers/Layer.js +1 -1
- package/maplibre/layers/RealtimeLayer.d.ts +181 -0
- package/maplibre/layers/RealtimeLayer.js +29 -5
- package/maplibre/layers/index.d.ts +2 -0
- package/maplibre/utils/getMercatorResolution.d.ts +7 -0
- package/maplibre/utils/getSourceCoordinates.d.ts +7 -0
- package/maplibre/utils/getSourceCoordinates.js +5 -5
- package/maplibre/utils/index.d.ts +2 -0
- package/mbt.js +22103 -14430
- package/mbt.js.map +4 -4
- package/mbt.min.js +61 -58
- package/mbt.min.js.map +4 -4
- package/ol/controls/CopyrightControl.d.ts +31 -0
- package/ol/controls/CopyrightControl.js +18 -8
- package/ol/controls/RoutingControl.d.ts +202 -0
- package/ol/controls/RoutingControl.js +220 -219
- package/ol/controls/StopFinderControl.d.ts +37 -0
- package/ol/controls/StopFinderControl.js +4 -1
- package/ol/controls/index.d.ts +3 -0
- package/ol/index.d.ts +7 -0
- package/ol/index.js +1 -0
- package/ol/layers/Layer.d.ts +101 -0
- package/ol/layers/Layer.js +25 -0
- package/ol/layers/MaplibreLayer.d.ts +160 -0
- package/ol/layers/MaplibreLayer.js +97 -27
- package/ol/layers/MaplibreStyleLayer.d.ts +237 -0
- package/ol/layers/MaplibreStyleLayer.js +291 -267
- package/ol/layers/RealtimeLayer.d.ts +283 -0
- package/ol/layers/RealtimeLayer.js +143 -128
- package/ol/layers/VectorLayer.d.ts +18 -0
- package/ol/layers/VectorLayer.js +31 -0
- package/ol/layers/index.d.ts +5 -0
- package/ol/layers/index.js +3 -0
- package/ol/mixins/MobilityLayerMixin.d.ts +96 -0
- package/ol/mixins/MobilityLayerMixin.js +1 -4
- package/ol/mixins/PropertiesLayerMixin.d.ts +135 -0
- package/ol/mixins/PropertiesLayerMixin.js +112 -140
- package/ol/mixins/index.d.ts +1 -0
- package/ol/mixins/index.js +2 -0
- package/ol/renderers/MaplibreLayerRenderer.d.ts +0 -0
- package/ol/renderers/MaplibreLayerRenderer.js +142 -114
- package/ol/renderers/MaplibreStyleLayerRenderer.d.ts +20 -0
- package/ol/renderers/MaplibreStyleLayerRenderer.js +20 -23
- package/ol/renderers/RealtimeLayerRenderer.d.ts +22 -0
- package/ol/renderers/RealtimeLayerRenderer.js +58 -53
- package/ol/styles/fullTrajectoryDelayStyle.d.ts +6 -0
- package/ol/styles/fullTrajectoryStyle.d.ts +5 -0
- package/ol/styles/index.d.ts +3 -0
- package/ol/styles/routingStyle.d.ts +4 -0
- package/ol/utils/getFeatureInfoAtCoordinate.d.ts +8 -0
- package/ol/utils/getFeatureInfoAtCoordinate.js +12 -18
- package/ol/utils/index.d.ts +1 -0
- package/package.json +31 -31
- package/setupTests.d.ts +1 -0
- package/setupTests.js +3 -4
- package/types/common.d.ts +55 -48
- package/types/index.d.ts +1 -1
- package/types/realtime.d.ts +91 -93
- package/types/routing.d.ts +60 -60
- package/types/stops.d.ts +62 -62
- package/ol/layers/MapGlLayer.js +0 -142
|
@@ -2,30 +2,34 @@
|
|
|
2
2
|
/* eslint-disable no-useless-constructor,@typescript-eslint/no-useless-constructor */
|
|
3
3
|
/* eslint-disable no-unused-vars,@typescript-eslint/no-unused-vars */
|
|
4
4
|
/* eslint-disable class-methods-use-this */
|
|
5
|
+
import debounce from 'lodash.debounce';
|
|
6
|
+
import throttle from 'lodash.throttle';
|
|
5
7
|
/* eslint-disable max-classes-per-file */
|
|
6
8
|
import { buffer, containsCoordinate, intersects } from 'ol/extent';
|
|
7
|
-
import { unByKey } from 'ol/Observable';
|
|
8
9
|
import GeoJSON from 'ol/format/GeoJSON';
|
|
9
|
-
import
|
|
10
|
-
import throttle from 'lodash.throttle';
|
|
10
|
+
import { unByKey } from 'ol/Observable';
|
|
11
11
|
import { fromLonLat } from 'ol/proj';
|
|
12
|
-
import realtimeDefaultStyle from '../styles/realtimeDefaultStyle';
|
|
13
12
|
import { RealtimeAPI, RealtimeModes } from '../../api';
|
|
14
|
-
import
|
|
13
|
+
import realtimeDefaultStyle from '../styles/realtimeDefaultStyle';
|
|
15
14
|
import * as realtimeConfig from '../utils/realtimeConfig';
|
|
15
|
+
import renderTrajectories from '../utils/renderTrajectories';
|
|
16
16
|
/**
|
|
17
17
|
* RealtimeLayerInterface.
|
|
18
18
|
* @private
|
|
19
19
|
*/
|
|
20
20
|
export class RealtimeLayerInterface {
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} id The vehicle identifier (the train_id property).
|
|
25
|
+
* @param {RealtimeMode} mode The mode to request. If not defined, the layer´s mode propetrty will be used.
|
|
26
|
+
* @return {Promise<{stopSequence: RealtimeStopSequence, fullTrajectory: RealtimeFullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
23
27
|
*/
|
|
24
|
-
|
|
28
|
+
getTrajectoryInfos(id, mode) { }
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
30
|
+
* Render the trajectories
|
|
27
31
|
*/
|
|
28
|
-
|
|
32
|
+
renderTrajectories() { }
|
|
29
33
|
/**
|
|
30
34
|
* Set the Realtime api's bbox.
|
|
31
35
|
*
|
|
@@ -34,17 +38,13 @@ export class RealtimeLayerInterface {
|
|
|
34
38
|
*/
|
|
35
39
|
setBbox(extent, zoom) { }
|
|
36
40
|
/**
|
|
37
|
-
*
|
|
41
|
+
* Start the clock.
|
|
38
42
|
*/
|
|
39
|
-
|
|
43
|
+
start() { }
|
|
40
44
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @param {string} id The vehicle identifier (the train_id property).
|
|
44
|
-
* @param {RealtimeMode} mode The mode to request. If not defined, the layer´s mode propetrty will be used.
|
|
45
|
-
* @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
45
|
+
* Stop the clock.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
stop() { }
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Mixin for RealtimeLayerInterface.
|
|
@@ -54,7 +54,7 @@ export class RealtimeLayerInterface {
|
|
|
54
54
|
* @private
|
|
55
55
|
*/
|
|
56
56
|
function RealtimeLayerMixin(Base) {
|
|
57
|
-
// @ts-
|
|
57
|
+
// @ts-expect-error
|
|
58
58
|
return class Mixin extends Base {
|
|
59
59
|
constructor(options) {
|
|
60
60
|
super(Object.assign({ hitTolerance: 10 }, options));
|
|
@@ -110,7 +110,7 @@ function RealtimeLayerMixin(Base) {
|
|
|
110
110
|
this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;
|
|
111
111
|
// Define throttling and debounce render function
|
|
112
112
|
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });
|
|
113
|
-
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true,
|
|
113
|
+
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true, maxWait: 5000, trailing: true });
|
|
114
114
|
// Bind callbacks
|
|
115
115
|
// this.onFeatureHover = this.onFeatureHover.bind(this);
|
|
116
116
|
// this.onFeatureClick = this.onFeatureClick.bind(this);
|
|
@@ -122,6 +122,28 @@ function RealtimeLayerMixin(Base) {
|
|
|
122
122
|
this.onDocumentVisibilityChange =
|
|
123
123
|
this.onDocumentVisibilityChange.bind(this);
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Add a trajectory.
|
|
127
|
+
* @param {RealtimeTrajectory} trajectory The trajectory to add.
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
addTrajectory(trajectory) {
|
|
131
|
+
if (!this.trajectories) {
|
|
132
|
+
this.trajectories = {};
|
|
133
|
+
}
|
|
134
|
+
const id = trajectory.properties.train_id;
|
|
135
|
+
if (id !== undefined) {
|
|
136
|
+
this.trajectories[id] = trajectory;
|
|
137
|
+
}
|
|
138
|
+
// @ts-expect-error the parameter are set by subclasses
|
|
139
|
+
this.renderTrajectories();
|
|
140
|
+
}
|
|
141
|
+
attachToMap(map) {
|
|
142
|
+
super.attachToMap(map);
|
|
143
|
+
// To avoid browser hanging when the tab is not visible for a certain amount of time,
|
|
144
|
+
// We stop the rendering and the websocket when hide and start again when show.
|
|
145
|
+
document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
146
|
+
}
|
|
125
147
|
/**
|
|
126
148
|
* Define layer's properties.
|
|
127
149
|
*
|
|
@@ -129,14 +151,20 @@ function RealtimeLayerMixin(Base) {
|
|
|
129
151
|
*/
|
|
130
152
|
defineProperties(options) {
|
|
131
153
|
(super.defineProperties || (() => { }))(options);
|
|
132
|
-
const {
|
|
154
|
+
const { bboxParameters, canvas, filter, hoverVehicleId, live, mode, pixelRatio, selectedVehicleId, sort, speed, style, styleOptions, time, } = options;
|
|
133
155
|
let currCanvas = canvas;
|
|
134
156
|
let currSpeed = speed || 1;
|
|
135
157
|
let currTime = time || new Date();
|
|
136
158
|
let currMode = mode || RealtimeModes.TOPOGRAPHIC;
|
|
137
159
|
let currStyle = style || realtimeDefaultStyle;
|
|
138
160
|
Object.defineProperties(this, {
|
|
139
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Custom parameters to send on each BBOX request.
|
|
163
|
+
*/
|
|
164
|
+
bboxParameters: {
|
|
165
|
+
value: bboxParameters,
|
|
166
|
+
writable: true,
|
|
167
|
+
},
|
|
140
168
|
canvas: {
|
|
141
169
|
get: () => {
|
|
142
170
|
if (!currCanvas) {
|
|
@@ -148,6 +176,29 @@ function RealtimeLayerMixin(Base) {
|
|
|
148
176
|
currCanvas = cnvas;
|
|
149
177
|
},
|
|
150
178
|
},
|
|
179
|
+
/**
|
|
180
|
+
* Function to filter which vehicles to display.
|
|
181
|
+
*/
|
|
182
|
+
filter: {
|
|
183
|
+
value: filter,
|
|
184
|
+
writable: true,
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* Id of the hovered vehicle.
|
|
188
|
+
*/
|
|
189
|
+
hoverVehicleId: {
|
|
190
|
+
value: hoverVehicleId,
|
|
191
|
+
writable: true,
|
|
192
|
+
},
|
|
193
|
+
isTrackerLayer: { value: true },
|
|
194
|
+
/**
|
|
195
|
+
* If true. The layer will always use Date.now() on the next tick to render the trajectories.
|
|
196
|
+
* When true, setting the time property has no effect.
|
|
197
|
+
*/
|
|
198
|
+
live: {
|
|
199
|
+
value: live === false ? live : true,
|
|
200
|
+
writable: true,
|
|
201
|
+
},
|
|
151
202
|
/**
|
|
152
203
|
* Style function used to render a vehicle.
|
|
153
204
|
*/
|
|
@@ -166,21 +217,26 @@ function RealtimeLayerMixin(Base) {
|
|
|
166
217
|
},
|
|
167
218
|
},
|
|
168
219
|
/**
|
|
169
|
-
*
|
|
220
|
+
* Id of the selected vehicle.
|
|
170
221
|
*/
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// @ts-ignore function without parameters is defined in subclasses
|
|
176
|
-
this.renderTrajectories();
|
|
177
|
-
},
|
|
222
|
+
pixelRatio: {
|
|
223
|
+
value: pixelRatio ||
|
|
224
|
+
(typeof window !== 'undefined' ? window.devicePixelRatio : 1),
|
|
225
|
+
writable: true,
|
|
178
226
|
},
|
|
179
227
|
/**
|
|
180
|
-
*
|
|
228
|
+
* Id of the selected vehicle.
|
|
181
229
|
*/
|
|
182
|
-
|
|
183
|
-
value:
|
|
230
|
+
selectedVehicleId: {
|
|
231
|
+
value: selectedVehicleId,
|
|
232
|
+
writable: true,
|
|
233
|
+
},
|
|
234
|
+
/**
|
|
235
|
+
* Function to sort the vehicles to display.
|
|
236
|
+
*/
|
|
237
|
+
sort: {
|
|
238
|
+
value: sort,
|
|
239
|
+
writable: true,
|
|
184
240
|
},
|
|
185
241
|
/**
|
|
186
242
|
* Speed of the wheel of time.
|
|
@@ -194,33 +250,21 @@ function RealtimeLayerMixin(Base) {
|
|
|
194
250
|
},
|
|
195
251
|
},
|
|
196
252
|
/**
|
|
197
|
-
*
|
|
198
|
-
*/
|
|
199
|
-
bboxParameters: {
|
|
200
|
-
value: bboxParameters,
|
|
201
|
-
writable: true,
|
|
202
|
-
},
|
|
203
|
-
/**
|
|
204
|
-
* Function to filter which vehicles to display.
|
|
205
|
-
*/
|
|
206
|
-
filter: {
|
|
207
|
-
value: filter,
|
|
208
|
-
writable: true,
|
|
209
|
-
},
|
|
210
|
-
/**
|
|
211
|
-
* Function to sort the vehicles to display.
|
|
253
|
+
* Style function used to render a vehicle.
|
|
212
254
|
*/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
255
|
+
style: {
|
|
256
|
+
get: () => currStyle,
|
|
257
|
+
set: (newStyle) => {
|
|
258
|
+
currStyle = newStyle;
|
|
259
|
+
// @ts-expect-error function without parameters is defined in subclasses
|
|
260
|
+
this.renderTrajectories();
|
|
261
|
+
},
|
|
216
262
|
},
|
|
217
263
|
/**
|
|
218
|
-
*
|
|
219
|
-
* When true, setting the time property has no effect.
|
|
264
|
+
* Custom options to pass as last parameter of the style function.
|
|
220
265
|
*/
|
|
221
|
-
|
|
222
|
-
value:
|
|
223
|
-
writable: true,
|
|
266
|
+
styleOptions: {
|
|
267
|
+
value: Object.assign(Object.assign({}, realtimeConfig), (styleOptions || {})),
|
|
224
268
|
},
|
|
225
269
|
/**
|
|
226
270
|
* Time used to display the trajectories. Can be a Date or a number in ms representing a Date.
|
|
@@ -229,8 +273,8 @@ function RealtimeLayerMixin(Base) {
|
|
|
229
273
|
time: {
|
|
230
274
|
get: () => currTime,
|
|
231
275
|
set: (newTime) => {
|
|
232
|
-
currTime = newTime
|
|
233
|
-
// @ts-
|
|
276
|
+
currTime = (newTime === null || newTime === void 0 ? void 0 : newTime.getTime) ? newTime : new Date(newTime);
|
|
277
|
+
// @ts-expect-error function without parameters is defined in subclasses
|
|
234
278
|
this.renderTrajectories();
|
|
235
279
|
},
|
|
236
280
|
},
|
|
@@ -242,25 +286,10 @@ function RealtimeLayerMixin(Base) {
|
|
|
242
286
|
writable: true,
|
|
243
287
|
},
|
|
244
288
|
/**
|
|
245
|
-
*
|
|
246
|
-
*/
|
|
247
|
-
hoverVehicleId: {
|
|
248
|
-
value: hoverVehicleId,
|
|
249
|
-
writable: true,
|
|
250
|
-
},
|
|
251
|
-
/**
|
|
252
|
-
* Id of the selected vehicle.
|
|
253
|
-
*/
|
|
254
|
-
selectedVehicleId: {
|
|
255
|
-
value: selectedVehicleId,
|
|
256
|
-
writable: true,
|
|
257
|
-
},
|
|
258
|
-
/**
|
|
259
|
-
* Id of the selected vehicle.
|
|
289
|
+
* If true, encapsulates the renderTrajectories calls in a debounce function.
|
|
260
290
|
*/
|
|
261
|
-
|
|
262
|
-
value:
|
|
263
|
-
(typeof window !== 'undefined' ? window.devicePixelRatio : 1),
|
|
291
|
+
useDebounce: {
|
|
292
|
+
value: options.useDebounce || false,
|
|
264
293
|
writable: true,
|
|
265
294
|
},
|
|
266
295
|
/**
|
|
@@ -277,13 +306,6 @@ function RealtimeLayerMixin(Base) {
|
|
|
277
306
|
value: options.useThrottle !== false,
|
|
278
307
|
writable: true,
|
|
279
308
|
},
|
|
280
|
-
/**
|
|
281
|
-
* If true, encapsulates the renderTrajectories calls in a debounce function.
|
|
282
|
-
*/
|
|
283
|
-
useDebounce: {
|
|
284
|
-
value: options.useDebounce || false,
|
|
285
|
-
writable: true,
|
|
286
|
-
},
|
|
287
309
|
/**
|
|
288
310
|
* Debug properties.
|
|
289
311
|
*/
|
|
@@ -297,12 +319,6 @@ function RealtimeLayerMixin(Base) {
|
|
|
297
319
|
// },
|
|
298
320
|
});
|
|
299
321
|
}
|
|
300
|
-
attachToMap(map) {
|
|
301
|
-
super.attachToMap(map);
|
|
302
|
-
// To avoid browser hanging when the tab is not visible for a certain amount of time,
|
|
303
|
-
// We stop the rendering and the websocket when hide and start again when show.
|
|
304
|
-
document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
305
|
-
}
|
|
306
322
|
detachFromMap() {
|
|
307
323
|
document.removeEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
308
324
|
this.stop();
|
|
@@ -315,99 +331,231 @@ function RealtimeLayerMixin(Base) {
|
|
|
315
331
|
super.detachFromMap();
|
|
316
332
|
}
|
|
317
333
|
}
|
|
318
|
-
start() {
|
|
319
|
-
this.stop();
|
|
320
|
-
// Before starting to update trajectories, we remove trajectories that have
|
|
321
|
-
// a time_intervals in the past, it will
|
|
322
|
-
// avoid phantom train that are at the end of their route because we never
|
|
323
|
-
// received the deleted_vehicle event because we have changed the browser tab.
|
|
324
|
-
this.purgeOutOfDateTrajectories();
|
|
325
|
-
// @ts-ignore function without parameters must be define in subclasses
|
|
326
|
-
this.renderTrajectories();
|
|
327
|
-
this.startUpdateTime();
|
|
328
|
-
this.api.open();
|
|
329
|
-
this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);
|
|
330
|
-
this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);
|
|
331
|
-
if (this.isUpdateBboxOnMoveEnd) {
|
|
332
|
-
// Update the bbox on each move end
|
|
333
|
-
// @ts-ignore function without parameters defined by subclasses
|
|
334
|
-
this.setBbox();
|
|
335
|
-
}
|
|
336
|
-
if (this.onStart) {
|
|
337
|
-
this.onStart(this);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
334
|
/**
|
|
341
|
-
*
|
|
342
|
-
*
|
|
335
|
+
* Request feature information for a given coordinate.
|
|
336
|
+
*
|
|
337
|
+
* @param {ol/coordinate~Coordinate} coordinate Coordinate.
|
|
338
|
+
* @param {Object} options Options See child classes to see which options are supported.
|
|
339
|
+
* @param {number} [options.resolution=1] The resolution of the map.
|
|
340
|
+
* @param {number} [options.nb=Infinity] The max number of vehicles to return.
|
|
341
|
+
* @return {Promise<FeatureInfo>} Promise with features, layer and coordinate.
|
|
343
342
|
*/
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
343
|
+
getFeatureInfoAtCoordinate(coordinate, options) {
|
|
344
|
+
const { nb, resolution } = options;
|
|
345
|
+
const ext = buffer([...coordinate, ...coordinate], this.hitTolerance * resolution);
|
|
346
|
+
let trajectories = Object.values(this.trajectories || {});
|
|
347
|
+
if (this.sort) {
|
|
348
|
+
// @ts-expect-error good type must be defined
|
|
349
|
+
trajectories = trajectories.sort(this.sort);
|
|
350
|
+
}
|
|
351
|
+
const vehicles = [];
|
|
352
|
+
for (let i = 0; i < trajectories.length; i += 1) {
|
|
353
|
+
// @ts-expect-error coordinate is added by the RealtimeLayer
|
|
354
|
+
const { coordinate: trajcoord } = trajectories[i].properties;
|
|
355
|
+
if (trajcoord && containsCoordinate(ext, trajcoord)) {
|
|
356
|
+
vehicles.push(trajectories[i]);
|
|
351
357
|
}
|
|
352
|
-
|
|
353
|
-
|
|
358
|
+
if (vehicles.length === nb) {
|
|
359
|
+
break;
|
|
354
360
|
}
|
|
355
|
-
}, this.updateTimeDelay);
|
|
356
|
-
}
|
|
357
|
-
stop() {
|
|
358
|
-
this.api.unsubscribeTrajectory(this.onTrajectoryMessage);
|
|
359
|
-
this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);
|
|
360
|
-
this.api.close();
|
|
361
|
-
if (this.onStop) {
|
|
362
|
-
this.onStop(this);
|
|
363
361
|
}
|
|
362
|
+
return Promise.resolve({
|
|
363
|
+
coordinate,
|
|
364
|
+
features: vehicles.map((vehicle) => this.format.readFeature(vehicle)),
|
|
365
|
+
layer: this,
|
|
366
|
+
});
|
|
364
367
|
}
|
|
365
368
|
/**
|
|
366
|
-
*
|
|
369
|
+
* Get the duration before the next update depending on zoom level.
|
|
370
|
+
*
|
|
367
371
|
* @private
|
|
372
|
+
* @param {number} zoom
|
|
368
373
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
374
|
+
getRefreshTimeInMs(zoom = 0) {
|
|
375
|
+
var _a;
|
|
376
|
+
const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;
|
|
377
|
+
const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;
|
|
378
|
+
const nextTick = Math.max(25, timeStep / (this.speed || 1));
|
|
379
|
+
const nextThrottleTick = Math.min(nextTick, 500);
|
|
380
|
+
// TODO: see if this should go elsewhere.
|
|
381
|
+
if (this.useThrottle) {
|
|
382
|
+
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });
|
|
373
383
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
384
|
+
else if (this.useDebounce) {
|
|
385
|
+
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, maxWait: 5000, trailing: true });
|
|
386
|
+
}
|
|
387
|
+
if ((_a = this.api) === null || _a === void 0 ? void 0 : _a.buffer) {
|
|
388
|
+
const [, size] = this.api.buffer;
|
|
389
|
+
this.api.buffer = [nextThrottleTick, size];
|
|
390
|
+
}
|
|
391
|
+
return nextTick;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
395
|
+
*
|
|
396
|
+
* @param {string} id The vehicle identifier (the train_id property).
|
|
397
|
+
* @return {Promise<{stopSequence: RealtimeStopSequence, fullTrajectory: RealtimeFullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
398
|
+
*/
|
|
399
|
+
getTrajectoryInfos(id) {
|
|
400
|
+
var _a, _b;
|
|
401
|
+
// When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
402
|
+
// Then we combine them in one response and send them to inherited layers.
|
|
403
|
+
const promises = [
|
|
404
|
+
this.api.getStopSequence(id),
|
|
405
|
+
this.api.getFullTrajectory(id, this.mode, this.getGeneralizationLevelByZoom(Math.floor(((_b = (_a = this.map) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom()) || 0))),
|
|
406
|
+
];
|
|
407
|
+
return Promise.all(promises).then(([stopSequence, fullTrajectory]) => {
|
|
408
|
+
const response = {
|
|
409
|
+
fullTrajectory,
|
|
410
|
+
stopSequence,
|
|
411
|
+
};
|
|
412
|
+
return response;
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Get vehicle.
|
|
417
|
+
* @param {function} filterFc A function use to filter results.
|
|
418
|
+
* @return {Array<Object>} Array of vehicle.
|
|
419
|
+
*/
|
|
420
|
+
getVehicle(filterFc) {
|
|
421
|
+
return ((this.trajectories &&
|
|
422
|
+
// @ts-expect-error good type must be defined
|
|
423
|
+
Object.values(this.trajectories).filter(filterFc)) ||
|
|
424
|
+
[]);
|
|
425
|
+
}
|
|
426
|
+
highlightVehicle(id) {
|
|
427
|
+
if (this.hoverVehicleId !== id) {
|
|
428
|
+
/** @private */
|
|
429
|
+
this.hoverVehicleId = id;
|
|
430
|
+
// @ts-expect-error good type must be defined
|
|
431
|
+
this.renderTrajectories(true);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Callback on websocket's deleted_vehicles channel events.
|
|
436
|
+
* It removes the trajectory from the list.
|
|
437
|
+
*
|
|
387
438
|
* @private
|
|
439
|
+
* @override
|
|
388
440
|
*/
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
return false;
|
|
441
|
+
onDeleteTrajectoryMessage(data) {
|
|
442
|
+
if (!data.content) {
|
|
443
|
+
return;
|
|
393
444
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
445
|
+
this.removeTrajectory(data.content);
|
|
446
|
+
}
|
|
447
|
+
onDocumentVisibilityChange() {
|
|
448
|
+
if (document.hidden) {
|
|
449
|
+
this.stop();
|
|
450
|
+
// Since we don't receive deleted_vehicles event when docuement
|
|
451
|
+
// is hidden. We have to clean all the trajectories for a fresh
|
|
452
|
+
// start when the document is visible again.
|
|
453
|
+
this.trajectories = {};
|
|
400
454
|
}
|
|
401
|
-
|
|
402
|
-
|
|
455
|
+
else {
|
|
456
|
+
if (this.getVisible() === false) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
this.start();
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Callback on websocket's trajectory channel events.
|
|
464
|
+
* It adds a trajectory to the list.
|
|
465
|
+
*
|
|
466
|
+
* @private
|
|
467
|
+
*/
|
|
468
|
+
onTrajectoryMessage(data) {
|
|
469
|
+
if (!data.content) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const trajectory = data.content;
|
|
473
|
+
const { geometry, properties: { raw_coordinates: rawCoordinates, time_since_update: timeSinceUpdate, train_id: id, }, } = trajectory;
|
|
474
|
+
// ignore old events [SBAHNM-97]
|
|
475
|
+
// @ts-expect-error can be undefined
|
|
476
|
+
if (timeSinceUpdate < 0) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
// console.time(`onTrajectoryMessage${data.content.properties.train_id}`);
|
|
480
|
+
// @ts-expect-error default value for extentand zoom are provided by subclasses
|
|
481
|
+
if (this.purgeTrajectory(trajectory)) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (this.debug &&
|
|
485
|
+
this.mode === RealtimeModes.TOPOGRAPHIC &&
|
|
486
|
+
rawCoordinates) {
|
|
487
|
+
// @ts-expect-error
|
|
488
|
+
trajectory.properties.olGeometry = this.format.readGeometry({
|
|
489
|
+
coordinates: fromLonLat(rawCoordinates, this.map.getView().getProjection()),
|
|
490
|
+
type: 'Point',
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
// @ts-expect-error
|
|
495
|
+
trajectory.properties.olGeometry = this.format.readGeometry(geometry);
|
|
496
|
+
}
|
|
497
|
+
// TODO Make sure the timeOffset is useful. May be we can remove it.
|
|
498
|
+
// @ts-expect-error
|
|
499
|
+
trajectory.properties.timeOffset = Date.now() - data.timestamp;
|
|
500
|
+
this.addTrajectory(trajectory);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* On zoomend we adjust the time interval of the update of vehicles positions.
|
|
504
|
+
*
|
|
505
|
+
* @param evt Event that triggered the function.
|
|
506
|
+
* @private
|
|
507
|
+
*/
|
|
508
|
+
onZoomEnd() {
|
|
509
|
+
this.startUpdateTime();
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Remove all trajectories that are in the past.
|
|
513
|
+
*/
|
|
514
|
+
purgeOutOfDateTrajectories() {
|
|
515
|
+
Object.entries(this.trajectories || {}).forEach(([key, trajectory]) => {
|
|
516
|
+
var _a;
|
|
517
|
+
const timeIntervals = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.time_intervals;
|
|
518
|
+
if (this.time && (timeIntervals === null || timeIntervals === void 0 ? void 0 : timeIntervals.length)) {
|
|
519
|
+
const lastTimeInterval = timeIntervals[timeIntervals.length - 1][0];
|
|
520
|
+
if (lastTimeInterval < this.time.getTime()) {
|
|
521
|
+
this.removeTrajectory(key);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Determine if the trajectory is useless and should be removed from the list or not.
|
|
528
|
+
* By default, this function exclude vehicles:
|
|
529
|
+
* - that have their trajectory outside the current extent and
|
|
530
|
+
* - that aren't in the MOT list.
|
|
531
|
+
*
|
|
532
|
+
* @param {RealtimeTrajectory} trajectory
|
|
533
|
+
* @param {Array<number>} extent
|
|
534
|
+
* @param {number} zoom
|
|
535
|
+
* @return {boolean} if the trajectory must be displayed or not.
|
|
536
|
+
* @private
|
|
537
|
+
*/
|
|
538
|
+
purgeTrajectory(trajectory, extent, zoom) {
|
|
539
|
+
const { bounds, type } = trajectory.properties;
|
|
540
|
+
if ((this.isUpdateBboxOnMoveEnd && !intersects(extent, bounds)) ||
|
|
541
|
+
(this.mots && !this.mots.includes(type))) {
|
|
542
|
+
this.removeTrajectory(trajectory);
|
|
403
543
|
return true;
|
|
404
544
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
removeTrajectory(trajectoryOrId) {
|
|
548
|
+
var _a;
|
|
549
|
+
let id;
|
|
550
|
+
if (typeof trajectoryOrId !== 'string') {
|
|
551
|
+
id = (_a = trajectoryOrId === null || trajectoryOrId === void 0 ? void 0 : trajectoryOrId.properties) === null || _a === void 0 ? void 0 : _a.train_id;
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
id = trajectoryOrId;
|
|
555
|
+
}
|
|
556
|
+
if (id !== undefined && this.trajectories) {
|
|
557
|
+
delete this.trajectories[id];
|
|
558
|
+
}
|
|
411
559
|
}
|
|
412
560
|
/**
|
|
413
561
|
* Render the trajectories requesting an animation frame and cancelling the previous one.
|
|
@@ -447,6 +595,51 @@ function RealtimeLayerMixin(Base) {
|
|
|
447
595
|
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
448
596
|
}
|
|
449
597
|
}
|
|
598
|
+
/**
|
|
599
|
+
* Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.
|
|
600
|
+
*
|
|
601
|
+
* @param {object} viewState The view state of the map.
|
|
602
|
+
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
603
|
+
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
604
|
+
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
605
|
+
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
606
|
+
* @param {number} viewState.resolution Resolution of the map to render.
|
|
607
|
+
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
608
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
609
|
+
* during map navigation.
|
|
610
|
+
* @private
|
|
611
|
+
*/
|
|
612
|
+
renderTrajectoriesInternal(viewState, noInterpolate = false) {
|
|
613
|
+
var _a;
|
|
614
|
+
if (!this.map || !this.trajectories) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
const time = this.live ? Date.now() : (_a = this.time) === null || _a === void 0 ? void 0 : _a.getTime();
|
|
618
|
+
const trajectories = Object.values(this.trajectories);
|
|
619
|
+
// console.time('sort');
|
|
620
|
+
if (this.sort) {
|
|
621
|
+
// @ts-expect-error type problem
|
|
622
|
+
trajectories.sort(this.sort);
|
|
623
|
+
}
|
|
624
|
+
// console.timeEnd('sort');
|
|
625
|
+
if (!this.canvas || !this.style) {
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
// console.time('render');
|
|
629
|
+
this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time }), Object.assign({ filter: this.filter, hoverVehicleId: this.hoverVehicleId, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation
|
|
630
|
+
? true
|
|
631
|
+
: noInterpolate, selectedVehicleId: this.selectedVehicleId }, this.styleOptions));
|
|
632
|
+
// console.timeEnd('render');
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
selectVehicle(id) {
|
|
636
|
+
if (this.selectedVehicleId !== id) {
|
|
637
|
+
/** @private */
|
|
638
|
+
this.selectedVehicleId = id;
|
|
639
|
+
// @ts-expect-error
|
|
640
|
+
this.renderTrajectories(true);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
450
643
|
setBbox(extent, zoom) {
|
|
451
644
|
// Clean trajectories before sending the new bbox
|
|
452
645
|
// Purge trajectories:
|
|
@@ -473,9 +666,9 @@ function RealtimeLayerMixin(Base) {
|
|
|
473
666
|
zoomFloor,
|
|
474
667
|
];
|
|
475
668
|
/* @private */
|
|
476
|
-
|
|
669
|
+
this.generalizationLevel = this.getGeneralizationLevelByZoom(zoomFloor);
|
|
477
670
|
if (this.generalizationLevel) {
|
|
478
|
-
bbox.push(`gen=${generalizationLevel}`);
|
|
671
|
+
bbox.push(`gen=${this.generalizationLevel}`);
|
|
479
672
|
}
|
|
480
673
|
/* @private */
|
|
481
674
|
this.mots = this.getMotsByZoom(zoomFloor);
|
|
@@ -496,246 +689,61 @@ function RealtimeLayerMixin(Base) {
|
|
|
496
689
|
// Extent and zoom level are mandatory.
|
|
497
690
|
this.api.bbox = bbox;
|
|
498
691
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;
|
|
508
|
-
const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;
|
|
509
|
-
const nextTick = Math.max(25, timeStep / (this.speed || 1));
|
|
510
|
-
const nextThrottleTick = Math.min(nextTick, 500);
|
|
511
|
-
// TODO: see if this should go elsewhere.
|
|
512
|
-
if (this.useThrottle) {
|
|
513
|
-
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });
|
|
514
|
-
}
|
|
515
|
-
else if (this.useDebounce) {
|
|
516
|
-
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true, maxWait: 5000 });
|
|
517
|
-
}
|
|
518
|
-
if ((_a = this.api) === null || _a === void 0 ? void 0 : _a.buffer) {
|
|
519
|
-
const [, size] = this.api.buffer;
|
|
520
|
-
this.api.buffer = [nextThrottleTick, size];
|
|
521
|
-
}
|
|
522
|
-
return nextTick;
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Get vehicle.
|
|
526
|
-
* @param {function} filterFc A function use to filter results.
|
|
527
|
-
* @return {Array<Object>} Array of vehicle.
|
|
528
|
-
*/
|
|
529
|
-
getVehicle(filterFc) {
|
|
530
|
-
return ((this.trajectories &&
|
|
531
|
-
// @ts-ignore
|
|
532
|
-
Object.values(this.trajectories).filter(filterFc)) ||
|
|
533
|
-
[]);
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Request feature information for a given coordinate.
|
|
537
|
-
*
|
|
538
|
-
* @param {ol/coordinate~Coordinate} coordinate Coordinate.
|
|
539
|
-
* @param {Object} options Options See child classes to see which options are supported.
|
|
540
|
-
* @param {number} [options.resolution=1] The resolution of the map.
|
|
541
|
-
* @param {number} [options.nb=Infinity] The max number of vehicles to return.
|
|
542
|
-
* @return {Promise<FeatureInfo>} Promise with features, layer and coordinate.
|
|
543
|
-
*/
|
|
544
|
-
getFeatureInfoAtCoordinate(coordinate, options) {
|
|
545
|
-
const { resolution, nb } = options;
|
|
546
|
-
const ext = buffer([...coordinate, ...coordinate], this.hitTolerance * resolution);
|
|
547
|
-
let trajectories = Object.values(this.trajectories || {});
|
|
548
|
-
if (this.sort) {
|
|
549
|
-
// @ts-ignore
|
|
550
|
-
trajectories = trajectories.sort(this.sort);
|
|
551
|
-
}
|
|
552
|
-
const vehicles = [];
|
|
553
|
-
for (let i = 0; i < trajectories.length; i += 1) {
|
|
554
|
-
if (trajectories[i].properties.coordinate &&
|
|
555
|
-
containsCoordinate(ext, trajectories[i].properties.coordinate)) {
|
|
556
|
-
vehicles.push(trajectories[i]);
|
|
557
|
-
}
|
|
558
|
-
if (vehicles.length === nb) {
|
|
559
|
-
break;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return Promise.resolve({
|
|
563
|
-
layer: this,
|
|
564
|
-
features: vehicles,
|
|
565
|
-
coordinate,
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
570
|
-
*
|
|
571
|
-
* @param {string} id The vehicle identifier (the train_id property).
|
|
572
|
-
* @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
573
|
-
*/
|
|
574
|
-
getTrajectoryInfos(id) {
|
|
575
|
-
var _a, _b;
|
|
576
|
-
// When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
577
|
-
// Then we combine them in one response and send them to inherited layers.
|
|
578
|
-
const promises = [
|
|
579
|
-
this.api.getStopSequence(id),
|
|
580
|
-
this.api.getFullTrajectory(id, this.mode, this.getGeneralizationLevelByZoom(Math.floor(((_b = (_a = this.map) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom()) || 0))),
|
|
581
|
-
];
|
|
582
|
-
return Promise.all(promises).then(([stopSequence, fullTrajectory]) => {
|
|
583
|
-
const response = {
|
|
584
|
-
stopSequence,
|
|
585
|
-
fullTrajectory,
|
|
586
|
-
};
|
|
587
|
-
return response;
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Remove all trajectories that are in the past.
|
|
592
|
-
*/
|
|
593
|
-
purgeOutOfDateTrajectories() {
|
|
594
|
-
Object.entries(this.trajectories || {}).forEach(([key, trajectory]) => {
|
|
595
|
-
var _a;
|
|
596
|
-
const timeIntervals = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.time_intervals;
|
|
597
|
-
if (this.time && timeIntervals.length) {
|
|
598
|
-
const lastTimeInterval = timeIntervals[timeIntervals.length - 1][0];
|
|
599
|
-
if (lastTimeInterval < this.time) {
|
|
600
|
-
this.removeTrajectory(key);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Determine if the trajectory is useless and should be removed from the list or not.
|
|
607
|
-
* By default, this function exclude vehicles:
|
|
608
|
-
* - that have their trajectory outside the current extent and
|
|
609
|
-
* - that aren't in the MOT list.
|
|
610
|
-
*
|
|
611
|
-
* @param {RealtimeTrajectory} trajectory
|
|
612
|
-
* @param {Array<number>} extent
|
|
613
|
-
* @param {number} zoom
|
|
614
|
-
* @return {boolean} if the trajectory must be displayed or not.
|
|
615
|
-
* @private
|
|
616
|
-
*/
|
|
617
|
-
purgeTrajectory(trajectory, extent, zoom) {
|
|
618
|
-
const { type, bounds } = trajectory.properties;
|
|
619
|
-
if ((this.isUpdateBboxOnMoveEnd && !intersects(extent, bounds)) ||
|
|
620
|
-
(this.mots && !this.mots.includes(type))) {
|
|
621
|
-
this.removeTrajectory(trajectory);
|
|
622
|
-
return true;
|
|
623
|
-
}
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Add a trajectory.
|
|
628
|
-
* @param {RealtimeTrajectory} trajectory The trajectory to add.
|
|
629
|
-
* @private
|
|
630
|
-
*/
|
|
631
|
-
addTrajectory(trajectory) {
|
|
632
|
-
if (!this.trajectories) {
|
|
633
|
-
this.trajectories = {};
|
|
634
|
-
}
|
|
635
|
-
this.trajectories[trajectory.properties.train_id] = trajectory;
|
|
636
|
-
// @ts-ignore the parameter are set by subclasses
|
|
692
|
+
start() {
|
|
693
|
+
this.stop();
|
|
694
|
+
// Before starting to update trajectories, we remove trajectories that have
|
|
695
|
+
// a time_intervals in the past, it will
|
|
696
|
+
// avoid phantom train that are at the end of their route because we never
|
|
697
|
+
// received the deleted_vehicle event because we have changed the browser tab.
|
|
698
|
+
this.purgeOutOfDateTrajectories();
|
|
699
|
+
// @ts-expect-error function without parameters must be define in subclasses
|
|
637
700
|
this.renderTrajectories();
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
id = trajectoryOrId;
|
|
701
|
+
this.startUpdateTime();
|
|
702
|
+
this.api.open();
|
|
703
|
+
this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);
|
|
704
|
+
this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);
|
|
705
|
+
if (this.isUpdateBboxOnMoveEnd) {
|
|
706
|
+
// Update the bbox on each move end
|
|
707
|
+
// @ts-expect-error function without parameters defined by subclasses
|
|
708
|
+
this.setBbox();
|
|
647
709
|
}
|
|
648
|
-
if (this.
|
|
649
|
-
|
|
710
|
+
if (this.onStart) {
|
|
711
|
+
this.onStart(this);
|
|
650
712
|
}
|
|
651
713
|
}
|
|
652
714
|
/**
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* @param evt Event that triggered the function.
|
|
715
|
+
* Start the clock.
|
|
656
716
|
* @private
|
|
657
717
|
*/
|
|
658
|
-
|
|
659
|
-
this.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
this.
|
|
664
|
-
|
|
665
|
-
// is hidden. We have to clean all the trajectories for a fresh
|
|
666
|
-
// start when the document is visible again.
|
|
667
|
-
this.trajectories = {};
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
if (this.visible === false) {
|
|
671
|
-
return;
|
|
718
|
+
startUpdateTime() {
|
|
719
|
+
this.stopUpdateTime();
|
|
720
|
+
this.updateTimeDelay = this.getRefreshTimeInMs() || 0;
|
|
721
|
+
this.updateTimeInterval = window.setInterval(() => {
|
|
722
|
+
// When live=true, we update the time with new Date();
|
|
723
|
+
if (this.live) {
|
|
724
|
+
this.time = new Date();
|
|
672
725
|
}
|
|
673
|
-
this.
|
|
674
|
-
|
|
726
|
+
else if (this.time && this.updateTimeDelay && this.speed) {
|
|
727
|
+
this.time = new Date(this.time.getTime() + this.updateTimeDelay * this.speed);
|
|
728
|
+
}
|
|
729
|
+
}, this.updateTimeDelay);
|
|
675
730
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
onTrajectoryMessage(data) {
|
|
683
|
-
if (!data.content) {
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
const trajectory = data.content;
|
|
687
|
-
const { geometry, properties: { train_id: id, time_since_update: timeSinceUpdate, raw_coordinates: rawCoordinates, }, } = trajectory;
|
|
688
|
-
// ignore old events [SBAHNM-97]
|
|
689
|
-
if (timeSinceUpdate < 0) {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
// console.time(`onTrajectoryMessage${data.content.properties.train_id}`);
|
|
693
|
-
// @ts-ignore default value for extentand zoom are provided by subclasses
|
|
694
|
-
if (this.purgeTrajectory(trajectory)) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if (this.debug &&
|
|
698
|
-
this.mode === RealtimeModes.TOPOGRAPHIC &&
|
|
699
|
-
rawCoordinates) {
|
|
700
|
-
trajectory.properties.olGeometry = this.format.readGeometry({
|
|
701
|
-
type: 'Point',
|
|
702
|
-
coordinates: fromLonLat(rawCoordinates, this.map.getView().getProjection()),
|
|
703
|
-
});
|
|
704
|
-
}
|
|
705
|
-
else {
|
|
706
|
-
trajectory.properties.olGeometry = this.format.readGeometry(geometry);
|
|
731
|
+
stop() {
|
|
732
|
+
this.api.unsubscribeTrajectory(this.onTrajectoryMessage);
|
|
733
|
+
this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);
|
|
734
|
+
this.api.close();
|
|
735
|
+
if (this.onStop) {
|
|
736
|
+
this.onStop(this);
|
|
707
737
|
}
|
|
708
|
-
// TODO Make sure the timeOffset is useful. May be we can remove it.
|
|
709
|
-
trajectory.properties.timeOffset = Date.now() - data.timestamp;
|
|
710
|
-
this.addTrajectory(trajectory);
|
|
711
738
|
}
|
|
712
739
|
/**
|
|
713
|
-
*
|
|
714
|
-
* It removes the trajectory from the list.
|
|
715
|
-
*
|
|
740
|
+
* Stop the clock.
|
|
716
741
|
* @private
|
|
717
|
-
* @override
|
|
718
742
|
*/
|
|
719
|
-
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
this.removeTrajectory(data.content);
|
|
724
|
-
}
|
|
725
|
-
highlightVehicle(id) {
|
|
726
|
-
if (this.hoverVehicleId !== id) {
|
|
727
|
-
/** @private */
|
|
728
|
-
this.hoverVehicleId = id;
|
|
729
|
-
// @ts-ignore
|
|
730
|
-
this.renderTrajectories(true);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
selectVehicle(id) {
|
|
734
|
-
if (this.selectedVehicleId !== id) {
|
|
735
|
-
/** @private */
|
|
736
|
-
this.selectedVehicleId = id;
|
|
737
|
-
// @ts-ignore
|
|
738
|
-
this.renderTrajectories(true);
|
|
743
|
+
stopUpdateTime() {
|
|
744
|
+
if (this.updateTimeInterval) {
|
|
745
|
+
clearInterval(this.updateTimeInterval);
|
|
746
|
+
this.updateTimeInterval = undefined;
|
|
739
747
|
}
|
|
740
748
|
}
|
|
741
749
|
};
|