mobility-toolbox-js 2.0.0-beta.1 → 2.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.
- package/README.md +7 -4
- package/api/index.js +0 -1
- package/api/tralis/TralisAPI.js +1 -1
- package/common/controls/Control.js +4 -1
- package/common/layers/Layer.js +18 -49
- package/common/layers/Layer.test.js +2 -106
- package/common/mixins/SearchMixin.js +1 -1
- package/common/mixins/TralisLayerMixin.js +549 -21
- package/common/styles/index.js +4 -0
- package/common/{utils/delayTrackerStyle.js → styles/trackerDefaultStyle.js} +8 -8
- package/common/styles/trackerDelayStyle.js +17 -0
- package/common/styles/trackerSimpleStyle.js +22 -0
- package/common/trackerConfig.test.js +0 -13
- package/common/utils/getMapboxMapCopyrights.js +1 -0
- package/common/utils/index.js +2 -3
- package/common/utils/sortByDelay.js +23 -0
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/mapbox/controls/CopyrightControl.js +5 -1
- package/mapbox/index.js +0 -2
- package/mapbox/layers/Layer.test.js +2 -2
- package/mapbox/layers/TralisLayer.js +270 -5
- package/mapbox/layers/TralisLayer.test.js +40 -0
- package/module.js +1 -9
- package/ol/controls/CopyrightControl.js +4 -4
- package/ol/controls/CopyrightControl.test.js +16 -16
- package/ol/controls/RoutingControl.js +9 -7
- package/ol/controls/RoutingControl.test.js +1 -1
- package/ol/controls/StopFinderControl.js +8 -6
- package/ol/controls/StopFinderControl.test.js +1 -1
- package/ol/index.js +3 -3
- package/ol/layers/Layer.js +9 -0
- package/ol/layers/Layer.test.js +22 -7
- package/ol/layers/MapboxLayer.js +39 -44
- package/ol/layers/MapboxLayer.test.js +5 -5
- package/ol/layers/MapboxStyleLayer.js +0 -6
- package/ol/layers/MapboxStyleLayer.test.js +22 -6
- package/ol/layers/MaplibreLayer.js +280 -0
- package/ol/layers/RoutingLayer.test.js +1 -1
- package/ol/layers/TralisLayer.js +258 -76
- package/ol/layers/TralisLayer.test.js +1 -49
- package/ol/layers/VectorLayer.test.js +1 -1
- package/ol/layers/WMSLayer.test.js +6 -2
- package/ol/styles/fullTrajectoryDelayStyle.js +35 -0
- package/ol/styles/fullTrajectoryStyle.js +51 -0
- package/ol/styles/index.js +2 -0
- package/package.json +16 -8
- package/api/trajserv/TrajservAPI.js +0 -71
- package/api/trajserv/TrajservAPI.test.js +0 -171
- package/api/trajserv/TrajservAPIUtils.js +0 -191
- package/api/trajserv/TrajservAPIUtils.test.js +0 -40
- package/api/trajserv/typedefs.js +0 -44
- package/common/mixins/MapMixin.js +0 -103
- package/common/mixins/TrackerLayerMixin.js +0 -745
- package/common/mixins/TrajservLayerMixin.js +0 -544
- package/common/utils/simpleTrackerStyle.js +0 -18
- package/mapbox/Map.js +0 -87
- package/mapbox/layers/TrackerLayer.js +0 -282
- package/mapbox/layers/TrackerLayer.test.js +0 -68
- package/mapbox/layers/TrajservLayer.js +0 -114
- package/mapbox/layers/TrajservLayer.test.js +0 -90
- package/ol/Map.js +0 -109
- package/ol/Map.test.js +0 -34
- package/ol/layers/TrackerLayer.js +0 -296
- package/ol/layers/TrackerLayer.test.js +0 -70
- package/ol/layers/TrajservLayer.js +0 -190
- package/ol/layers/TrajservLayer.test.js +0 -113
|
@@ -3,12 +3,25 @@
|
|
|
3
3
|
/* eslint-disable no-unused-vars */
|
|
4
4
|
/* eslint-disable class-methods-use-this */
|
|
5
5
|
/* eslint-disable max-classes-per-file */
|
|
6
|
+
import qs from 'query-string';
|
|
7
|
+
import { buffer, containsCoordinate, intersects } from 'ol/extent';
|
|
8
|
+
import { unByKey } from 'ol/Observable';
|
|
6
9
|
import GeoJSON from 'ol/format/GeoJSON';
|
|
7
10
|
import Point from 'ol/geom/Point';
|
|
8
|
-
import
|
|
11
|
+
import debounce from 'lodash.debounce';
|
|
12
|
+
import throttle from 'lodash.throttle';
|
|
9
13
|
import { fromLonLat } from 'ol/proj';
|
|
14
|
+
import Tracker from '../Tracker';
|
|
15
|
+
import { timeSteps } from '../trackerConfig';
|
|
16
|
+
import createFilters from '../utils/createTrackerFilters';
|
|
17
|
+
import trackerDefaultStyle from '../styles/trackerDefaultStyle';
|
|
10
18
|
import { TralisAPI, TralisModes } from '../../api';
|
|
11
19
|
|
|
20
|
+
/* Permalink parameter used to filters vehicles */
|
|
21
|
+
const LINE_FILTER = 'publishedlinename';
|
|
22
|
+
const ROUTE_FILTER = 'tripnumber';
|
|
23
|
+
const OPERATOR_FILTER = 'operator';
|
|
24
|
+
|
|
12
25
|
/**
|
|
13
26
|
* TralisLayerInterface.
|
|
14
27
|
*/
|
|
@@ -38,6 +51,16 @@ export class TralisLayerInterface {
|
|
|
38
51
|
*/
|
|
39
52
|
terminate() {}
|
|
40
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Start the clock.
|
|
56
|
+
*/
|
|
57
|
+
start() {}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Stop the clock.
|
|
61
|
+
*/
|
|
62
|
+
stop() {}
|
|
63
|
+
|
|
41
64
|
/**
|
|
42
65
|
* Set the Tralis api's bbox.
|
|
43
66
|
*
|
|
@@ -61,28 +84,20 @@ export class TralisLayerInterface {
|
|
|
61
84
|
* @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
62
85
|
*/
|
|
63
86
|
getTrajectoryInfos(id, mode) {}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Define the style of the vehicle.
|
|
67
|
-
* Draw a blue circle with the id of the props parameter.
|
|
68
|
-
*
|
|
69
|
-
* @param {TralisTrajectory} trajectory A trajectory
|
|
70
|
-
* @param {ViewState} viewState Map's view state (zoom, resolution, center, ...)
|
|
71
|
-
*/
|
|
72
|
-
defaultStyle(trajectory, viewState) {}
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
/**
|
|
76
90
|
* Mixin for TralisLayerInterface.
|
|
77
91
|
*
|
|
78
|
-
* @param {
|
|
92
|
+
* @param {Class} Base A class to extend with {TralisLayerInterface} functionnalities.
|
|
79
93
|
* @return {Class} A class that implements {TralisLayerInterface} class and extends Base;
|
|
80
94
|
* @private
|
|
81
95
|
*/
|
|
82
|
-
const TralisLayerMixin = (
|
|
83
|
-
class extends
|
|
96
|
+
const TralisLayerMixin = (Base) =>
|
|
97
|
+
class extends Base {
|
|
84
98
|
constructor(options = {}) {
|
|
85
|
-
super({ ...options });
|
|
99
|
+
super({ hitTolerance: 10, ...options });
|
|
100
|
+
|
|
86
101
|
this.debug = options.debug;
|
|
87
102
|
this.mode = options.mode || TralisModes.TOPOGRAPHIC;
|
|
88
103
|
this.api = options.api || new TralisAPI(options);
|
|
@@ -110,7 +125,24 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
110
125
|
// This property will call api.setBbox on each movend event
|
|
111
126
|
this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;
|
|
112
127
|
|
|
128
|
+
// Define throttling nad debounce render function
|
|
129
|
+
this.throttleRenderTrajectories = throttle(
|
|
130
|
+
this.renderTrajectoriesInternal,
|
|
131
|
+
50,
|
|
132
|
+
{ leading: false, trailing: true },
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
this.debounceRenderTrajectories = debounce(
|
|
136
|
+
this.renderTrajectoriesInternal,
|
|
137
|
+
50,
|
|
138
|
+
{ leading: true, trailing: true, maxWait: 5000 },
|
|
139
|
+
);
|
|
140
|
+
|
|
113
141
|
// Bind callbacks
|
|
142
|
+
this.onFeatureHover = this.onFeatureHover.bind(this);
|
|
143
|
+
this.onFeatureClick = this.onFeatureClick.bind(this);
|
|
144
|
+
this.renderTrajectoriesInternal =
|
|
145
|
+
this.renderTrajectoriesInternal.bind(this);
|
|
114
146
|
this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);
|
|
115
147
|
this.onDeleteTrajectoryMessage =
|
|
116
148
|
this.onDeleteTrajectoryMessage.bind(this);
|
|
@@ -118,9 +150,268 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
118
150
|
this.onDocumentVisibilityChange.bind(this);
|
|
119
151
|
}
|
|
120
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Define layer's properties.
|
|
155
|
+
*
|
|
156
|
+
* @ignore
|
|
157
|
+
*/
|
|
158
|
+
defineProperties(options) {
|
|
159
|
+
// Tracker options use to build the tracker.
|
|
160
|
+
let { regexPublishedLineName, publishedLineName, tripNumber, operator } =
|
|
161
|
+
options;
|
|
162
|
+
const {
|
|
163
|
+
style,
|
|
164
|
+
speed,
|
|
165
|
+
pixelRatio,
|
|
166
|
+
hoverVehicleId,
|
|
167
|
+
selectedVehicleId,
|
|
168
|
+
filter,
|
|
169
|
+
sort,
|
|
170
|
+
time,
|
|
171
|
+
live,
|
|
172
|
+
} = options;
|
|
173
|
+
|
|
174
|
+
const initTrackerOptions = {
|
|
175
|
+
style,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
Object.keys(initTrackerOptions).forEach(
|
|
179
|
+
(key) =>
|
|
180
|
+
initTrackerOptions[key] === undefined &&
|
|
181
|
+
delete initTrackerOptions[key],
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
let currSpeed = speed || 1;
|
|
185
|
+
let currTime = time || new Date();
|
|
186
|
+
|
|
187
|
+
super.defineProperties(options);
|
|
188
|
+
|
|
189
|
+
Object.defineProperties(this, {
|
|
190
|
+
isTrackerLayer: { value: true },
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Style function used to render a vehicle.
|
|
194
|
+
*/
|
|
195
|
+
style: {
|
|
196
|
+
value: (trajectory, viewState) =>
|
|
197
|
+
(style || trackerDefaultStyle)(trajectory, viewState, this),
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Speed of the wheel of time.
|
|
202
|
+
* If live property is true. The speed is ignored.
|
|
203
|
+
*/
|
|
204
|
+
speed: {
|
|
205
|
+
get: () => currSpeed,
|
|
206
|
+
set: (newSpeed) => {
|
|
207
|
+
currSpeed = newSpeed;
|
|
208
|
+
this.start();
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Function to filter which vehicles to display.
|
|
214
|
+
*/
|
|
215
|
+
filter: {
|
|
216
|
+
value: filter,
|
|
217
|
+
writable: true,
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Function to sort the vehicles to display.
|
|
222
|
+
*/
|
|
223
|
+
sort: {
|
|
224
|
+
value: sort,
|
|
225
|
+
writable: true,
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The tracker that renders the trajectories.
|
|
230
|
+
*/
|
|
231
|
+
tracker: { value: null, writable: true },
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Canvas cache object for trajectories drawn.
|
|
235
|
+
*/
|
|
236
|
+
styleCache: { value: {} },
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* If true. The layer will always use Date.now() on the next tick to render the trajectories.
|
|
240
|
+
* When true, setting the time property has no effect.
|
|
241
|
+
*/
|
|
242
|
+
live: {
|
|
243
|
+
value: live === false ? live : true,
|
|
244
|
+
writable: true,
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Time used to display the trajectories. Can be a Date or a number in ms representing a Date.
|
|
249
|
+
* If live property is true. The setter does nothing.
|
|
250
|
+
*/
|
|
251
|
+
time: {
|
|
252
|
+
get: () => currTime,
|
|
253
|
+
set: (newTime) => {
|
|
254
|
+
currTime = newTime && newTime.getTime ? newTime : new Date(newTime);
|
|
255
|
+
this.renderTrajectories();
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Keep track of which trajectories are stored.
|
|
261
|
+
*/
|
|
262
|
+
trajectories: {
|
|
263
|
+
value: {},
|
|
264
|
+
writable: true,
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Keep track of which trajectories are currently drawn.
|
|
269
|
+
*/
|
|
270
|
+
renderedTrajectories: {
|
|
271
|
+
get: () => (this.tracker && this.tracker.renderedTrajectories) || [],
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Id of the hovered vehicle.
|
|
276
|
+
*/
|
|
277
|
+
hoverVehicleId: {
|
|
278
|
+
value: hoverVehicleId,
|
|
279
|
+
writable: true,
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Id of the selected vehicle.
|
|
284
|
+
*/
|
|
285
|
+
selectedVehicleId: {
|
|
286
|
+
value: selectedVehicleId,
|
|
287
|
+
writable: true,
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Id of the selected vehicle.
|
|
292
|
+
*/
|
|
293
|
+
pixelRatio: {
|
|
294
|
+
value:
|
|
295
|
+
pixelRatio ||
|
|
296
|
+
(typeof window !== 'undefined' ? window.devicePixelRatio : 1),
|
|
297
|
+
writable: true,
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Options used by the constructor of the Tracker class.
|
|
302
|
+
*/
|
|
303
|
+
initTrackerOptions: {
|
|
304
|
+
value: initTrackerOptions,
|
|
305
|
+
writable: false,
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* If true, encapsulates the renderTrajectories calls in a requestAnimationFrame.
|
|
310
|
+
*/
|
|
311
|
+
useRequestAnimationFrame: {
|
|
312
|
+
value: options.useRequestAnimationFrame || false,
|
|
313
|
+
writable: true,
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* If true, encapsulates the renderTrajectories calls in a throttle function. Default to true.
|
|
318
|
+
*/
|
|
319
|
+
useThrottle: {
|
|
320
|
+
value: options.useThrottle || true,
|
|
321
|
+
writable: true,
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* If true, encapsulates the renderTrajectories calls in a debounce function.
|
|
326
|
+
*/
|
|
327
|
+
useDebounce: {
|
|
328
|
+
value: options.useDebounce || false,
|
|
329
|
+
writable: true,
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Filter properties used in combination with permalink parameters.
|
|
334
|
+
*/
|
|
335
|
+
publishedLineName: {
|
|
336
|
+
get: () => publishedLineName,
|
|
337
|
+
set: (newPublishedLineName) => {
|
|
338
|
+
publishedLineName = newPublishedLineName;
|
|
339
|
+
this.updateFilters();
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
tripNumber: {
|
|
343
|
+
get: () => tripNumber,
|
|
344
|
+
set: (newTripNumber) => {
|
|
345
|
+
tripNumber = newTripNumber;
|
|
346
|
+
this.updateFilters();
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
operator: {
|
|
350
|
+
get: () => operator,
|
|
351
|
+
set: (newOperator) => {
|
|
352
|
+
operator = newOperator;
|
|
353
|
+
this.updateFilters();
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
regexPublishedLineName: {
|
|
357
|
+
get: () => regexPublishedLineName,
|
|
358
|
+
set: (newRegex) => {
|
|
359
|
+
regexPublishedLineName = newRegex;
|
|
360
|
+
this.updateFilters();
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Style properties.
|
|
366
|
+
*/
|
|
367
|
+
delayDisplay: {
|
|
368
|
+
value: options.delayDisplay || 300000,
|
|
369
|
+
writable: true,
|
|
370
|
+
},
|
|
371
|
+
delayOutlineColor: {
|
|
372
|
+
value: options.delayOutlineColor || '#000000',
|
|
373
|
+
writable: true,
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Debug properties.
|
|
378
|
+
*/
|
|
379
|
+
// Not used anymore, but could be useful for debugging.
|
|
380
|
+
// showVehicleTraj: {
|
|
381
|
+
// value:
|
|
382
|
+
// options.showVehicleTraj !== undefined
|
|
383
|
+
// ? options.showVehicleTraj
|
|
384
|
+
// : true,
|
|
385
|
+
// writable: true,
|
|
386
|
+
// },
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Update filter function based on convenient properties
|
|
390
|
+
this.updateFilters();
|
|
391
|
+
}
|
|
392
|
+
|
|
121
393
|
init(map) {
|
|
122
394
|
super.init(map);
|
|
123
395
|
|
|
396
|
+
this.tracker = new Tracker({
|
|
397
|
+
style: (...args) => this.style(...args),
|
|
398
|
+
...this.initTrackerOptions,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// If the layer is visible we start the rendering clock
|
|
402
|
+
if (this.visible) {
|
|
403
|
+
this.start();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// On change of visibility we start/stop the rendering clock
|
|
407
|
+
this.visibilityRef = this.on('change:visible', (evt) => {
|
|
408
|
+
if (evt.target.visible) {
|
|
409
|
+
this.start();
|
|
410
|
+
} else {
|
|
411
|
+
this.stop();
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
|
|
124
415
|
// To avoid browser hanging when the tab is not visible for a certain amount of time,
|
|
125
416
|
// We stop the rendering and the websocket when hide and start again when show.
|
|
126
417
|
document.addEventListener(
|
|
@@ -134,11 +425,31 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
134
425
|
'visibilitychange',
|
|
135
426
|
this.onDocumentVisibilityChange,
|
|
136
427
|
);
|
|
428
|
+
|
|
429
|
+
this.stop();
|
|
430
|
+
unByKey(this.visibilityRef);
|
|
431
|
+
if (this.tracker) {
|
|
432
|
+
const { canvas } = this.tracker;
|
|
433
|
+
const context = canvas.getContext('2d');
|
|
434
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
435
|
+
this.tracker = null;
|
|
436
|
+
}
|
|
137
437
|
super.terminate();
|
|
138
438
|
}
|
|
139
439
|
|
|
140
440
|
start() {
|
|
141
|
-
|
|
441
|
+
this.stop();
|
|
442
|
+
this.renderTrajectories();
|
|
443
|
+
this.startUpdateTime();
|
|
444
|
+
|
|
445
|
+
if (this.isClickActive) {
|
|
446
|
+
this.onClick(this.onFeatureClick);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (this.isHoverActive) {
|
|
450
|
+
this.onHover(this.onFeatureHover);
|
|
451
|
+
}
|
|
452
|
+
|
|
142
453
|
this.api.open();
|
|
143
454
|
this.api.subscribeTrajectory(
|
|
144
455
|
this.mode,
|
|
@@ -157,13 +468,119 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
157
468
|
}
|
|
158
469
|
}
|
|
159
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Start the clock.
|
|
473
|
+
* @private
|
|
474
|
+
*/
|
|
475
|
+
startUpdateTime() {
|
|
476
|
+
this.stopUpdateTime();
|
|
477
|
+
this.updateTimeDelay = this.getRefreshTimeInMs();
|
|
478
|
+
this.updateTimeInterval = setInterval(() => {
|
|
479
|
+
// When live=true, we update the time with new Date();
|
|
480
|
+
this.time = this.live
|
|
481
|
+
? new Date()
|
|
482
|
+
: this.time.getTime() + this.updateTimeDelay * this.speed;
|
|
483
|
+
}, this.updateTimeDelay);
|
|
484
|
+
}
|
|
485
|
+
|
|
160
486
|
stop() {
|
|
161
|
-
super.stop();
|
|
162
487
|
this.api.unsubscribeTrajectory(this.onTrajectoryMessage);
|
|
163
488
|
this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);
|
|
164
489
|
this.api.close();
|
|
165
490
|
}
|
|
166
491
|
|
|
492
|
+
/**
|
|
493
|
+
* Stop the clock.
|
|
494
|
+
* @private
|
|
495
|
+
*/
|
|
496
|
+
stopUpdateTime() {
|
|
497
|
+
if (this.updateTimeInterval) {
|
|
498
|
+
clearInterval(this.updateTimeInterval);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.
|
|
504
|
+
*
|
|
505
|
+
* @param {object} viewState The view state of the map.
|
|
506
|
+
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
507
|
+
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
508
|
+
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
509
|
+
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
510
|
+
* @param {number} viewState.resolution Resolution of the map to render.
|
|
511
|
+
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
512
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
513
|
+
* during map navigation.
|
|
514
|
+
* @private
|
|
515
|
+
*/
|
|
516
|
+
renderTrajectoriesInternal(viewState, noInterpolate) {
|
|
517
|
+
if (!this.tracker) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const time = this.live ? Date.now() : this.time;
|
|
522
|
+
|
|
523
|
+
const trajectories = Object.values(this.trajectories);
|
|
524
|
+
|
|
525
|
+
// console.time('sort');
|
|
526
|
+
if (this.sort) {
|
|
527
|
+
trajectories.sort(this.sort);
|
|
528
|
+
}
|
|
529
|
+
// console.timeEnd('sort');
|
|
530
|
+
|
|
531
|
+
// console.time('render');
|
|
532
|
+
this.renderState = this.tracker.renderTrajectories(
|
|
533
|
+
trajectories,
|
|
534
|
+
{ ...viewState, pixelRatio: this.pixelRatio, time },
|
|
535
|
+
{
|
|
536
|
+
noInterpolate:
|
|
537
|
+
viewState.zoom < this.minZoomInterpolation ? true : noInterpolate,
|
|
538
|
+
hoverVehicleId: this.hoverVehicleId,
|
|
539
|
+
selectedVehicleId: this.selectedVehicleId,
|
|
540
|
+
iconScale: this.iconScale,
|
|
541
|
+
delayDisplay: this.delayDisplay,
|
|
542
|
+
delayOutlineColor: this.delayOutlineColor,
|
|
543
|
+
},
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// console.timeEnd('render');
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Render the trajectories requesting an animation frame and cancelling the previous one.
|
|
552
|
+
* This function must be overrided by children to provide the correct parameters.
|
|
553
|
+
*
|
|
554
|
+
* @param {object} viewState The view state of the map.
|
|
555
|
+
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
556
|
+
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
557
|
+
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
558
|
+
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
559
|
+
* @param {number} viewState.resolution Resolution of the map to render.
|
|
560
|
+
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
561
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
562
|
+
* during map navigation.
|
|
563
|
+
* @private
|
|
564
|
+
*/
|
|
565
|
+
renderTrajectories(viewState, noInterpolate) {
|
|
566
|
+
if (this.requestId) {
|
|
567
|
+
cancelAnimationFrame(this.requestId);
|
|
568
|
+
this.requestId = null;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (!noInterpolate && this.useRequestAnimationFrame) {
|
|
572
|
+
this.requestId = requestAnimationFrame(() => {
|
|
573
|
+
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
574
|
+
});
|
|
575
|
+
} else if (!noInterpolate && this.useDebounce) {
|
|
576
|
+
this.debounceRenderTrajectories(viewState, noInterpolate);
|
|
577
|
+
} else if (!noInterpolate && this.useThrottle) {
|
|
578
|
+
this.throttleRenderTrajectories(viewState, noInterpolate);
|
|
579
|
+
} else {
|
|
580
|
+
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
167
584
|
setBbox(extent, zoom) {
|
|
168
585
|
// Clean trajectories before sending the new bbox
|
|
169
586
|
// Purge trajectories:
|
|
@@ -210,6 +627,88 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
210
627
|
);
|
|
211
628
|
}
|
|
212
629
|
|
|
630
|
+
/**
|
|
631
|
+
* Get the duration before the next update depending on zoom level.
|
|
632
|
+
*
|
|
633
|
+
* @private
|
|
634
|
+
* @param {number} zoom
|
|
635
|
+
*/
|
|
636
|
+
getRefreshTimeInMs(zoom) {
|
|
637
|
+
const roundedZoom = Math.round(zoom);
|
|
638
|
+
const timeStep = timeSteps[roundedZoom] || 25;
|
|
639
|
+
const nextTick = Math.max(25, timeStep / this.speed);
|
|
640
|
+
const nextThrottleTick = Math.min(nextTick, 500);
|
|
641
|
+
// TODO: see if this should go elsewhere.
|
|
642
|
+
if (this.useThrottle) {
|
|
643
|
+
this.throttleRenderTrajectories = throttle(
|
|
644
|
+
this.renderTrajectoriesInternal,
|
|
645
|
+
nextThrottleTick,
|
|
646
|
+
{ leading: true, trailing: true },
|
|
647
|
+
);
|
|
648
|
+
} else if (this.useDebounce) {
|
|
649
|
+
this.debounceRenderTrajectories = debounce(
|
|
650
|
+
this.renderTrajectoriesInternal,
|
|
651
|
+
nextThrottleTick,
|
|
652
|
+
{ leading: true, trailing: true, maxWait: 5000 },
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
if (this.api?.buffer) {
|
|
656
|
+
const [, size] = this.api.buffer;
|
|
657
|
+
this.api.buffer = [nextThrottleTick, size];
|
|
658
|
+
}
|
|
659
|
+
return nextTick;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Get vehicle.
|
|
664
|
+
* @param {function} filterFc A function use to filter results.
|
|
665
|
+
* @return {Array<Object>} Array of vehicle.
|
|
666
|
+
*/
|
|
667
|
+
getVehicle(filterFc) {
|
|
668
|
+
return Object.values(this.trajectories).filter(filterFc);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Request feature information for a given coordinate.
|
|
673
|
+
*
|
|
674
|
+
* @param {ol/coordinate~Coordinate} coordinate Coordinate.
|
|
675
|
+
* @param {Object} options Options See child classes to see which options are supported.
|
|
676
|
+
* @param {number} [options.resolution=1] The resolution of the map.
|
|
677
|
+
* @param {number} [options.nb=Infinity] The max number of vehicles to return.
|
|
678
|
+
* @return {Promise<FeatureInfo>} Promise with features, layer and coordinate.
|
|
679
|
+
*/
|
|
680
|
+
getFeatureInfoAtCoordinate(coordinate, options = {}) {
|
|
681
|
+
const { resolution, nb } = options;
|
|
682
|
+
const ext = buffer(
|
|
683
|
+
[...coordinate, ...coordinate],
|
|
684
|
+
this.hitTolerance * resolution,
|
|
685
|
+
);
|
|
686
|
+
let trajectories = Object.values(this.trajectories);
|
|
687
|
+
|
|
688
|
+
if (this.sort) {
|
|
689
|
+
trajectories = trajectories.sort(this.sort);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const vehicles = [];
|
|
693
|
+
for (let i = 0; i < trajectories.length; i += 1) {
|
|
694
|
+
if (
|
|
695
|
+
trajectories[i].properties.coordinate &&
|
|
696
|
+
containsCoordinate(ext, trajectories[i].properties.coordinate)
|
|
697
|
+
) {
|
|
698
|
+
vehicles.push(trajectories[i]);
|
|
699
|
+
}
|
|
700
|
+
if (vehicles.length === nb) {
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return Promise.resolve({
|
|
706
|
+
layer: this,
|
|
707
|
+
features: vehicles.map((vehicle) => this.format.readFeature(vehicle)),
|
|
708
|
+
coordinate,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
|
|
213
712
|
/**
|
|
214
713
|
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
215
714
|
*
|
|
@@ -274,9 +773,17 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
274
773
|
delete this.trajectories[id];
|
|
275
774
|
}
|
|
276
775
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
776
|
+
/**
|
|
777
|
+
* On zoomend we adjust the time interval of the update of vehicles positions.
|
|
778
|
+
*
|
|
779
|
+
* @param evt Event that triggered the function.
|
|
780
|
+
* @private
|
|
781
|
+
*/
|
|
782
|
+
// eslint-disable-next-line no-unused-vars
|
|
783
|
+
onZoomEnd(evt) {
|
|
784
|
+
this.startUpdateTime();
|
|
785
|
+
}
|
|
786
|
+
|
|
280
787
|
onDocumentVisibilityChange() {
|
|
281
788
|
if (!this.visible) {
|
|
282
789
|
return;
|
|
@@ -373,7 +880,6 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
373
880
|
this.hoverVehicleId = id;
|
|
374
881
|
this.renderTrajectories(true);
|
|
375
882
|
}
|
|
376
|
-
super.onFeatureHover(features, layer, coordinate);
|
|
377
883
|
}
|
|
378
884
|
|
|
379
885
|
/**
|
|
@@ -395,7 +901,29 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
395
901
|
this.selectedVehicle = feature;
|
|
396
902
|
this.renderTrajectories(true);
|
|
397
903
|
}
|
|
398
|
-
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Update filter provided by properties or permalink.
|
|
908
|
+
*/
|
|
909
|
+
updateFilters() {
|
|
910
|
+
// Setting filters from the permalink if no values defined by the layer.
|
|
911
|
+
const parameters = qs.parse(window.location.search.toLowerCase());
|
|
912
|
+
const publishedName = this.publishedLineName || parameters[LINE_FILTER];
|
|
913
|
+
const tripNumber = this.tripNumber || parameters[ROUTE_FILTER];
|
|
914
|
+
const operator = this.operator || parameters[OPERATOR_FILTER];
|
|
915
|
+
const { regexPublishedLineName } = this;
|
|
916
|
+
|
|
917
|
+
// Only overrides filter function if one of this property exists.
|
|
918
|
+
if (publishedName || tripNumber || operator || regexPublishedLineName) {
|
|
919
|
+
// filter is the property in TrackerLayerMixin.
|
|
920
|
+
this.filter = createFilters(
|
|
921
|
+
publishedName,
|
|
922
|
+
tripNumber,
|
|
923
|
+
operator,
|
|
924
|
+
regexPublishedLineName,
|
|
925
|
+
);
|
|
926
|
+
}
|
|
399
927
|
}
|
|
400
928
|
};
|
|
401
929
|
|
|
@@ -158,24 +158,24 @@ const style = (trajectory, viewState, options) => {
|
|
|
158
158
|
} = options;
|
|
159
159
|
|
|
160
160
|
const { zoom, pixelRatio } = viewState;
|
|
161
|
-
let {
|
|
161
|
+
let { type, cancelled } = trajectory.properties;
|
|
162
162
|
const {
|
|
163
163
|
train_id: id,
|
|
164
|
+
line,
|
|
164
165
|
delay,
|
|
165
|
-
|
|
166
|
+
state,
|
|
166
167
|
operator_provides_realtime_journey: operatorProvidesRealtime,
|
|
167
168
|
} = trajectory.properties;
|
|
169
|
+
let { name, text_color: textColor, color } = line || {};
|
|
170
|
+
|
|
171
|
+
// In the future, the cancelled property will be removed we still managed it
|
|
172
|
+
// until the backend change is on prod.
|
|
173
|
+
cancelled = cancelled === true || state === 'JOURNEY_CANCELLED';
|
|
168
174
|
|
|
169
175
|
if (!type) {
|
|
170
176
|
type = 'Rail';
|
|
171
177
|
}
|
|
172
178
|
|
|
173
|
-
if (!line) {
|
|
174
|
-
line = {};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
let { name, text_color: textColor, color } = line;
|
|
178
|
-
|
|
179
179
|
if (!name) {
|
|
180
180
|
name = 'I';
|
|
181
181
|
}
|