mobility-toolbox-js 2.0.0-beta.46 → 2.0.0-beta.47
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/RealtimeAPI.d.ts +80 -64
- package/api/RealtimeAPI.d.ts.map +1 -1
- package/api/RealtimeAPI.js +58 -45
- package/api/RoutingAPI.d.ts +2 -2
- package/api/RoutingAPI.d.ts.map +1 -1
- package/api/RoutingAPI.js +1 -1
- package/api/StopsAPI.d.ts +14 -12
- package/api/StopsAPI.d.ts.map +1 -1
- package/api/StopsAPI.js +7 -9
- package/api/typedefs.d.ts +84 -10
- package/api/typedefs.d.ts.map +1 -1
- package/api/typedefs.js +3 -1
- package/common/api/WebSocketAPI.d.ts +80 -24
- package/common/api/WebSocketAPI.d.ts.map +1 -1
- package/common/api/WebSocketAPI.js +28 -16
- package/common/controls/{Control.d.ts → ControlCommon.d.ts} +21 -19
- package/common/controls/ControlCommon.d.ts.map +1 -0
- package/common/controls/{Control.js → ControlCommon.js} +21 -8
- package/common/controls/CopyrightControlCommon.d.ts +13 -0
- package/common/controls/CopyrightControlCommon.d.ts.map +1 -0
- package/common/controls/CopyrightControlCommon.js +34 -0
- package/common/controls/StopFinderControlCommon.d.ts +54 -0
- package/common/controls/StopFinderControlCommon.d.ts.map +1 -0
- package/common/{mixins/StopFinderMixin.js → controls/StopFinderControlCommon.js} +25 -38
- package/common/layers/{Layer.d.ts → LayerCommon.d.ts} +34 -21
- package/common/layers/LayerCommon.d.ts.map +1 -0
- package/common/layers/{Layer.js → LayerCommon.js} +15 -9
- package/common/mixins/RealtimeLayerMixin.d.ts +243 -19
- package/common/mixins/RealtimeLayerMixin.d.ts.map +1 -1
- package/common/mixins/RealtimeLayerMixin.js +598 -569
- package/common/mixins/UserInteractionsLayerMixin.d.ts +18 -8
- package/common/mixins/UserInteractionsLayerMixin.d.ts.map +1 -1
- package/common/mixins/UserInteractionsLayerMixin.js +170 -159
- package/common/styles/realtimeDefaultStyle.d.ts +30 -9
- package/common/styles/realtimeDefaultStyle.d.ts.map +1 -1
- package/common/styles/realtimeDefaultStyle.js +41 -17
- package/common/styles/realtimeDelayStyle.d.ts +3 -2
- package/common/styles/realtimeDelayStyle.d.ts.map +1 -1
- package/common/styles/realtimeSimpleStyle.d.ts +1 -1
- package/common/styles/realtimeSimpleStyle.d.ts.map +1 -1
- package/common/styles/realtimeSimpleStyle.js +9 -7
- package/common/typedefs.d.ts +64 -3
- package/common/typedefs.d.ts.map +1 -1
- package/common/typedefs.js +34 -4
- package/common/utils/cleanStopTime.d.ts +3 -2
- package/common/utils/cleanStopTime.d.ts.map +1 -1
- package/common/utils/cleanStopTime.js +0 -3
- package/common/utils/compareDepartures.d.ts +6 -4
- package/common/utils/compareDepartures.d.ts.map +1 -1
- package/common/utils/compareDepartures.js +3 -2
- package/common/utils/createCanvas.d.ts +3 -2
- package/common/utils/createCanvas.d.ts.map +1 -1
- package/common/utils/createTrackerFilters.d.ts +3 -2
- package/common/utils/createTrackerFilters.d.ts.map +1 -1
- package/common/utils/createTrackerFilters.js +3 -3
- package/common/utils/getLayersAsFlatArray.d.ts +1 -1
- package/common/utils/getLayersAsFlatArray.d.ts.map +1 -1
- package/common/utils/getLayersAsFlatArray.js +1 -0
- package/common/utils/getMapboxMapCopyrights.d.ts +13 -3
- package/common/utils/getMapboxMapCopyrights.d.ts.map +1 -1
- package/common/utils/getMapboxMapCopyrights.js +10 -4
- package/common/utils/getMapboxRender.d.ts +3 -1
- package/common/utils/getMapboxRender.d.ts.map +1 -1
- package/common/utils/getMapboxRender.js +1 -2
- package/common/utils/getVehiclePosition.d.ts +1 -1
- package/common/utils/getVehiclePosition.d.ts.map +1 -1
- package/common/utils/removeDuplicate.d.ts +2 -2
- package/common/utils/removeDuplicate.d.ts.map +1 -1
- package/common/utils/renderTrajectories.d.ts +3 -6
- package/common/utils/renderTrajectories.d.ts.map +1 -1
- package/common/utils/renderTrajectories.js +17 -8
- package/common/utils/trackerConfig.d.ts.map +1 -1
- package/common/utils/trackerConfig.js +3 -0
- package/mapbox/controls/CopyrightControl.d.ts +6 -8
- package/mapbox/controls/CopyrightControl.d.ts.map +1 -1
- package/mapbox/controls/CopyrightControl.js +3 -8
- package/mapbox/layers/Layer.js +1 -1
- package/mapbox/layers/RealtimeLayer.d.ts +1 -1
- package/mapbox/layers/RealtimeLayer.d.ts.map +1 -1
- package/mapbox/utils.d.ts +1 -1
- package/mapbox/utils.d.ts.map +1 -1
- package/mbt.js +824 -702
- package/mbt.js.map +3 -3
- package/mbt.min.js +84 -84
- package/mbt.min.js.map +3 -3
- package/ol/controls/CopyrightControl.d.ts +10 -10
- package/ol/controls/CopyrightControl.d.ts.map +1 -1
- package/ol/controls/CopyrightControl.js +8 -8
- package/ol/controls/RoutingControl.d.ts +10 -3
- package/ol/controls/RoutingControl.d.ts.map +1 -1
- package/ol/controls/RoutingControl.js +2 -2
- package/ol/controls/StopFinderControl.d.ts +5 -7
- package/ol/controls/StopFinderControl.d.ts.map +1 -1
- package/ol/controls/StopFinderControl.js +4 -8
- package/ol/layers/Layer.d.ts +57 -9
- package/ol/layers/Layer.d.ts.map +1 -1
- package/ol/layers/Layer.js +17 -8
- package/ol/layers/MapGlLayer.d.ts +67 -0
- package/ol/layers/MapGlLayer.d.ts.map +1 -0
- package/{common/mixins/MapboxLayerMixin.js → ol/layers/MapGlLayer.js} +66 -44
- package/ol/layers/MapboxLayer.d.ts +15 -17
- package/ol/layers/MapboxLayer.d.ts.map +1 -1
- package/ol/layers/MapboxLayer.js +10 -7
- package/ol/layers/MapboxStyleLayer.d.ts +6 -0
- package/ol/layers/MapboxStyleLayer.d.ts.map +1 -1
- package/ol/layers/MaplibreLayer.d.ts +4 -4
- package/ol/layers/MaplibreLayer.d.ts.map +1 -1
- package/ol/layers/MaplibreLayer.js +2 -3
- package/ol/layers/RealtimeLayer.d.ts +106 -30
- package/ol/layers/RealtimeLayer.d.ts.map +1 -1
- package/ol/layers/RealtimeLayer.js +22 -14
- package/ol/styles/fullTrajectoryStyle.d.ts +3 -2
- package/ol/styles/fullTrajectoryStyle.d.ts.map +1 -1
- package/package.json +15 -9
- package/types/common.d.ts +111 -0
- package/types/index.d.ts +1 -0
- package/types/realtime.d.ts +290 -9
- package/api/RealtimeAPI.test.d.ts +0 -2
- package/api/RealtimeAPI.test.d.ts.map +0 -1
- package/api/RealtimeAPI.test.js +0 -67
- package/api/RoutingAPI.test.d.ts +0 -2
- package/api/RoutingAPI.test.d.ts.map +0 -1
- package/api/RoutingAPI.test.js +0 -29
- package/api/StopsAPI.test.d.ts +0 -2
- package/api/StopsAPI.test.d.ts.map +0 -1
- package/api/StopsAPI.test.js +0 -26
- package/common/api/HttpAPI.test.d.ts +0 -2
- package/common/api/HttpAPI.test.d.ts.map +0 -1
- package/common/api/HttpAPI.test.js +0 -54
- package/common/api/WebSocketAPI.test.d.ts +0 -2
- package/common/api/WebSocketAPI.test.d.ts.map +0 -1
- package/common/api/WebSocketAPI.test.js +0 -380
- package/common/controls/Control.d.ts.map +0 -1
- package/common/controls/Control.test.d.ts +0 -2
- package/common/controls/Control.test.d.ts.map +0 -1
- package/common/controls/Control.test.js +0 -89
- package/common/layers/Layer.d.ts.map +0 -1
- package/common/layers/Layer.test.d.ts +0 -2
- package/common/layers/Layer.test.d.ts.map +0 -1
- package/common/layers/Layer.test.js +0 -137
- package/common/mixins/CopyrightMixin.d.ts +0 -22
- package/common/mixins/CopyrightMixin.d.ts.map +0 -1
- package/common/mixins/CopyrightMixin.js +0 -43
- package/common/mixins/MapboxLayerMixin.d.ts +0 -27
- package/common/mixins/MapboxLayerMixin.d.ts.map +0 -1
- package/common/mixins/StopFinderMixin.d.ts +0 -40
- package/common/mixins/StopFinderMixin.d.ts.map +0 -1
- package/common/mixins/UserInteractionsLayerMixin.test.d.ts +0 -2
- package/common/mixins/UserInteractionsLayerMixin.test.d.ts.map +0 -1
- package/common/mixins/UserInteractionsLayerMixin.test.js +0 -214
- package/common/utils/createTrackerFilters.test.d.ts +0 -2
- package/common/utils/createTrackerFilters.test.d.ts.map +0 -1
- package/common/utils/createTrackerFilters.test.js +0 -79
- package/common/utils/getMapboxMapCopyrights.test.d.ts +0 -2
- package/common/utils/getMapboxMapCopyrights.test.d.ts.map +0 -1
- package/common/utils/getMapboxMapCopyrights.test.js +0 -40
- package/common/utils/removeDuplicate.test.d.ts +0 -2
- package/common/utils/removeDuplicate.test.d.ts.map +0 -1
- package/common/utils/removeDuplicate.test.js +0 -19
- package/common/utils/timeUtils.test.d.ts +0 -2
- package/common/utils/timeUtils.test.d.ts.map +0 -1
- package/common/utils/timeUtils.test.js +0 -10
- package/common/utils/trackerConfig.test.d.ts +0 -2
- package/common/utils/trackerConfig.test.d.ts.map +0 -1
- package/common/utils/trackerConfig.test.js +0 -23
- package/mapbox/layers/Layer.test.d.ts +0 -2
- package/mapbox/layers/Layer.test.d.ts.map +0 -1
- package/mapbox/layers/Layer.test.js +0 -204
- package/mapbox/layers/RealtimeLayer.test.d.ts +0 -2
- package/mapbox/layers/RealtimeLayer.test.d.ts.map +0 -1
- package/mapbox/layers/RealtimeLayer.test.js +0 -10
- package/ol/controls/CopyrightControl.test.d.ts +0 -2
- package/ol/controls/CopyrightControl.test.d.ts.map +0 -1
- package/ol/controls/CopyrightControl.test.js +0 -177
- package/ol/controls/RoutingControl.test.d.ts +0 -2
- package/ol/controls/RoutingControl.test.d.ts.map +0 -1
- package/ol/controls/RoutingControl.test.js +0 -150
- package/ol/controls/StopFinderControl.test.d.ts +0 -2
- package/ol/controls/StopFinderControl.test.d.ts.map +0 -1
- package/ol/controls/StopFinderControl.test.js +0 -49
- package/ol/layers/Layer.test.d.ts +0 -2
- package/ol/layers/Layer.test.d.ts.map +0 -1
- package/ol/layers/Layer.test.js +0 -196
- package/ol/layers/MapboxLayer.test.d.ts +0 -2
- package/ol/layers/MapboxLayer.test.d.ts.map +0 -1
- package/ol/layers/MapboxLayer.test.js +0 -164
- package/ol/layers/MapboxStyleLayer.test.d.ts +0 -2
- package/ol/layers/MapboxStyleLayer.test.d.ts.map +0 -1
- package/ol/layers/MapboxStyleLayer.test.js +0 -232
- package/ol/layers/RealtimeLayer.test.d.ts +0 -2
- package/ol/layers/RealtimeLayer.test.d.ts.map +0 -1
- package/ol/layers/RealtimeLayer.test.js +0 -71
- package/ol/layers/RoutingLayer.test.d.ts +0 -2
- package/ol/layers/RoutingLayer.test.d.ts.map +0 -1
- package/ol/layers/RoutingLayer.test.js +0 -39
- package/ol/layers/VectorLayer.test.d.ts +0 -2
- package/ol/layers/VectorLayer.test.d.ts.map +0 -1
- package/ol/layers/VectorLayer.test.js +0 -87
- package/ol/layers/WMSLayer.test.d.ts +0 -2
- package/ol/layers/WMSLayer.test.d.ts.map +0 -1
- package/ol/layers/WMSLayer.test.js +0 -66
|
@@ -17,28 +17,6 @@ import * as trackerConfig from '../utils/trackerConfig';
|
|
|
17
17
|
* RealtimeLayerInterface.
|
|
18
18
|
*/
|
|
19
19
|
export class RealtimeLayerInterface {
|
|
20
|
-
/*
|
|
21
|
-
* Constructor
|
|
22
|
-
|
|
23
|
-
* @param {Object} options Layer options.
|
|
24
|
-
* @param {string} options.url Realtime service url.
|
|
25
|
-
* @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).
|
|
26
|
-
* @param {boolean} [options.debug=false] Display additional debug informations.
|
|
27
|
-
* @param {RealtimeMode} [options.mode=RealtimeMode.TOPOGRAPHIC] Realtime's Mode.
|
|
28
|
-
* @param {number} [options.minZoomInterpolation=8] Minimal zoom when trains positions start to be interpolated.
|
|
29
|
-
* @param {number} [options.minZoomNonTrain=9] Minimal zoom when non trains vehicles are allowed to be displayed.
|
|
30
|
-
*/
|
|
31
|
-
constructor(options = {}) { }
|
|
32
|
-
/**
|
|
33
|
-
* Initialize the layer subscribing to the Realtime api.
|
|
34
|
-
*
|
|
35
|
-
* @param {ol/Map~Map} map
|
|
36
|
-
*/
|
|
37
|
-
attachToMap(map) { }
|
|
38
|
-
/**
|
|
39
|
-
* Terminate the layer unsubscribing to the Realtime api.
|
|
40
|
-
*/
|
|
41
|
-
detachFromMap() { }
|
|
42
20
|
/**
|
|
43
21
|
* Start the clock.
|
|
44
22
|
*/
|
|
@@ -60,6 +38,10 @@ export class RealtimeLayerInterface {
|
|
|
60
38
|
* @param {RealtimeMode} mode Realtime mode
|
|
61
39
|
*/
|
|
62
40
|
setMode(mode) { }
|
|
41
|
+
/**
|
|
42
|
+
* Render the trajectories
|
|
43
|
+
*/
|
|
44
|
+
renderTrajectories() { }
|
|
63
45
|
/**
|
|
64
46
|
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
65
47
|
*
|
|
@@ -76,575 +58,622 @@ export class RealtimeLayerInterface {
|
|
|
76
58
|
* @return {Class} A class that implements {RealtimeLayerInterface} class and extends Base;
|
|
77
59
|
* @private
|
|
78
60
|
*/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
value:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
61
|
+
function RealtimeLayerMixin(Base) {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
return class Mixin extends Base {
|
|
64
|
+
constructor(options) {
|
|
65
|
+
super(Object.assign({ hitTolerance: 10 }, options));
|
|
66
|
+
this.debug = options.debug || false;
|
|
67
|
+
this.mode = options.mode || RealtimeModes.TOPOGRAPHIC;
|
|
68
|
+
this.api = options.api || new RealtimeAPI(options);
|
|
69
|
+
this.tenant = options.tenant || ''; // sbb,sbh or sbm
|
|
70
|
+
this.minZoomNonTrain = options.minZoomNonTrain || 9; // Min zoom level from which non trains are allowed to be displayed. Min value is 9 (as configured by the server
|
|
71
|
+
this.minZoomInterpolation = options.minZoomInterpolation || 8; // Min zoom level from which trains positions are not interpolated.
|
|
72
|
+
this.format = new GeoJSON();
|
|
73
|
+
this.generalizationLevelByZoom = options.generalizationLevelByZoom || [
|
|
74
|
+
5, 5, 5, 5, 5, 5, 5, 5, 10, 30, 30, 100, 100, 100,
|
|
75
|
+
];
|
|
76
|
+
this.getGeneralizationLevelByZoom = (zoom) => {
|
|
77
|
+
return ((options.getGeneralizationLevelByZoom &&
|
|
78
|
+
options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom)) ||
|
|
79
|
+
this.generalizationLevelByZoom[zoom]);
|
|
80
|
+
};
|
|
81
|
+
this.renderTimeIntervalByZoom = options.renderTimeIntervalByZoom || [
|
|
82
|
+
100000, 50000, 40000, 30000, 20000, 15000, 10000, 5000, 2000, 1000, 400,
|
|
83
|
+
300, 250, 180, 90, 60, 50, 50, 50, 50, 50,
|
|
84
|
+
];
|
|
85
|
+
this.getRenderTimeIntervalByZoom = (zoom) => {
|
|
86
|
+
return ((options.getRenderTimeIntervalByZoom &&
|
|
87
|
+
options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom)) ||
|
|
88
|
+
this.renderTimeIntervalByZoom[zoom]);
|
|
89
|
+
};
|
|
90
|
+
// This property will call api.setBbox on each movend event
|
|
91
|
+
this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;
|
|
92
|
+
// Define throttling and debounce render function
|
|
93
|
+
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });
|
|
94
|
+
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true, trailing: true, maxWait: 5000 });
|
|
95
|
+
// Bind callbacks
|
|
96
|
+
this.onFeatureHover = this.onFeatureHover.bind(this);
|
|
97
|
+
this.onFeatureClick = this.onFeatureClick.bind(this);
|
|
98
|
+
this.renderTrajectoriesInternal =
|
|
99
|
+
this.renderTrajectoriesInternal.bind(this);
|
|
100
|
+
this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);
|
|
101
|
+
this.onDeleteTrajectoryMessage =
|
|
102
|
+
this.onDeleteTrajectoryMessage.bind(this);
|
|
103
|
+
this.onDocumentVisibilityChange =
|
|
104
|
+
this.onDocumentVisibilityChange.bind(this);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Define layer's properties.
|
|
108
|
+
*
|
|
109
|
+
* @ignore
|
|
110
|
+
*/
|
|
111
|
+
defineProperties(options) {
|
|
112
|
+
const { style, speed, pixelRatio, hoverVehicleId, selectedVehicleId, filter, sort, time, live, canvas, styleOptions, } = options;
|
|
113
|
+
let currSpeed = speed || 1;
|
|
114
|
+
let currTime = time || new Date();
|
|
115
|
+
super.defineProperties(options);
|
|
116
|
+
Object.defineProperties(this, {
|
|
117
|
+
isTrackerLayer: { value: true },
|
|
118
|
+
canvas: {
|
|
119
|
+
value: canvas || document.createElement('canvas'),
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Style function used to render a vehicle.
|
|
123
|
+
*/
|
|
124
|
+
style: {
|
|
125
|
+
value: style || realtimeDefaultStyle,
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Custom options to pass as last parameter of the style function.
|
|
129
|
+
*/
|
|
130
|
+
styleOptions: {
|
|
131
|
+
value: Object.assign(Object.assign({}, trackerConfig), (styleOptions || {})),
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Speed of the wheel of time.
|
|
135
|
+
* If live property is true. The speed is ignored.
|
|
136
|
+
*/
|
|
137
|
+
speed: {
|
|
138
|
+
get: () => currSpeed,
|
|
139
|
+
set: (newSpeed) => {
|
|
140
|
+
currSpeed = newSpeed;
|
|
141
|
+
this.start();
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
/**
|
|
145
|
+
* Function to filter which vehicles to display.
|
|
146
|
+
*/
|
|
147
|
+
filter: {
|
|
148
|
+
value: filter,
|
|
149
|
+
writable: true,
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* Function to sort the vehicles to display.
|
|
153
|
+
*/
|
|
154
|
+
sort: {
|
|
155
|
+
value: sort,
|
|
156
|
+
writable: true,
|
|
158
157
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
},
|
|
167
|
-
/**
|
|
168
|
-
* Function to sort the vehicles to display.
|
|
169
|
-
*/
|
|
170
|
-
sort: {
|
|
171
|
-
value: sort,
|
|
172
|
-
writable: true,
|
|
173
|
-
},
|
|
174
|
-
/**
|
|
175
|
-
* If true. The layer will always use Date.now() on the next tick to render the trajectories.
|
|
176
|
-
* When true, setting the time property has no effect.
|
|
177
|
-
*/
|
|
178
|
-
live: {
|
|
179
|
-
value: live === false ? live : true,
|
|
180
|
-
writable: true,
|
|
181
|
-
},
|
|
182
|
-
/**
|
|
183
|
-
* Time used to display the trajectories. Can be a Date or a number in ms representing a Date.
|
|
184
|
-
* If live property is true. The setter does nothing.
|
|
185
|
-
*/
|
|
186
|
-
time: {
|
|
187
|
-
get: () => currTime,
|
|
188
|
-
set: (newTime) => {
|
|
189
|
-
currTime = newTime && newTime.getTime ? newTime : new Date(newTime);
|
|
190
|
-
this.renderTrajectories();
|
|
158
|
+
/**
|
|
159
|
+
* If true. The layer will always use Date.now() on the next tick to render the trajectories.
|
|
160
|
+
* When true, setting the time property has no effect.
|
|
161
|
+
*/
|
|
162
|
+
live: {
|
|
163
|
+
value: live === false ? live : true,
|
|
164
|
+
writable: true,
|
|
191
165
|
},
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Time used to display the trajectories. Can be a Date or a number in ms representing a Date.
|
|
168
|
+
* If live property is true. The setter does nothing.
|
|
169
|
+
*/
|
|
170
|
+
time: {
|
|
171
|
+
get: () => currTime,
|
|
172
|
+
set: (newTime) => {
|
|
173
|
+
currTime = newTime && newTime.getTime ? newTime : new Date(newTime);
|
|
174
|
+
// @ts-ignore function without parameters is defined in subclasses
|
|
175
|
+
this.renderTrajectories();
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Keep track of which trajectories are stored.
|
|
180
|
+
*/
|
|
181
|
+
trajectories: {
|
|
182
|
+
value: {},
|
|
183
|
+
writable: true,
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* Id of the hovered vehicle.
|
|
187
|
+
*/
|
|
188
|
+
hoverVehicleId: {
|
|
189
|
+
value: hoverVehicleId,
|
|
190
|
+
writable: true,
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* Id of the selected vehicle.
|
|
194
|
+
*/
|
|
195
|
+
selectedVehicleId: {
|
|
196
|
+
value: selectedVehicleId,
|
|
197
|
+
writable: true,
|
|
198
|
+
},
|
|
199
|
+
/**
|
|
200
|
+
* Id of the selected vehicle.
|
|
201
|
+
*/
|
|
202
|
+
pixelRatio: {
|
|
203
|
+
value: pixelRatio ||
|
|
204
|
+
(typeof window !== 'undefined' ? window.devicePixelRatio : 1),
|
|
205
|
+
writable: true,
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* If true, encapsulates the renderTrajectories calls in a requestAnimationFrame.
|
|
209
|
+
*/
|
|
210
|
+
useRequestAnimationFrame: {
|
|
211
|
+
value: options.useRequestAnimationFrame || false,
|
|
212
|
+
writable: true,
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* If true, encapsulates the renderTrajectories calls in a throttle function. Default to true.
|
|
216
|
+
*/
|
|
217
|
+
useThrottle: {
|
|
218
|
+
value: options.useThrottle !== false,
|
|
219
|
+
writable: true,
|
|
220
|
+
},
|
|
221
|
+
/**
|
|
222
|
+
* If true, encapsulates the renderTrajectories calls in a debounce function.
|
|
223
|
+
*/
|
|
224
|
+
useDebounce: {
|
|
225
|
+
value: options.useDebounce || false,
|
|
226
|
+
writable: true,
|
|
227
|
+
},
|
|
228
|
+
/**
|
|
229
|
+
* Debug properties.
|
|
230
|
+
*/
|
|
231
|
+
// Not used anymore, but could be useful for debugging.
|
|
232
|
+
// showVehicleTraj: {
|
|
233
|
+
// value:
|
|
234
|
+
// options.showVehicleTraj !== undefined
|
|
235
|
+
// ? options.showVehicleTraj
|
|
236
|
+
// : true,
|
|
237
|
+
// writable: true,
|
|
238
|
+
// },
|
|
239
|
+
});
|
|
261
240
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
241
|
+
attachToMap(map) {
|
|
242
|
+
super.attachToMap(map);
|
|
243
|
+
// If the layer is visible we start the rendering clock
|
|
244
|
+
if (this.visible) {
|
|
265
245
|
this.start();
|
|
266
246
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
detachFromMap() {
|
|
276
|
-
document.removeEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
277
|
-
this.stop();
|
|
278
|
-
unByKey(this.visibilityRef);
|
|
279
|
-
const context = this.canvas.getContext('2d');
|
|
280
|
-
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
281
|
-
super.detachFromMap();
|
|
282
|
-
}
|
|
283
|
-
start() {
|
|
284
|
-
this.stop();
|
|
285
|
-
this.renderTrajectories();
|
|
286
|
-
this.startUpdateTime();
|
|
287
|
-
this.api.open();
|
|
288
|
-
this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
289
|
-
this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
290
|
-
if (this.isUpdateBboxOnMoveEnd) {
|
|
291
|
-
// Update the bbox on each move end
|
|
292
|
-
this.setBbox();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Start the clock.
|
|
297
|
-
* @private
|
|
298
|
-
*/
|
|
299
|
-
startUpdateTime() {
|
|
300
|
-
this.stopUpdateTime();
|
|
301
|
-
this.updateTimeDelay = this.getRefreshTimeInMs();
|
|
302
|
-
this.updateTimeInterval = setInterval(() => {
|
|
303
|
-
// When live=true, we update the time with new Date();
|
|
304
|
-
this.time = this.live
|
|
305
|
-
? new Date()
|
|
306
|
-
: this.time.getTime() + this.updateTimeDelay * this.speed;
|
|
307
|
-
}, this.updateTimeDelay);
|
|
308
|
-
}
|
|
309
|
-
stop() {
|
|
310
|
-
this.api.unsubscribeTrajectory(this.onTrajectoryMessage);
|
|
311
|
-
this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);
|
|
312
|
-
this.api.close();
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Stop the clock.
|
|
316
|
-
* @private
|
|
317
|
-
*/
|
|
318
|
-
stopUpdateTime() {
|
|
319
|
-
if (this.updateTimeInterval) {
|
|
320
|
-
clearInterval(this.updateTimeInterval);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.
|
|
325
|
-
*
|
|
326
|
-
* @param {object} viewState The view state of the map.
|
|
327
|
-
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
328
|
-
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
329
|
-
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
330
|
-
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
331
|
-
* @param {number} viewState.resolution Resolution of the map to render.
|
|
332
|
-
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
333
|
-
* drawn at the last known coordinate. Use this for performance optimization
|
|
334
|
-
* during map navigation.
|
|
335
|
-
* @private
|
|
336
|
-
*/
|
|
337
|
-
renderTrajectoriesInternal(viewState, noInterpolate) {
|
|
338
|
-
if (!this.map) {
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
const time = this.live ? Date.now() : this.time;
|
|
342
|
-
const trajectories = Object.values(this.trajectories);
|
|
343
|
-
// console.time('sort');
|
|
344
|
-
if (this.sort) {
|
|
345
|
-
trajectories.sort(this.sort);
|
|
346
|
-
}
|
|
347
|
-
// console.timeEnd('sort');
|
|
348
|
-
// console.time('render');
|
|
349
|
-
this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio, time }), Object.assign({ noInterpolate: viewState.zoom < this.minZoomInterpolation ? true : noInterpolate, hoverVehicleId: this.hoverVehicleId, selectedVehicleId: this.selectedVehicleId }, this.styleOptions));
|
|
350
|
-
// console.timeEnd('render');
|
|
351
|
-
return true;
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Render the trajectories requesting an animation frame and cancelling the previous one.
|
|
355
|
-
* This function must be overrided by children to provide the correct parameters.
|
|
356
|
-
*
|
|
357
|
-
* @param {object} viewState The view state of the map.
|
|
358
|
-
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
359
|
-
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
360
|
-
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
361
|
-
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
362
|
-
* @param {number} viewState.resolution Resolution of the map to render.
|
|
363
|
-
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
364
|
-
* drawn at the last known coordinate. Use this for performance optimization
|
|
365
|
-
* during map navigation.
|
|
366
|
-
* @private
|
|
367
|
-
*/
|
|
368
|
-
renderTrajectories(viewState, noInterpolate) {
|
|
369
|
-
if (this.requestId) {
|
|
370
|
-
cancelAnimationFrame(this.requestId);
|
|
371
|
-
this.requestId = null;
|
|
372
|
-
}
|
|
373
|
-
if (!noInterpolate && this.useRequestAnimationFrame) {
|
|
374
|
-
this.requestId = requestAnimationFrame(() => {
|
|
375
|
-
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
247
|
+
// On change of visibility we start/stop the rendering clock
|
|
248
|
+
this.visibilityRef = this.on('change:visible', (evt) => {
|
|
249
|
+
if (evt.target.visible) {
|
|
250
|
+
this.start();
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
this.stop();
|
|
254
|
+
}
|
|
376
255
|
});
|
|
256
|
+
// To avoid browser hanging when the tab is not visible for a certain amount of time,
|
|
257
|
+
// We stop the rendering and the websocket when hide and start again when show.
|
|
258
|
+
document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
377
259
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
this.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
setBbox(extent, zoom) {
|
|
389
|
-
// Clean trajectories before sending the new bbox
|
|
390
|
-
// Purge trajectories:
|
|
391
|
-
// - which are outside the extent
|
|
392
|
-
// - when it's bus and zoom level is too low for them
|
|
393
|
-
const keys = Object.keys(this.trajectories);
|
|
394
|
-
for (let i = keys.length - 1; i >= 0; i -= 1) {
|
|
395
|
-
this.purgeTrajectory(this.trajectories[keys[i]], extent, zoom);
|
|
396
|
-
}
|
|
397
|
-
const bbox = [...extent];
|
|
398
|
-
if (this.isUpdateBboxOnMoveEnd) {
|
|
399
|
-
bbox.push(zoom);
|
|
400
|
-
if (this.tenant) {
|
|
401
|
-
bbox.push(`tenant=${this.tenant}`);
|
|
402
|
-
}
|
|
403
|
-
/* @ignore */
|
|
404
|
-
this.generalizationLevel = this.getGeneralizationLevelByZoom(zoom);
|
|
405
|
-
if (this.generalizationLevel) {
|
|
406
|
-
bbox.push(`gen=${this.generalizationLevel}`);
|
|
260
|
+
detachFromMap() {
|
|
261
|
+
document.removeEventListener('visibilitychange', this.onDocumentVisibilityChange);
|
|
262
|
+
this.stop();
|
|
263
|
+
unByKey(this.visibilityRef);
|
|
264
|
+
if (this.canvas) {
|
|
265
|
+
const context = this.canvas.getContext('2d');
|
|
266
|
+
context === null || context === void 0 ? void 0 : context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
267
|
+
super.detachFromMap();
|
|
407
268
|
}
|
|
408
269
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
* @private
|
|
423
|
-
* @param {number} zoom
|
|
424
|
-
*/
|
|
425
|
-
getRefreshTimeInMs(zoom) {
|
|
426
|
-
var _a;
|
|
427
|
-
const roundedZoom = Math.round(zoom);
|
|
428
|
-
const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;
|
|
429
|
-
const nextTick = Math.max(25, timeStep / this.speed);
|
|
430
|
-
const nextThrottleTick = Math.min(nextTick, 500);
|
|
431
|
-
// TODO: see if this should go elsewhere.
|
|
432
|
-
if (this.useThrottle) {
|
|
433
|
-
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });
|
|
434
|
-
}
|
|
435
|
-
else if (this.useDebounce) {
|
|
436
|
-
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true, maxWait: 5000 });
|
|
437
|
-
}
|
|
438
|
-
if ((_a = this.api) === null || _a === void 0 ? void 0 : _a.buffer) {
|
|
439
|
-
const [, size] = this.api.buffer;
|
|
440
|
-
this.api.buffer = [nextThrottleTick, size];
|
|
270
|
+
start() {
|
|
271
|
+
this.stop();
|
|
272
|
+
// @ts-ignore function without parameters must be define in subclasses
|
|
273
|
+
this.renderTrajectories();
|
|
274
|
+
this.startUpdateTime();
|
|
275
|
+
this.api.open();
|
|
276
|
+
this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
277
|
+
this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
278
|
+
if (this.isUpdateBboxOnMoveEnd) {
|
|
279
|
+
// Update the bbox on each move end
|
|
280
|
+
// @ts-ignore function without parameters defined by subclasses
|
|
281
|
+
this.setBbox();
|
|
282
|
+
}
|
|
441
283
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Start the clock.
|
|
286
|
+
* @private
|
|
287
|
+
*/
|
|
288
|
+
startUpdateTime() {
|
|
289
|
+
this.stopUpdateTime();
|
|
290
|
+
this.updateTimeDelay = this.getRefreshTimeInMs() || 0;
|
|
291
|
+
this.updateTimeInterval = window.setInterval(() => {
|
|
292
|
+
// When live=true, we update the time with new Date();
|
|
293
|
+
if (this.live) {
|
|
294
|
+
this.time = new Date();
|
|
295
|
+
}
|
|
296
|
+
else if (this.time && this.updateTimeDelay && this.speed) {
|
|
297
|
+
this.time = new Date(this.time.getTime() + this.updateTimeDelay * this.speed);
|
|
298
|
+
}
|
|
299
|
+
}, this.updateTimeDelay);
|
|
300
|
+
}
|
|
301
|
+
stop() {
|
|
302
|
+
this.api.unsubscribeTrajectory(this.onTrajectoryMessage);
|
|
303
|
+
this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);
|
|
304
|
+
this.api.close();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Stop the clock.
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
stopUpdateTime() {
|
|
311
|
+
if (this.updateTimeInterval) {
|
|
312
|
+
clearInterval(this.updateTimeInterval);
|
|
313
|
+
this.updateTimeInterval = undefined;
|
|
314
|
+
}
|
|
467
315
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.
|
|
318
|
+
*
|
|
319
|
+
* @param {object} viewState The view state of the map.
|
|
320
|
+
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
321
|
+
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
322
|
+
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
323
|
+
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
324
|
+
* @param {number} viewState.resolution Resolution of the map to render.
|
|
325
|
+
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
326
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
327
|
+
* during map navigation.
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
330
|
+
renderTrajectoriesInternal(viewState, noInterpolate = false) {
|
|
331
|
+
var _a;
|
|
332
|
+
if (!this.map || !this.trajectories) {
|
|
333
|
+
return false;
|
|
473
334
|
}
|
|
474
|
-
|
|
475
|
-
|
|
335
|
+
const time = this.live ? Date.now() : (_a = this.time) === null || _a === void 0 ? void 0 : _a.getTime();
|
|
336
|
+
const trajectories = Object.values(this.trajectories);
|
|
337
|
+
// console.time('sort');
|
|
338
|
+
if (this.sort) {
|
|
339
|
+
// @ts-ignore
|
|
340
|
+
trajectories.sort(this.sort);
|
|
476
341
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
*
|
|
487
|
-
* @param {string} id The vehicle identifier (the train_id property).
|
|
488
|
-
* @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
489
|
-
*/
|
|
490
|
-
getTrajectoryInfos(id) {
|
|
491
|
-
// When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
492
|
-
// Then we combine them in one response and send them to inherited layers.
|
|
493
|
-
const promises = [
|
|
494
|
-
this.api.getStopSequence(id, this.mode),
|
|
495
|
-
this.api.getFullTrajectory(id, this.mode, this.generalizationLevel),
|
|
496
|
-
];
|
|
497
|
-
return Promise.all(promises).then(([stopSequence, fullTrajectory]) => {
|
|
498
|
-
const response = {
|
|
499
|
-
stopSequence,
|
|
500
|
-
fullTrajectory,
|
|
501
|
-
};
|
|
502
|
-
return response;
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Determine if the trajectory is useless and should be removed from the list or not.
|
|
507
|
-
* By default, this function exclude vehicles:
|
|
508
|
-
* - that have their trajectory outside the current extent and
|
|
509
|
-
* - that are not a train and zoom level is lower than layer's minZoomNonTrain property.
|
|
510
|
-
*
|
|
511
|
-
* @param {RealtimeTrajectory} trajectory
|
|
512
|
-
* @param {Array<number>} extent
|
|
513
|
-
* @param {number} zoom
|
|
514
|
-
* @return {boolean} if the trajectory must be displayed or not.
|
|
515
|
-
* @ignore
|
|
516
|
-
*/
|
|
517
|
-
purgeTrajectory(trajectory, extent, zoom) {
|
|
518
|
-
const { type, bounds, train_id: id } = trajectory.properties;
|
|
519
|
-
if (!intersects(extent, bounds) ||
|
|
520
|
-
(type !== 'rail' && zoom < (this.minZoomNonTrain || 9))) {
|
|
521
|
-
this.removeTrajectory(id);
|
|
342
|
+
// console.timeEnd('sort');
|
|
343
|
+
if (!this.canvas || !this.style) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
// console.time('render');
|
|
347
|
+
this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time }), Object.assign({ noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation
|
|
348
|
+
? true
|
|
349
|
+
: noInterpolate, hoverVehicleId: this.hoverVehicleId, selectedVehicleId: this.selectedVehicleId }, this.styleOptions));
|
|
350
|
+
// console.timeEnd('render');
|
|
522
351
|
return true;
|
|
523
352
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Callback on websocket's trajectory channel events.
|
|
564
|
-
* It adds a trajectory to the list.
|
|
565
|
-
*
|
|
566
|
-
* @private
|
|
567
|
-
*/
|
|
568
|
-
onTrajectoryMessage(data) {
|
|
569
|
-
if (!data.content) {
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
const trajectory = data.content;
|
|
573
|
-
const { geometry, properties: { train_id: id, time_since_update: timeSinceUpdate, raw_coordinates: rawCoordinates, }, } = trajectory;
|
|
574
|
-
// ignore old events [SBAHNM-97]
|
|
575
|
-
if (timeSinceUpdate < 0) {
|
|
576
|
-
return;
|
|
353
|
+
/**
|
|
354
|
+
* Render the trajectories requesting an animation frame and cancelling the previous one.
|
|
355
|
+
* This function must be overrided by children to provide the correct parameters.
|
|
356
|
+
*
|
|
357
|
+
* @param {object} viewState The view state of the map.
|
|
358
|
+
* @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.
|
|
359
|
+
* @param {number[4]} viewState.extent Extent of the map in mercator coordinates.
|
|
360
|
+
* @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.
|
|
361
|
+
* @param {number} [viewState.rotation = 0] Rotation of the map to render.
|
|
362
|
+
* @param {number} viewState.resolution Resolution of the map to render.
|
|
363
|
+
* @param {boolean} noInterpolate If true trajectories are not interpolated but
|
|
364
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
365
|
+
* during map navigation.
|
|
366
|
+
* @private
|
|
367
|
+
*/
|
|
368
|
+
renderTrajectories(viewState, noInterpolate) {
|
|
369
|
+
if (this.requestId) {
|
|
370
|
+
cancelAnimationFrame(this.requestId);
|
|
371
|
+
this.requestId = undefined;
|
|
372
|
+
}
|
|
373
|
+
if (!viewState) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (!noInterpolate && this.useRequestAnimationFrame) {
|
|
377
|
+
this.requestId = requestAnimationFrame(() => {
|
|
378
|
+
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
else if (!noInterpolate && this.useDebounce) {
|
|
382
|
+
this.debounceRenderTrajectories(viewState, noInterpolate);
|
|
383
|
+
}
|
|
384
|
+
else if (!noInterpolate && this.useThrottle) {
|
|
385
|
+
this.throttleRenderTrajectories(viewState, noInterpolate);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
this.renderTrajectoriesInternal(viewState, noInterpolate);
|
|
389
|
+
}
|
|
577
390
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
391
|
+
setBbox(extent, zoom) {
|
|
392
|
+
// Clean trajectories before sending the new bbox
|
|
393
|
+
// Purge trajectories:
|
|
394
|
+
// - which are outside the extent
|
|
395
|
+
// - when it's bus and zoom level is too low for them
|
|
396
|
+
if (this.trajectories && extent && zoom) {
|
|
397
|
+
const keys = Object.keys(this.trajectories);
|
|
398
|
+
for (let i = keys.length - 1; i >= 0; i -= 1) {
|
|
399
|
+
this.purgeTrajectory(this.trajectories[keys[i]], extent, zoom);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (!extent) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const bbox = [...extent];
|
|
406
|
+
if (this.isUpdateBboxOnMoveEnd && zoom) {
|
|
407
|
+
bbox.push(zoom);
|
|
408
|
+
if (this.tenant) {
|
|
409
|
+
bbox.push(`tenant=${this.tenant}`);
|
|
410
|
+
}
|
|
411
|
+
/* @ignore */
|
|
412
|
+
this.generalizationLevel = this.getGeneralizationLevelByZoom(zoom);
|
|
413
|
+
if (this.generalizationLevel) {
|
|
414
|
+
bbox.push(`gen=${this.generalizationLevel}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
this.api.bbox = bbox;
|
|
581
418
|
}
|
|
582
|
-
|
|
583
|
-
this.mode ===
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
419
|
+
setMode(mode) {
|
|
420
|
+
if (this.mode === mode) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
this.mode = mode;
|
|
424
|
+
this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
425
|
+
this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Get the duration before the next update depending on zoom level.
|
|
429
|
+
*
|
|
430
|
+
* @private
|
|
431
|
+
* @param {number} zoom
|
|
432
|
+
*/
|
|
433
|
+
getRefreshTimeInMs(zoom = 0) {
|
|
434
|
+
var _a;
|
|
435
|
+
const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;
|
|
436
|
+
const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;
|
|
437
|
+
const nextTick = Math.max(25, timeStep / (this.speed || 1));
|
|
438
|
+
const nextThrottleTick = Math.min(nextTick, 500);
|
|
439
|
+
// TODO: see if this should go elsewhere.
|
|
440
|
+
if (this.useThrottle) {
|
|
441
|
+
this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });
|
|
442
|
+
}
|
|
443
|
+
else if (this.useDebounce) {
|
|
444
|
+
this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true, maxWait: 5000 });
|
|
445
|
+
}
|
|
446
|
+
if ((_a = this.api) === null || _a === void 0 ? void 0 : _a.buffer) {
|
|
447
|
+
const [, size] = this.api.buffer;
|
|
448
|
+
this.api.buffer = [nextThrottleTick, size];
|
|
449
|
+
}
|
|
450
|
+
return nextTick;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Get vehicle.
|
|
454
|
+
* @param {function} filterFc A function use to filter results.
|
|
455
|
+
* @return {Array<Object>} Array of vehicle.
|
|
456
|
+
*/
|
|
457
|
+
getVehicle(filterFc) {
|
|
458
|
+
return ((this.trajectories &&
|
|
459
|
+
// @ts-ignore
|
|
460
|
+
Object.values(this.trajectories).filter(filterFc)) ||
|
|
461
|
+
[]);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Request feature information for a given coordinate.
|
|
465
|
+
*
|
|
466
|
+
* @param {ol/coordinate~Coordinate} coordinate Coordinate.
|
|
467
|
+
* @param {Object} options Options See child classes to see which options are supported.
|
|
468
|
+
* @param {number} [options.resolution=1] The resolution of the map.
|
|
469
|
+
* @param {number} [options.nb=Infinity] The max number of vehicles to return.
|
|
470
|
+
* @return {Promise<FeatureInfo>} Promise with features, layer and coordinate.
|
|
471
|
+
*/
|
|
472
|
+
getFeatureInfoAtCoordinate(coordinate, options) {
|
|
473
|
+
const { resolution, nb } = options;
|
|
474
|
+
const ext = buffer([...coordinate, ...coordinate], this.hitTolerance * resolution);
|
|
475
|
+
let trajectories = Object.values(this.trajectories || {});
|
|
476
|
+
if (this.sort) {
|
|
477
|
+
// @ts-ignore
|
|
478
|
+
trajectories = trajectories.sort(this.sort);
|
|
479
|
+
}
|
|
480
|
+
const vehicles = [];
|
|
481
|
+
for (let i = 0; i < trajectories.length; i += 1) {
|
|
482
|
+
if (trajectories[i].properties.coordinate &&
|
|
483
|
+
containsCoordinate(ext, trajectories[i].properties.coordinate)) {
|
|
484
|
+
vehicles.push(trajectories[i]);
|
|
485
|
+
}
|
|
486
|
+
if (vehicles.length === nb) {
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return Promise.resolve({
|
|
491
|
+
layer: this,
|
|
492
|
+
features: vehicles.map((vehicle) => this.format.readFeature(vehicle)),
|
|
493
|
+
coordinate,
|
|
494
|
+
});
|
|
589
495
|
}
|
|
590
|
-
|
|
591
|
-
|
|
496
|
+
/**
|
|
497
|
+
* Request the stopSequence and the fullTrajectory informations for a vehicle.
|
|
498
|
+
*
|
|
499
|
+
* @param {string} id The vehicle identifier (the train_id property).
|
|
500
|
+
* @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.
|
|
501
|
+
*/
|
|
502
|
+
getTrajectoryInfos(id) {
|
|
503
|
+
// When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.
|
|
504
|
+
// Then we combine them in one response and send them to inherited layers.
|
|
505
|
+
const promises = [
|
|
506
|
+
this.api.getStopSequence(id),
|
|
507
|
+
this.api.getFullTrajectory(id, this.mode, this.generalizationLevel),
|
|
508
|
+
];
|
|
509
|
+
return Promise.all(promises).then(([stopSequence, fullTrajectory]) => {
|
|
510
|
+
const response = {
|
|
511
|
+
stopSequence,
|
|
512
|
+
fullTrajectory,
|
|
513
|
+
};
|
|
514
|
+
return response;
|
|
515
|
+
});
|
|
592
516
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
517
|
+
/**
|
|
518
|
+
* Determine if the trajectory is useless and should be removed from the list or not.
|
|
519
|
+
* By default, this function exclude vehicles:
|
|
520
|
+
* - that have their trajectory outside the current extent and
|
|
521
|
+
* - that are not a train and zoom level is lower than layer's minZoomNonTrain property.
|
|
522
|
+
*
|
|
523
|
+
* @param {RealtimeTrajectory} trajectory
|
|
524
|
+
* @param {Array<number>} extent
|
|
525
|
+
* @param {number} zoom
|
|
526
|
+
* @return {boolean} if the trajectory must be displayed or not.
|
|
527
|
+
* @ignore
|
|
528
|
+
*/
|
|
529
|
+
purgeTrajectory(trajectory, extent, zoom) {
|
|
530
|
+
const { type, bounds } = trajectory.properties;
|
|
531
|
+
if (!intersects(extent, bounds) ||
|
|
532
|
+
(type !== 'rail' && zoom < (this.minZoomNonTrain || 9))) {
|
|
533
|
+
this.removeTrajectory(trajectory);
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
return false;
|
|
607
537
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
538
|
+
/**
|
|
539
|
+
* Add a trajectory.
|
|
540
|
+
* @param {RealtimeTrajectory} trajectory The trajectory to add.
|
|
541
|
+
* @private
|
|
542
|
+
*/
|
|
543
|
+
addTrajectory(trajectory) {
|
|
544
|
+
if (this.filter && !this.filter(trajectory)) {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (!this.trajectories) {
|
|
548
|
+
this.trajectories = {};
|
|
549
|
+
}
|
|
550
|
+
this.trajectories[trajectory.properties.train_id] = trajectory;
|
|
551
|
+
// @ts-ignore the parameter are set by subclasses
|
|
552
|
+
this.renderTrajectories();
|
|
553
|
+
}
|
|
554
|
+
removeTrajectory(trajectoryOrId) {
|
|
555
|
+
var _a;
|
|
556
|
+
let id;
|
|
557
|
+
if (typeof trajectoryOrId !== 'string') {
|
|
558
|
+
id = (_a = trajectoryOrId === null || trajectoryOrId === void 0 ? void 0 : trajectoryOrId.properties) === null || _a === void 0 ? void 0 : _a.train_id;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
id = trajectoryOrId;
|
|
562
|
+
}
|
|
563
|
+
if (this.trajectories) {
|
|
564
|
+
delete this.trajectories[id];
|
|
565
|
+
}
|
|
622
566
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
567
|
+
/**
|
|
568
|
+
* On zoomend we adjust the time interval of the update of vehicles positions.
|
|
569
|
+
*
|
|
570
|
+
* @param evt Event that triggered the function.
|
|
571
|
+
* @private
|
|
572
|
+
*/
|
|
573
|
+
onZoomEnd() {
|
|
574
|
+
this.startUpdateTime();
|
|
575
|
+
}
|
|
576
|
+
onDocumentVisibilityChange() {
|
|
577
|
+
if (!this.visible) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (document.hidden) {
|
|
581
|
+
this.stop();
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
this.start();
|
|
585
|
+
}
|
|
627
586
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
587
|
+
/**
|
|
588
|
+
* Callback on websocket's trajectory channel events.
|
|
589
|
+
* It adds a trajectory to the list.
|
|
590
|
+
*
|
|
591
|
+
* @private
|
|
592
|
+
*/
|
|
593
|
+
onTrajectoryMessage(data) {
|
|
594
|
+
if (!data.content) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const trajectory = data.content;
|
|
598
|
+
const { geometry, properties: { train_id: id, time_since_update: timeSinceUpdate, raw_coordinates: rawCoordinates, }, } = trajectory;
|
|
599
|
+
// ignore old events [SBAHNM-97]
|
|
600
|
+
if (timeSinceUpdate < 0) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
// console.time(`onTrajectoryMessage${data.content.properties.train_id}`);
|
|
604
|
+
// @ts-ignore default value for extentand zoom are provided by subclasses
|
|
605
|
+
if (this.purgeTrajectory(trajectory)) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
if (this.debug &&
|
|
609
|
+
this.mode === RealtimeModes.TOPOGRAPHIC &&
|
|
610
|
+
rawCoordinates) {
|
|
611
|
+
trajectory.properties.olGeometry = {
|
|
612
|
+
type: 'Point',
|
|
613
|
+
coordinates: fromLonLat(rawCoordinates, this.map.getView().getProjection()),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
trajectory.properties.olGeometry = this.format.readGeometry(geometry);
|
|
618
|
+
}
|
|
619
|
+
// TODO Make sure the timeOffset is useful. May be we can remove it.
|
|
620
|
+
trajectory.properties.timeOffset = Date.now() - data.timestamp;
|
|
621
|
+
this.addTrajectory(trajectory);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Callback on websocket's deleted_vehicles channel events.
|
|
625
|
+
* It removes the trajectory from the list.
|
|
626
|
+
*
|
|
627
|
+
* @private
|
|
628
|
+
* @override
|
|
629
|
+
*/
|
|
630
|
+
onDeleteTrajectoryMessage(data) {
|
|
631
|
+
if (!data.content) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
this.removeTrajectory(data.content);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Callback when user moves the mouse/pointer over the map.
|
|
638
|
+
* It sets the layer's hoverVehicleId property with the current hovered vehicle's id.
|
|
639
|
+
*
|
|
640
|
+
* @private
|
|
641
|
+
* @override
|
|
642
|
+
*/
|
|
643
|
+
onFeatureHover(features, layer, coordinate) {
|
|
644
|
+
const [feature] = features;
|
|
645
|
+
let id = null;
|
|
646
|
+
if (feature) {
|
|
647
|
+
id = feature.get('train_id');
|
|
648
|
+
}
|
|
649
|
+
if (this.hoverVehicleId !== id) {
|
|
650
|
+
/** @ignore */
|
|
651
|
+
this.hoverVehicleId = id;
|
|
652
|
+
// @ts-ignore
|
|
653
|
+
this.renderTrajectories(true);
|
|
654
|
+
}
|
|
641
655
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
656
|
+
/**
|
|
657
|
+
* Callback when user clicks on the map.
|
|
658
|
+
* It sets the layer's selectedVehicleId property with the current selected vehicle's id.
|
|
659
|
+
*
|
|
660
|
+
* @private
|
|
661
|
+
* @override
|
|
662
|
+
*/
|
|
663
|
+
onFeatureClick(features, layer, coordinate) {
|
|
664
|
+
const [feature] = features;
|
|
665
|
+
let id = null;
|
|
666
|
+
if (feature) {
|
|
667
|
+
id = feature.get('train_id');
|
|
668
|
+
}
|
|
669
|
+
if (this.selectedVehicleId !== id) {
|
|
670
|
+
/** @ignore */
|
|
671
|
+
this.selectedVehicleId = id;
|
|
672
|
+
this.selectedVehicle = feature;
|
|
673
|
+
// @ts-ignore parameters are provided by subclasses
|
|
674
|
+
this.renderTrajectories(true);
|
|
675
|
+
}
|
|
647
676
|
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
677
|
+
};
|
|
678
|
+
}
|
|
650
679
|
export default RealtimeLayerMixin;
|