mobility-toolbox-js 1.6.0-beta.4 → 1.6.0-beta.8
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/tralis/TralisAPI.js +1 -1
- package/api/tralis/WebSocketConnector.js +8 -8
- package/common/layers/Layer.js +10 -7
- package/common/layers/Layer.test.js +27 -0
- package/common/mixins/TrackerLayerMixin.js +99 -1
- package/common/mixins/TrajservLayerMixin.js +76 -159
- package/common/mixins/TralisLayerMixin.js +45 -10
- package/common/trackerConfig.js +16 -13
- package/common/trackerConfig.test.js +38 -0
- package/common/utils/createTrackerFilters.js +82 -0
- package/common/utils/createTrackerFilters.test.js +89 -0
- package/common/utils/index.js +1 -0
- package/common/utils/trackerStyle.js +201 -0
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/mapbox/layers/Layer.js +32 -6
- package/mapbox/layers/Layer.test.js +122 -0
- package/mapbox/layers/TrackerLayer.js +3 -3
- package/mapbox/layers/TrajservLayer.js +4 -88
- package/mapbox/layers/TralisLayer.js +0 -1
- package/ol/layers/Layer.js +39 -8
- package/ol/layers/Layer.test.js +81 -0
- package/ol/layers/TrackerLayer.js +24 -7
- package/ol/layers/TrackerLayer.test.js +8 -0
- package/ol/layers/TrajservLayer.js +34 -126
- package/ol/layers/TralisLayer.js +102 -0
- package/package.json +1 -1
package/api/tralis/TralisAPI.js
CHANGED
|
@@ -75,7 +75,7 @@ class TralisAPI {
|
|
|
75
75
|
/** @ignore */
|
|
76
76
|
this.prefix = options.prefix || '';
|
|
77
77
|
|
|
78
|
-
this.isUpdateBboxOnMoveEnd = options.
|
|
78
|
+
this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd || false;
|
|
79
79
|
|
|
80
80
|
/** @ignore */
|
|
81
81
|
this.conn = new WebSocketConnector(wsUrl);
|
|
@@ -11,8 +11,8 @@ class WebSocketConnector {
|
|
|
11
11
|
this.subscriptions = [];
|
|
12
12
|
this.connect(url);
|
|
13
13
|
|
|
14
|
-
this.isSUBAllow =
|
|
15
|
-
this.isDELAllow =
|
|
14
|
+
this.isSUBAllow = false;
|
|
15
|
+
this.isDELAllow = false;
|
|
16
16
|
|
|
17
17
|
// keep websocket alive
|
|
18
18
|
setInterval(() => {
|
|
@@ -55,13 +55,13 @@ class WebSocketConnector {
|
|
|
55
55
|
// this.setProjection(this.currentProj);
|
|
56
56
|
// }
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
[...this.subscriptions].forEach((s) => {
|
|
59
|
+
this.subscribe(s.params, s.cb, s.errorCb, s.quiet);
|
|
60
|
+
});
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
if (this.currentBbox) {
|
|
63
|
+
this.setBbox(this.currentBbox);
|
|
64
|
+
}
|
|
65
65
|
|
|
66
66
|
// reconnect on close
|
|
67
67
|
this.websocket.onclose = () => {
|
package/common/layers/Layer.js
CHANGED
|
@@ -13,7 +13,9 @@ import { v4 as uuid } from 'uuid';
|
|
|
13
13
|
* @classproperty {string} key - Identifier of the layer. Must be unique.
|
|
14
14
|
* @classproperty {string[]} copyrights - Array of copyrights.
|
|
15
15
|
* @classproperty {boolean} isBaseLayer - Define if the layer is a base layer. Read-only.
|
|
16
|
-
* @classproperty {boolean} isQueryable - Define if the layer can be queried. Read-only.
|
|
16
|
+
* @classproperty {boolean} isQueryable - Define if the layer can be queried. If false, it will set isHoverActive and isClickActive to false. Read-only.
|
|
17
|
+
* @classproperty {boolean} isClickActive - If true feature information will be queried on user click event. See inherited layers for more informations. Read-only.
|
|
18
|
+
* @classproperty {boolean} isHoverActive - If true feature information will be queried on pointer move event. See inherited layers for more informations. Read-only.
|
|
17
19
|
* @classproperty {boolean} isReactSpatialLayer - Custom property for duck typing since `instanceof` is not working when the instance was created on different bundles. Read-only.
|
|
18
20
|
* @classproperty {Layer[]} children - List of children.
|
|
19
21
|
* @classproperty {boolean} visible - Define if the layer is visible or not.
|
|
@@ -33,9 +35,9 @@ export default class Layer extends Observable {
|
|
|
33
35
|
* @param {Object} [options.properties={}] Application-specific layer properties.
|
|
34
36
|
* @param {boolean} [options.visible=true] If true this layer is visible on the map.
|
|
35
37
|
* @param {boolean} [options.isBaseLayer=false] If true this layer is a baseLayer.
|
|
36
|
-
* @param {boolean} [options.isQueryable=true]
|
|
37
|
-
* @param {boolean} [options.isClickActive=true] If true feature information will be queried on click event. See inherited layers for more informations.
|
|
38
|
-
* @param {boolean} [options.isHoverActive=true] If true feature information will be queried on pointer move event. See inherited layers for more informations.
|
|
38
|
+
* @param {boolean} [options.isQueryable=true] Define if the layer can be queried. If false, it will also set isHoverActive and isClickActive to false. Read-only.
|
|
39
|
+
* @param {boolean} [options.isClickActive=true] If true feature information will be queried on click event. See inherited layers for more informations. Read-only.
|
|
40
|
+
* @param {boolean} [options.isHoverActive=true] If true feature information will be queried on pointer move event. See inherited layers for more informations. Read-only.
|
|
39
41
|
* @param {number} [options.hitTolerance=5] Hit-detection tolerance in css pixels. Pixels inside the radius around the given position will be checked for features.
|
|
40
42
|
*/
|
|
41
43
|
constructor(options = {}) {
|
|
@@ -109,10 +111,10 @@ export default class Layer extends Observable {
|
|
|
109
111
|
value: !!isQueryable,
|
|
110
112
|
},
|
|
111
113
|
isClickActive: {
|
|
112
|
-
value: !!isClickActive,
|
|
114
|
+
value: !!isQueryable && !!isClickActive,
|
|
113
115
|
},
|
|
114
116
|
isHoverActive: {
|
|
115
|
-
value: !!isHoverActive,
|
|
117
|
+
value: !!isQueryable && !!isHoverActive,
|
|
116
118
|
},
|
|
117
119
|
hitTolerance: {
|
|
118
120
|
value: hitTolerance || 5,
|
|
@@ -307,6 +309,7 @@ export default class Layer extends Observable {
|
|
|
307
309
|
// eslint-disable-next-line no-console
|
|
308
310
|
console.error(
|
|
309
311
|
'getFeatureInfoAtCoordinate must be implemented by inheriting layers',
|
|
312
|
+
this.key,
|
|
310
313
|
);
|
|
311
314
|
|
|
312
315
|
// This layer returns no feature info.
|
|
@@ -427,7 +430,7 @@ export default class Layer extends Observable {
|
|
|
427
430
|
.then((featureInfo) => {
|
|
428
431
|
const { features, layer, coordinate } = featureInfo;
|
|
429
432
|
this.hoverCallbacks.forEach((callback) =>
|
|
430
|
-
callback(
|
|
433
|
+
callback(features, layer, coordinate),
|
|
431
434
|
);
|
|
432
435
|
return featureInfo;
|
|
433
436
|
})
|
|
@@ -63,6 +63,21 @@ describe('Layer', () => {
|
|
|
63
63
|
expect(layer.name).toEqual('Layer');
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
test('should set isClickActive and isHoverActive to false if isQueryable is set to false.', () => {
|
|
67
|
+
const options = {
|
|
68
|
+
name: 'Layer',
|
|
69
|
+
isQueryable: false,
|
|
70
|
+
isClickActive: true,
|
|
71
|
+
isHoverActive: true,
|
|
72
|
+
olLayer,
|
|
73
|
+
};
|
|
74
|
+
const layer = new Layer(options);
|
|
75
|
+
expect(layer).toBeInstanceOf(Layer);
|
|
76
|
+
expect(layer.isQueryable).toBe(false);
|
|
77
|
+
expect(layer.isClickActive).toBe(false);
|
|
78
|
+
expect(layer.isHoverActive).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
66
81
|
test('should called terminate on initialization.', () => {
|
|
67
82
|
const layer = new Layer({ name: 'Layer', olLayer });
|
|
68
83
|
const spy = jest.spyOn(layer, 'terminate');
|
|
@@ -465,7 +480,13 @@ describe('Layer', () => {
|
|
|
465
480
|
expect(spy).toHaveBeenCalledWith(evt.coordinate);
|
|
466
481
|
expect(featureInfo).toBe(goodFeatureInfo);
|
|
467
482
|
expect(fn).toHaveBeenCalledTimes(1);
|
|
483
|
+
expect(fn.mock.calls[0][0]).toBe(goodFeatureInfo.features);
|
|
484
|
+
expect(fn.mock.calls[0][1]).toBe(goodFeatureInfo.layer);
|
|
485
|
+
expect(fn.mock.calls[0][2]).toBe(goodFeatureInfo.coordinate);
|
|
468
486
|
expect(fn2).toHaveBeenCalledTimes(1);
|
|
487
|
+
expect(fn2.mock.calls[0][0]).toBe(goodFeatureInfo.features);
|
|
488
|
+
expect(fn2.mock.calls[0][1]).toBe(goodFeatureInfo.layer);
|
|
489
|
+
expect(fn2.mock.calls[0][2]).toBe(goodFeatureInfo.coordinate);
|
|
469
490
|
done();
|
|
470
491
|
});
|
|
471
492
|
});
|
|
@@ -599,7 +620,13 @@ describe('Layer', () => {
|
|
|
599
620
|
expect(spy).toHaveBeenCalledWith(evt.coordinate);
|
|
600
621
|
expect(featureInfo).toBe(goodFeatureInfo);
|
|
601
622
|
expect(fn).toHaveBeenCalledTimes(1);
|
|
623
|
+
expect(fn.mock.calls[0][0]).toBe(goodFeatureInfo.features);
|
|
624
|
+
expect(fn.mock.calls[0][1]).toBe(goodFeatureInfo.layer);
|
|
625
|
+
expect(fn.mock.calls[0][2]).toBe(goodFeatureInfo.coordinate);
|
|
602
626
|
expect(fn2).toHaveBeenCalledTimes(1);
|
|
627
|
+
expect(fn2.mock.calls[0][0]).toBe(goodFeatureInfo.features);
|
|
628
|
+
expect(fn2.mock.calls[0][1]).toBe(goodFeatureInfo.layer);
|
|
629
|
+
expect(fn2.mock.calls[0][2]).toBe(goodFeatureInfo.coordinate);
|
|
603
630
|
done();
|
|
604
631
|
});
|
|
605
632
|
});
|
|
@@ -3,8 +3,15 @@
|
|
|
3
3
|
import { buffer, containsCoordinate } from 'ol/extent';
|
|
4
4
|
import { unByKey } from 'ol/Observable';
|
|
5
5
|
import Feature from 'ol/Feature';
|
|
6
|
+
import qs from 'query-string';
|
|
6
7
|
import Tracker from '../Tracker';
|
|
7
8
|
import { timeSteps } from '../trackerConfig';
|
|
9
|
+
import createFilters from '../utils/createTrackerFilters';
|
|
10
|
+
|
|
11
|
+
/* Permalink parameter used to filters vehicles */
|
|
12
|
+
const LINE_FILTER = 'publishedlinename';
|
|
13
|
+
const ROUTE_FILTER = 'tripnumber';
|
|
14
|
+
const OPERATOR_FILTER = 'operator';
|
|
8
15
|
|
|
9
16
|
/**
|
|
10
17
|
* TrackerLayerInterface.
|
|
@@ -129,6 +136,13 @@ const TrackerLayerMixin = (Base) =>
|
|
|
129
136
|
live,
|
|
130
137
|
} = options;
|
|
131
138
|
|
|
139
|
+
let {
|
|
140
|
+
regexPublishedLineName,
|
|
141
|
+
publishedLineName,
|
|
142
|
+
tripNumber,
|
|
143
|
+
operator,
|
|
144
|
+
} = options;
|
|
145
|
+
|
|
132
146
|
const initTrackerOptions = {
|
|
133
147
|
pixelRatio: pixelRatio || window.devicePixelRatio || 1,
|
|
134
148
|
interpolate,
|
|
@@ -314,6 +328,74 @@ const TrackerLayerMixin = (Base) =>
|
|
|
314
328
|
default: false,
|
|
315
329
|
writable: true,
|
|
316
330
|
},
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Filter properties used in combination with permalink parameters.
|
|
334
|
+
*/
|
|
335
|
+
publishedLineName: {
|
|
336
|
+
get: () => {
|
|
337
|
+
return publishedLineName;
|
|
338
|
+
},
|
|
339
|
+
set: (newPublishedLineName) => {
|
|
340
|
+
publishedLineName = newPublishedLineName;
|
|
341
|
+
this.updateFilters();
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
tripNumber: {
|
|
345
|
+
get: () => {
|
|
346
|
+
return tripNumber;
|
|
347
|
+
},
|
|
348
|
+
set: (newTripNumber) => {
|
|
349
|
+
tripNumber = newTripNumber;
|
|
350
|
+
this.updateFilters();
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
operator: {
|
|
354
|
+
get: () => {
|
|
355
|
+
return operator;
|
|
356
|
+
},
|
|
357
|
+
set: (newOperator) => {
|
|
358
|
+
operator = newOperator;
|
|
359
|
+
this.updateFilters();
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
regexPublishedLineName: {
|
|
363
|
+
get: () => {
|
|
364
|
+
return regexPublishedLineName;
|
|
365
|
+
},
|
|
366
|
+
set: (newRegex) => {
|
|
367
|
+
regexPublishedLineName = newRegex;
|
|
368
|
+
this.updateFilters();
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Style properties.
|
|
374
|
+
*/
|
|
375
|
+
delayDisplay: {
|
|
376
|
+
value: options.delayDisplay || 300000,
|
|
377
|
+
writable: true,
|
|
378
|
+
},
|
|
379
|
+
delayOutlineColor: {
|
|
380
|
+
value: options.delayOutlineColor || '#000000',
|
|
381
|
+
writable: true,
|
|
382
|
+
},
|
|
383
|
+
useDelayStyle: {
|
|
384
|
+
value: options.useDelayStyle || false,
|
|
385
|
+
writable: true,
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Debug properties.
|
|
390
|
+
*/
|
|
391
|
+
// Not used anymore, but could be useful for debugging.
|
|
392
|
+
// showVehicleTraj: {
|
|
393
|
+
// value:
|
|
394
|
+
// options.showVehicleTraj !== undefined
|
|
395
|
+
// ? options.showVehicleTraj
|
|
396
|
+
// : true,
|
|
397
|
+
// writable: true,
|
|
398
|
+
// },
|
|
317
399
|
});
|
|
318
400
|
}
|
|
319
401
|
|
|
@@ -375,6 +457,7 @@ const TrackerLayerMixin = (Base) =>
|
|
|
375
457
|
*/
|
|
376
458
|
start() {
|
|
377
459
|
this.stop();
|
|
460
|
+
this.updateFilters();
|
|
378
461
|
this.tracker.setVisible(true);
|
|
379
462
|
this.renderTrajectories();
|
|
380
463
|
this.startUpdateTime();
|
|
@@ -587,10 +670,25 @@ const TrackerLayerMixin = (Base) =>
|
|
|
587
670
|
const roundedZoom = Math.round(zoom);
|
|
588
671
|
const timeStep = timeSteps[roundedZoom] || 25;
|
|
589
672
|
const nextTick = Math.max(25, timeStep / this.speed);
|
|
590
|
-
console.log(`Next render in ${nextTick} ms.`);
|
|
673
|
+
// console.log(`Next render in ${nextTick} ms.`);
|
|
591
674
|
return nextTick;
|
|
592
675
|
}
|
|
593
676
|
|
|
677
|
+
/**
|
|
678
|
+
* Update filter provided by properties or permalink.
|
|
679
|
+
*/
|
|
680
|
+
updateFilters() {
|
|
681
|
+
// Setting filters from the permalink if no values defined by the layer.
|
|
682
|
+
const parameters = qs.parse(window.location.search.toLowerCase());
|
|
683
|
+
// filter is the property in TrackerLayerMixin.
|
|
684
|
+
this.filter = createFilters(
|
|
685
|
+
this.publishedLineName || parameters[LINE_FILTER],
|
|
686
|
+
this.tripNumber || parameters[ROUTE_FILTER],
|
|
687
|
+
this.operator || parameters[OPERATOR_FILTER],
|
|
688
|
+
this.regexPublishedLineName,
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
594
692
|
/**
|
|
595
693
|
* @private
|
|
596
694
|
*/
|
|
@@ -101,74 +101,6 @@ export class TrajservLayerInterface {
|
|
|
101
101
|
defaultStyle(trajectory, viewState) {}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const LINE_FILTER = 'publishedlinename';
|
|
105
|
-
const ROUTE_FILTER = 'tripnumber';
|
|
106
|
-
const OPERATOR_FILTER = 'operator';
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create a array of filter functions based on some parameters.
|
|
110
|
-
* @param {string} line
|
|
111
|
-
* @param {string} route
|
|
112
|
-
* @param {string} operator
|
|
113
|
-
* @param {string} regexLine
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
const createFilters = (line, route, operator, regexLine) => {
|
|
117
|
-
const filterList = [];
|
|
118
|
-
|
|
119
|
-
if (!line && !route && !operator && !regexLine) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (regexLine) {
|
|
124
|
-
const regexLineList =
|
|
125
|
-
typeof regexLine === 'string' ? [regexLine] : regexLine;
|
|
126
|
-
const lineFilter = (t) =>
|
|
127
|
-
regexLineList.some((tr) => new RegExp(tr, 'i').test(t.name));
|
|
128
|
-
filterList.push(lineFilter);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (line) {
|
|
132
|
-
const lineFiltersList = typeof line === 'string' ? line.split(',') : line;
|
|
133
|
-
const lineList = lineFiltersList.map((l) =>
|
|
134
|
-
l.replace(/\s+/g, '').toUpperCase(),
|
|
135
|
-
);
|
|
136
|
-
const lineFilter = (l) =>
|
|
137
|
-
lineList.some((filter) => filter === l.name.toUpperCase());
|
|
138
|
-
filterList.push(lineFilter);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (route) {
|
|
142
|
-
const routes = typeof route === 'string' ? route.split(',') : route;
|
|
143
|
-
const routeList = routes.map((item) => parseInt(item, 10));
|
|
144
|
-
const routeFilter = (item) => {
|
|
145
|
-
const routeId = parseInt(item.routeIdentifier.split('.')[0], 10);
|
|
146
|
-
return routeList.some((id) => id === routeId);
|
|
147
|
-
};
|
|
148
|
-
filterList.push(routeFilter);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (operator) {
|
|
152
|
-
const operatorList = typeof operator === 'string' ? [operator] : operator;
|
|
153
|
-
const operatorFilter = (t) =>
|
|
154
|
-
operatorList.some((op) => new RegExp(op, 'i').test(t.operator));
|
|
155
|
-
filterList.push(operatorFilter);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!filterList.length) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return (t) => {
|
|
163
|
-
for (let i = 0; i < filterList.length; i += 1) {
|
|
164
|
-
if (!filterList[i](t)) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return true;
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
|
|
172
104
|
/**
|
|
173
105
|
* Mixin for TrajservLayerInterface.
|
|
174
106
|
*
|
|
@@ -185,12 +117,6 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
185
117
|
*/
|
|
186
118
|
defineProperties(options) {
|
|
187
119
|
super.defineProperties(options);
|
|
188
|
-
let {
|
|
189
|
-
regexPublishedLineName,
|
|
190
|
-
publishedLineName,
|
|
191
|
-
tripNumber,
|
|
192
|
-
operator,
|
|
193
|
-
} = options;
|
|
194
120
|
|
|
195
121
|
let requestIntervalSeconds = 3;
|
|
196
122
|
let defaultApi;
|
|
@@ -205,25 +131,6 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
205
131
|
defaultApi = new TrajservAPI(apiOptions);
|
|
206
132
|
}
|
|
207
133
|
Object.defineProperties(this, {
|
|
208
|
-
showVehicleTraj: {
|
|
209
|
-
value:
|
|
210
|
-
options.showVehicleTraj !== undefined
|
|
211
|
-
? options.showVehicleTraj
|
|
212
|
-
: true,
|
|
213
|
-
writable: true,
|
|
214
|
-
},
|
|
215
|
-
delayDisplay: {
|
|
216
|
-
value: options.delayDisplay || 300000,
|
|
217
|
-
writable: true,
|
|
218
|
-
},
|
|
219
|
-
delayOutlineColor: {
|
|
220
|
-
value: options.delayOutlineColor || '#000000',
|
|
221
|
-
writable: true,
|
|
222
|
-
},
|
|
223
|
-
useDelayStyle: {
|
|
224
|
-
value: options.useDelayStyle || false,
|
|
225
|
-
writable: true,
|
|
226
|
-
},
|
|
227
134
|
requestIntervalSeconds: {
|
|
228
135
|
get: () => {
|
|
229
136
|
return requestIntervalSeconds;
|
|
@@ -238,42 +145,7 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
238
145
|
}
|
|
239
146
|
},
|
|
240
147
|
},
|
|
241
|
-
|
|
242
|
-
get: () => {
|
|
243
|
-
return publishedLineName;
|
|
244
|
-
},
|
|
245
|
-
set: (newPublishedLineName) => {
|
|
246
|
-
publishedLineName = newPublishedLineName;
|
|
247
|
-
this.updateFilters();
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
tripNumber: {
|
|
251
|
-
get: () => {
|
|
252
|
-
return tripNumber;
|
|
253
|
-
},
|
|
254
|
-
set: (newTripNumber) => {
|
|
255
|
-
tripNumber = newTripNumber;
|
|
256
|
-
this.updateFilters();
|
|
257
|
-
},
|
|
258
|
-
},
|
|
259
|
-
operator: {
|
|
260
|
-
get: () => {
|
|
261
|
-
return operator;
|
|
262
|
-
},
|
|
263
|
-
set: (newOperator) => {
|
|
264
|
-
operator = newOperator;
|
|
265
|
-
this.updateFilters();
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
regexPublishedLineName: {
|
|
269
|
-
get: () => {
|
|
270
|
-
return regexPublishedLineName;
|
|
271
|
-
},
|
|
272
|
-
set: (newRegex) => {
|
|
273
|
-
regexPublishedLineName = newRegex;
|
|
274
|
-
this.updateFilters();
|
|
275
|
-
},
|
|
276
|
-
},
|
|
148
|
+
|
|
277
149
|
api: {
|
|
278
150
|
value: options.api || defaultApi,
|
|
279
151
|
},
|
|
@@ -302,7 +174,6 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
302
174
|
}
|
|
303
175
|
|
|
304
176
|
stop() {
|
|
305
|
-
this.journeyId = null;
|
|
306
177
|
this.stopUpdateTrajectories();
|
|
307
178
|
this.abortFetchTrajectories();
|
|
308
179
|
super.stop();
|
|
@@ -314,10 +185,8 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
314
185
|
* @private
|
|
315
186
|
* @override
|
|
316
187
|
*/
|
|
317
|
-
onFeatureHover(
|
|
318
|
-
const
|
|
319
|
-
features: [feature],
|
|
320
|
-
} = featureInfo;
|
|
188
|
+
onFeatureHover(features, layer, coordinate) {
|
|
189
|
+
const [feature] = features;
|
|
321
190
|
let id = null;
|
|
322
191
|
if (feature) {
|
|
323
192
|
id = feature.get('id');
|
|
@@ -327,7 +196,7 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
327
196
|
this.hoverVehicleId = id;
|
|
328
197
|
this.renderTrajectories();
|
|
329
198
|
}
|
|
330
|
-
super.onFeatureHover(
|
|
199
|
+
super.onFeatureHover(features, layer, coordinate);
|
|
331
200
|
}
|
|
332
201
|
|
|
333
202
|
/**
|
|
@@ -336,32 +205,78 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
336
205
|
* @private
|
|
337
206
|
* @override
|
|
338
207
|
*/
|
|
339
|
-
onFeatureClick(
|
|
340
|
-
const
|
|
341
|
-
features: [feature],
|
|
342
|
-
} = featureInfo;
|
|
208
|
+
onFeatureClick(features, layer, coordinate) {
|
|
209
|
+
const [feature] = features;
|
|
343
210
|
if (feature) {
|
|
344
211
|
/** @ignore */
|
|
345
212
|
this.selectedVehicleId = feature.get('id');
|
|
346
213
|
/** @ignore */
|
|
347
214
|
this.journeyId = feature.get('journeyIdentifier');
|
|
348
|
-
this.
|
|
215
|
+
this.highlightTrajectory();
|
|
349
216
|
} else {
|
|
350
217
|
this.selectedVehicleId = null;
|
|
218
|
+
this.journeyId = null;
|
|
351
219
|
}
|
|
352
|
-
super.onFeatureClick(
|
|
220
|
+
super.onFeatureClick(features, layer, coordinate);
|
|
353
221
|
}
|
|
354
222
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.
|
|
364
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Highlight the trajectory of journey.
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
highlightTrajectory() {
|
|
228
|
+
const { selectedVehicleId, journeyId } = this;
|
|
229
|
+
const promises = [
|
|
230
|
+
// Fetch stations information with a trajectory id.
|
|
231
|
+
this.api.fetchTrajectoryStations(
|
|
232
|
+
this.getParams({
|
|
233
|
+
id: selectedVehicleId,
|
|
234
|
+
time: getUTCTimeString(new Date()),
|
|
235
|
+
}),
|
|
236
|
+
),
|
|
237
|
+
// Full trajectory.
|
|
238
|
+
this.api.fetchTrajectoryById(
|
|
239
|
+
this.getParams({
|
|
240
|
+
id: journeyId,
|
|
241
|
+
time: getUTCTimeString(new Date()),
|
|
242
|
+
}),
|
|
243
|
+
),
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
Promise.all(promises)
|
|
247
|
+
.then(([trajStations, fullTraj]) => {
|
|
248
|
+
const stationsCoords = [];
|
|
249
|
+
if (trajStations) {
|
|
250
|
+
trajStations.stations.forEach((station) => {
|
|
251
|
+
stationsCoords.push(station.coordinates);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (fullTraj) {
|
|
256
|
+
const { p: multiLine, t, c: color } = fullTraj;
|
|
257
|
+
const lineCoords = [];
|
|
258
|
+
multiLine.forEach((line) => {
|
|
259
|
+
line.forEach((point) => {
|
|
260
|
+
lineCoords.push([point.x, point.y]);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const lineColor = color ? `#${color}` : getBgColor(t);
|
|
265
|
+
// Don't allow white lines, use red instead.
|
|
266
|
+
const vehiculeColor = /#ffffff/i.test(lineColor)
|
|
267
|
+
? '#ff0000'
|
|
268
|
+
: lineColor;
|
|
269
|
+
|
|
270
|
+
this.drawFullTrajectory(
|
|
271
|
+
stationsCoords,
|
|
272
|
+
lineCoords,
|
|
273
|
+
this.useDelayStyle ? '#a0a0a0' : vehiculeColor,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
.catch(() => {
|
|
278
|
+
this.drawFullTrajectory();
|
|
279
|
+
});
|
|
365
280
|
}
|
|
366
281
|
|
|
367
282
|
abortFetchTrajectories() {
|
|
@@ -370,14 +285,6 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
370
285
|
}
|
|
371
286
|
}
|
|
372
287
|
|
|
373
|
-
updateTrajectoryStations(trajId) {
|
|
374
|
-
const params = this.getParams({
|
|
375
|
-
id: trajId,
|
|
376
|
-
time: getUTCTimeString(new Date()),
|
|
377
|
-
});
|
|
378
|
-
return this.api.fetchTrajectoryStations(params);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
288
|
getParams(extraParams = {}) {
|
|
382
289
|
// The 5 seconds more are used as a buffer if the request takes too long.
|
|
383
290
|
const requestIntervalInMs = (this.requestIntervalSeconds + 5) * 1000;
|
|
@@ -464,6 +371,16 @@ const TrajservLayerMixin = (TrackerLayer) =>
|
|
|
464
371
|
});
|
|
465
372
|
}
|
|
466
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Draw the trajectory as a line with points for each stop.
|
|
376
|
+
*
|
|
377
|
+
* @param {Array} stationsCoords Array of station coordinates in EPSG:4326.
|
|
378
|
+
* @param {Array<ol/coordinate~Coordinate>} lineCoords A list of coordinates in EPSG:3857.
|
|
379
|
+
* @param {string} color The color of the line.
|
|
380
|
+
* @private
|
|
381
|
+
*/
|
|
382
|
+
drawFullTrajectory(stationsCoords, lineCoords, color) {}
|
|
383
|
+
|
|
467
384
|
/**
|
|
468
385
|
* Define the style of the vehicle.
|
|
469
386
|
*
|
|
@@ -128,10 +128,8 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
128
128
|
* @private
|
|
129
129
|
* @override
|
|
130
130
|
*/
|
|
131
|
-
onFeatureHover(
|
|
132
|
-
const
|
|
133
|
-
features: [feature],
|
|
134
|
-
} = featureInfo;
|
|
131
|
+
onFeatureHover(features, layer, coordinate) {
|
|
132
|
+
const [feature] = features;
|
|
135
133
|
let id = null;
|
|
136
134
|
if (feature) {
|
|
137
135
|
id = feature.get('train_id');
|
|
@@ -141,7 +139,7 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
141
139
|
this.hoverVehicleId = id;
|
|
142
140
|
this.renderTrajectories();
|
|
143
141
|
}
|
|
144
|
-
super.onFeatureHover(
|
|
142
|
+
super.onFeatureHover(features, layer, coordinate);
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
/**
|
|
@@ -150,23 +148,28 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
150
148
|
* @private
|
|
151
149
|
* @override
|
|
152
150
|
*/
|
|
153
|
-
onFeatureClick(
|
|
154
|
-
const
|
|
155
|
-
features: [feature],
|
|
156
|
-
} = featureInfo;
|
|
151
|
+
onFeatureClick(features, layer, coordinate) {
|
|
152
|
+
const [feature] = features;
|
|
157
153
|
if (feature) {
|
|
158
154
|
/** @ignore */
|
|
159
155
|
this.selectedVehicleId = feature.get('train_id');
|
|
156
|
+
this.highlightTrajectory();
|
|
160
157
|
} else {
|
|
161
158
|
this.selectedVehicleId = null;
|
|
162
159
|
}
|
|
163
|
-
super.onFeatureClick(
|
|
160
|
+
super.onFeatureClick(features, layer, coordinate);
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
onMessage(data) {
|
|
167
164
|
if (!data.content) {
|
|
168
165
|
return;
|
|
169
166
|
}
|
|
167
|
+
|
|
168
|
+
// Temporary fix to avoid displaying old trains cached .
|
|
169
|
+
if (data.content.properties.mot) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
170
173
|
const feat = this.format.readFeature(data.content);
|
|
171
174
|
|
|
172
175
|
feat.set('timeOffset', Date.now() - data.timestamp);
|
|
@@ -197,6 +200,38 @@ const TralisLayerMixin = (TrackerLayer) =>
|
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
|
|
203
|
+
/**
|
|
204
|
+
* When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
205
|
+
* Then we combine them in one response and send them to inherited layers.
|
|
206
|
+
*
|
|
207
|
+
* @private
|
|
208
|
+
* @override
|
|
209
|
+
*/
|
|
210
|
+
highlightTrajectory() {
|
|
211
|
+
// When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
212
|
+
// Then we combine them in one response and send them to inherited layers.
|
|
213
|
+
const promises = [
|
|
214
|
+
this.api.getStopSequence(this.selectedVehicleId, this.mode),
|
|
215
|
+
this.api.getFullTrajectory(this.selectedVehicleId, this.mode),
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
return Promise.all(promises).then(([stopSequence, fullTrajectory]) => {
|
|
219
|
+
console.log(
|
|
220
|
+
`stopSequence for ${this.selectedVehicleId}:`,
|
|
221
|
+
stopSequence,
|
|
222
|
+
);
|
|
223
|
+
console.log(
|
|
224
|
+
`fullTrajectory for ${this.selectedVehicleId}:`,
|
|
225
|
+
fullTrajectory,
|
|
226
|
+
);
|
|
227
|
+
const response = {
|
|
228
|
+
stopSequence,
|
|
229
|
+
fullTrajectory,
|
|
230
|
+
};
|
|
231
|
+
return response;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
200
235
|
addTrajectory(id, traj, addOnTop) {
|
|
201
236
|
const idx = this.trajectories.findIndex((t) => t.train_id === id);
|
|
202
237
|
const { time_intervals: timeIntervals } = traj;
|