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.
Files changed (201) hide show
  1. package/api/RealtimeAPI.d.ts +80 -64
  2. package/api/RealtimeAPI.d.ts.map +1 -1
  3. package/api/RealtimeAPI.js +58 -45
  4. package/api/RoutingAPI.d.ts +2 -2
  5. package/api/RoutingAPI.d.ts.map +1 -1
  6. package/api/RoutingAPI.js +1 -1
  7. package/api/StopsAPI.d.ts +14 -12
  8. package/api/StopsAPI.d.ts.map +1 -1
  9. package/api/StopsAPI.js +7 -9
  10. package/api/typedefs.d.ts +84 -10
  11. package/api/typedefs.d.ts.map +1 -1
  12. package/api/typedefs.js +3 -1
  13. package/common/api/WebSocketAPI.d.ts +80 -24
  14. package/common/api/WebSocketAPI.d.ts.map +1 -1
  15. package/common/api/WebSocketAPI.js +28 -16
  16. package/common/controls/{Control.d.ts → ControlCommon.d.ts} +21 -19
  17. package/common/controls/ControlCommon.d.ts.map +1 -0
  18. package/common/controls/{Control.js → ControlCommon.js} +21 -8
  19. package/common/controls/CopyrightControlCommon.d.ts +13 -0
  20. package/common/controls/CopyrightControlCommon.d.ts.map +1 -0
  21. package/common/controls/CopyrightControlCommon.js +34 -0
  22. package/common/controls/StopFinderControlCommon.d.ts +54 -0
  23. package/common/controls/StopFinderControlCommon.d.ts.map +1 -0
  24. package/common/{mixins/StopFinderMixin.js → controls/StopFinderControlCommon.js} +25 -38
  25. package/common/layers/{Layer.d.ts → LayerCommon.d.ts} +34 -21
  26. package/common/layers/LayerCommon.d.ts.map +1 -0
  27. package/common/layers/{Layer.js → LayerCommon.js} +15 -9
  28. package/common/mixins/RealtimeLayerMixin.d.ts +243 -19
  29. package/common/mixins/RealtimeLayerMixin.d.ts.map +1 -1
  30. package/common/mixins/RealtimeLayerMixin.js +598 -569
  31. package/common/mixins/UserInteractionsLayerMixin.d.ts +18 -8
  32. package/common/mixins/UserInteractionsLayerMixin.d.ts.map +1 -1
  33. package/common/mixins/UserInteractionsLayerMixin.js +170 -159
  34. package/common/styles/realtimeDefaultStyle.d.ts +30 -9
  35. package/common/styles/realtimeDefaultStyle.d.ts.map +1 -1
  36. package/common/styles/realtimeDefaultStyle.js +41 -17
  37. package/common/styles/realtimeDelayStyle.d.ts +3 -2
  38. package/common/styles/realtimeDelayStyle.d.ts.map +1 -1
  39. package/common/styles/realtimeSimpleStyle.d.ts +1 -1
  40. package/common/styles/realtimeSimpleStyle.d.ts.map +1 -1
  41. package/common/styles/realtimeSimpleStyle.js +9 -7
  42. package/common/typedefs.d.ts +64 -3
  43. package/common/typedefs.d.ts.map +1 -1
  44. package/common/typedefs.js +34 -4
  45. package/common/utils/cleanStopTime.d.ts +3 -2
  46. package/common/utils/cleanStopTime.d.ts.map +1 -1
  47. package/common/utils/cleanStopTime.js +0 -3
  48. package/common/utils/compareDepartures.d.ts +6 -4
  49. package/common/utils/compareDepartures.d.ts.map +1 -1
  50. package/common/utils/compareDepartures.js +3 -2
  51. package/common/utils/createCanvas.d.ts +3 -2
  52. package/common/utils/createCanvas.d.ts.map +1 -1
  53. package/common/utils/createTrackerFilters.d.ts +3 -2
  54. package/common/utils/createTrackerFilters.d.ts.map +1 -1
  55. package/common/utils/createTrackerFilters.js +3 -3
  56. package/common/utils/getLayersAsFlatArray.d.ts +1 -1
  57. package/common/utils/getLayersAsFlatArray.d.ts.map +1 -1
  58. package/common/utils/getLayersAsFlatArray.js +1 -0
  59. package/common/utils/getMapboxMapCopyrights.d.ts +13 -3
  60. package/common/utils/getMapboxMapCopyrights.d.ts.map +1 -1
  61. package/common/utils/getMapboxMapCopyrights.js +10 -4
  62. package/common/utils/getMapboxRender.d.ts +3 -1
  63. package/common/utils/getMapboxRender.d.ts.map +1 -1
  64. package/common/utils/getMapboxRender.js +1 -2
  65. package/common/utils/getVehiclePosition.d.ts +1 -1
  66. package/common/utils/getVehiclePosition.d.ts.map +1 -1
  67. package/common/utils/removeDuplicate.d.ts +2 -2
  68. package/common/utils/removeDuplicate.d.ts.map +1 -1
  69. package/common/utils/renderTrajectories.d.ts +3 -6
  70. package/common/utils/renderTrajectories.d.ts.map +1 -1
  71. package/common/utils/renderTrajectories.js +17 -8
  72. package/common/utils/trackerConfig.d.ts.map +1 -1
  73. package/common/utils/trackerConfig.js +3 -0
  74. package/mapbox/controls/CopyrightControl.d.ts +6 -8
  75. package/mapbox/controls/CopyrightControl.d.ts.map +1 -1
  76. package/mapbox/controls/CopyrightControl.js +3 -8
  77. package/mapbox/layers/Layer.js +1 -1
  78. package/mapbox/layers/RealtimeLayer.d.ts +1 -1
  79. package/mapbox/layers/RealtimeLayer.d.ts.map +1 -1
  80. package/mapbox/utils.d.ts +1 -1
  81. package/mapbox/utils.d.ts.map +1 -1
  82. package/mbt.js +824 -702
  83. package/mbt.js.map +3 -3
  84. package/mbt.min.js +84 -84
  85. package/mbt.min.js.map +3 -3
  86. package/ol/controls/CopyrightControl.d.ts +10 -10
  87. package/ol/controls/CopyrightControl.d.ts.map +1 -1
  88. package/ol/controls/CopyrightControl.js +8 -8
  89. package/ol/controls/RoutingControl.d.ts +10 -3
  90. package/ol/controls/RoutingControl.d.ts.map +1 -1
  91. package/ol/controls/RoutingControl.js +2 -2
  92. package/ol/controls/StopFinderControl.d.ts +5 -7
  93. package/ol/controls/StopFinderControl.d.ts.map +1 -1
  94. package/ol/controls/StopFinderControl.js +4 -8
  95. package/ol/layers/Layer.d.ts +57 -9
  96. package/ol/layers/Layer.d.ts.map +1 -1
  97. package/ol/layers/Layer.js +17 -8
  98. package/ol/layers/MapGlLayer.d.ts +67 -0
  99. package/ol/layers/MapGlLayer.d.ts.map +1 -0
  100. package/{common/mixins/MapboxLayerMixin.js → ol/layers/MapGlLayer.js} +66 -44
  101. package/ol/layers/MapboxLayer.d.ts +15 -17
  102. package/ol/layers/MapboxLayer.d.ts.map +1 -1
  103. package/ol/layers/MapboxLayer.js +10 -7
  104. package/ol/layers/MapboxStyleLayer.d.ts +6 -0
  105. package/ol/layers/MapboxStyleLayer.d.ts.map +1 -1
  106. package/ol/layers/MaplibreLayer.d.ts +4 -4
  107. package/ol/layers/MaplibreLayer.d.ts.map +1 -1
  108. package/ol/layers/MaplibreLayer.js +2 -3
  109. package/ol/layers/RealtimeLayer.d.ts +106 -30
  110. package/ol/layers/RealtimeLayer.d.ts.map +1 -1
  111. package/ol/layers/RealtimeLayer.js +22 -14
  112. package/ol/styles/fullTrajectoryStyle.d.ts +3 -2
  113. package/ol/styles/fullTrajectoryStyle.d.ts.map +1 -1
  114. package/package.json +15 -9
  115. package/types/common.d.ts +111 -0
  116. package/types/index.d.ts +1 -0
  117. package/types/realtime.d.ts +290 -9
  118. package/api/RealtimeAPI.test.d.ts +0 -2
  119. package/api/RealtimeAPI.test.d.ts.map +0 -1
  120. package/api/RealtimeAPI.test.js +0 -67
  121. package/api/RoutingAPI.test.d.ts +0 -2
  122. package/api/RoutingAPI.test.d.ts.map +0 -1
  123. package/api/RoutingAPI.test.js +0 -29
  124. package/api/StopsAPI.test.d.ts +0 -2
  125. package/api/StopsAPI.test.d.ts.map +0 -1
  126. package/api/StopsAPI.test.js +0 -26
  127. package/common/api/HttpAPI.test.d.ts +0 -2
  128. package/common/api/HttpAPI.test.d.ts.map +0 -1
  129. package/common/api/HttpAPI.test.js +0 -54
  130. package/common/api/WebSocketAPI.test.d.ts +0 -2
  131. package/common/api/WebSocketAPI.test.d.ts.map +0 -1
  132. package/common/api/WebSocketAPI.test.js +0 -380
  133. package/common/controls/Control.d.ts.map +0 -1
  134. package/common/controls/Control.test.d.ts +0 -2
  135. package/common/controls/Control.test.d.ts.map +0 -1
  136. package/common/controls/Control.test.js +0 -89
  137. package/common/layers/Layer.d.ts.map +0 -1
  138. package/common/layers/Layer.test.d.ts +0 -2
  139. package/common/layers/Layer.test.d.ts.map +0 -1
  140. package/common/layers/Layer.test.js +0 -137
  141. package/common/mixins/CopyrightMixin.d.ts +0 -22
  142. package/common/mixins/CopyrightMixin.d.ts.map +0 -1
  143. package/common/mixins/CopyrightMixin.js +0 -43
  144. package/common/mixins/MapboxLayerMixin.d.ts +0 -27
  145. package/common/mixins/MapboxLayerMixin.d.ts.map +0 -1
  146. package/common/mixins/StopFinderMixin.d.ts +0 -40
  147. package/common/mixins/StopFinderMixin.d.ts.map +0 -1
  148. package/common/mixins/UserInteractionsLayerMixin.test.d.ts +0 -2
  149. package/common/mixins/UserInteractionsLayerMixin.test.d.ts.map +0 -1
  150. package/common/mixins/UserInteractionsLayerMixin.test.js +0 -214
  151. package/common/utils/createTrackerFilters.test.d.ts +0 -2
  152. package/common/utils/createTrackerFilters.test.d.ts.map +0 -1
  153. package/common/utils/createTrackerFilters.test.js +0 -79
  154. package/common/utils/getMapboxMapCopyrights.test.d.ts +0 -2
  155. package/common/utils/getMapboxMapCopyrights.test.d.ts.map +0 -1
  156. package/common/utils/getMapboxMapCopyrights.test.js +0 -40
  157. package/common/utils/removeDuplicate.test.d.ts +0 -2
  158. package/common/utils/removeDuplicate.test.d.ts.map +0 -1
  159. package/common/utils/removeDuplicate.test.js +0 -19
  160. package/common/utils/timeUtils.test.d.ts +0 -2
  161. package/common/utils/timeUtils.test.d.ts.map +0 -1
  162. package/common/utils/timeUtils.test.js +0 -10
  163. package/common/utils/trackerConfig.test.d.ts +0 -2
  164. package/common/utils/trackerConfig.test.d.ts.map +0 -1
  165. package/common/utils/trackerConfig.test.js +0 -23
  166. package/mapbox/layers/Layer.test.d.ts +0 -2
  167. package/mapbox/layers/Layer.test.d.ts.map +0 -1
  168. package/mapbox/layers/Layer.test.js +0 -204
  169. package/mapbox/layers/RealtimeLayer.test.d.ts +0 -2
  170. package/mapbox/layers/RealtimeLayer.test.d.ts.map +0 -1
  171. package/mapbox/layers/RealtimeLayer.test.js +0 -10
  172. package/ol/controls/CopyrightControl.test.d.ts +0 -2
  173. package/ol/controls/CopyrightControl.test.d.ts.map +0 -1
  174. package/ol/controls/CopyrightControl.test.js +0 -177
  175. package/ol/controls/RoutingControl.test.d.ts +0 -2
  176. package/ol/controls/RoutingControl.test.d.ts.map +0 -1
  177. package/ol/controls/RoutingControl.test.js +0 -150
  178. package/ol/controls/StopFinderControl.test.d.ts +0 -2
  179. package/ol/controls/StopFinderControl.test.d.ts.map +0 -1
  180. package/ol/controls/StopFinderControl.test.js +0 -49
  181. package/ol/layers/Layer.test.d.ts +0 -2
  182. package/ol/layers/Layer.test.d.ts.map +0 -1
  183. package/ol/layers/Layer.test.js +0 -196
  184. package/ol/layers/MapboxLayer.test.d.ts +0 -2
  185. package/ol/layers/MapboxLayer.test.d.ts.map +0 -1
  186. package/ol/layers/MapboxLayer.test.js +0 -164
  187. package/ol/layers/MapboxStyleLayer.test.d.ts +0 -2
  188. package/ol/layers/MapboxStyleLayer.test.d.ts.map +0 -1
  189. package/ol/layers/MapboxStyleLayer.test.js +0 -232
  190. package/ol/layers/RealtimeLayer.test.d.ts +0 -2
  191. package/ol/layers/RealtimeLayer.test.d.ts.map +0 -1
  192. package/ol/layers/RealtimeLayer.test.js +0 -71
  193. package/ol/layers/RoutingLayer.test.d.ts +0 -2
  194. package/ol/layers/RoutingLayer.test.d.ts.map +0 -1
  195. package/ol/layers/RoutingLayer.test.js +0 -39
  196. package/ol/layers/VectorLayer.test.d.ts +0 -2
  197. package/ol/layers/VectorLayer.test.d.ts.map +0 -1
  198. package/ol/layers/VectorLayer.test.js +0 -87
  199. package/ol/layers/WMSLayer.test.d.ts +0 -2
  200. package/ol/layers/WMSLayer.test.d.ts.map +0 -1
  201. 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
- const RealtimeLayerMixin = (Base) => class extends Base {
80
- constructor(options = {}) {
81
- super(Object.assign({ hitTolerance: 10 }, options));
82
- this.debug = options.debug;
83
- this.mode = options.mode || RealtimeModes.TOPOGRAPHIC;
84
- this.api = options.api || new RealtimeAPI(options);
85
- this.tenant = options.tenant || ''; // sbb,sbh or sbm
86
- 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
87
- this.minZoomInterpolation = options.minZoomInterpolation || 8; // Min zoom level from which trains positions are not interpolated.
88
- this.format = new GeoJSON();
89
- this.generalizationLevelByZoom = options.generalizationLevelByZoom || [
90
- 5, 5, 5, 5, 5, 5, 5, 5, 10, 30, 30, 100, 100, 100,
91
- ];
92
- this.getGeneralizationLevelByZoom = (zoom) => {
93
- return ((options.getGeneralizationLevelByZoom &&
94
- options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom)) ||
95
- this.generalizationLevelByZoom[zoom]);
96
- };
97
- this.renderTimeIntervalByZoom = options.renderTimeIntervalByZoom || [
98
- 100000, 50000, 40000, 30000, 20000, 15000, 10000, 5000, 2000, 1000, 400,
99
- 300, 250, 180, 90, 60, 50, 50, 50, 50, 50,
100
- ];
101
- this.getRenderTimeIntervalByZoom = (zoom) => {
102
- return ((options.getRenderTimeIntervalByZoom &&
103
- options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom)) ||
104
- this.renderTimeIntervalByZoom[zoom]);
105
- };
106
- // This property will call api.setBbox on each movend event
107
- this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;
108
- // Define throttling and debounce render function
109
- this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });
110
- this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true, trailing: true, maxWait: 5000 });
111
- // Bind callbacks
112
- this.onFeatureHover = this.onFeatureHover.bind(this);
113
- this.onFeatureClick = this.onFeatureClick.bind(this);
114
- this.renderTrajectoriesInternal =
115
- this.renderTrajectoriesInternal.bind(this);
116
- this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);
117
- this.onDeleteTrajectoryMessage =
118
- this.onDeleteTrajectoryMessage.bind(this);
119
- this.onDocumentVisibilityChange =
120
- this.onDocumentVisibilityChange.bind(this);
121
- }
122
- /**
123
- * Define layer's properties.
124
- *
125
- * @ignore
126
- */
127
- defineProperties(options) {
128
- const { style, speed, pixelRatio, hoverVehicleId, selectedVehicleId, filter, sort, time, live, canvas, styleOptions, } = options;
129
- let currSpeed = speed || 1;
130
- let currTime = time || new Date();
131
- super.defineProperties(options);
132
- Object.defineProperties(this, {
133
- isTrackerLayer: { value: true },
134
- canvas: {
135
- value: canvas || document.createElement('canvas'),
136
- },
137
- /**
138
- * Style function used to render a vehicle.
139
- */
140
- style: {
141
- value: style || realtimeDefaultStyle,
142
- },
143
- /**
144
- * Custom options to pass as last parameter of the style function.
145
- */
146
- styleOptions: {
147
- value: Object.assign(Object.assign({}, trackerConfig), (styleOptions || {})),
148
- },
149
- /**
150
- * Speed of the wheel of time.
151
- * If live property is true. The speed is ignored.
152
- */
153
- speed: {
154
- get: () => currSpeed,
155
- set: (newSpeed) => {
156
- currSpeed = newSpeed;
157
- this.start();
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
- * Function to filter which vehicles to display.
162
- */
163
- filter: {
164
- value: filter,
165
- writable: true,
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
- * Keep track of which trajectories are stored.
195
- */
196
- trajectories: {
197
- value: {},
198
- writable: true,
199
- },
200
- /**
201
- * Id of the hovered vehicle.
202
- */
203
- hoverVehicleId: {
204
- value: hoverVehicleId,
205
- writable: true,
206
- },
207
- /**
208
- * Id of the selected vehicle.
209
- */
210
- selectedVehicleId: {
211
- value: selectedVehicleId,
212
- writable: true,
213
- },
214
- /**
215
- * Id of the selected vehicle.
216
- */
217
- pixelRatio: {
218
- value: pixelRatio ||
219
- (typeof window !== 'undefined' ? window.devicePixelRatio : 1),
220
- writable: true,
221
- },
222
- /**
223
- * If true, encapsulates the renderTrajectories calls in a requestAnimationFrame.
224
- */
225
- useRequestAnimationFrame: {
226
- value: options.useRequestAnimationFrame || false,
227
- writable: true,
228
- },
229
- /**
230
- * If true, encapsulates the renderTrajectories calls in a throttle function. Default to true.
231
- */
232
- useThrottle: {
233
- value: options.useThrottle !== false,
234
- writable: true,
235
- },
236
- /**
237
- * If true, encapsulates the renderTrajectories calls in a debounce function.
238
- */
239
- useDebounce: {
240
- value: options.useDebounce || false,
241
- writable: true,
242
- },
243
- /**
244
- * Debug properties.
245
- */
246
- // Not used anymore, but could be useful for debugging.
247
- // showVehicleTraj: {
248
- // value:
249
- // options.showVehicleTraj !== undefined
250
- // ? options.showVehicleTraj
251
- // : true,
252
- // writable: true,
253
- // },
254
- });
255
- }
256
- attachToMap(map) {
257
- super.attachToMap(map);
258
- // If the layer is visible we start the rendering clock
259
- if (this.visible) {
260
- this.start();
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
- // On change of visibility we start/stop the rendering clock
263
- this.visibilityRef = this.on('change:visible', (evt) => {
264
- if (evt.target.visible) {
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
- else {
268
- this.stop();
269
- }
270
- });
271
- // To avoid browser hanging when the tab is not visible for a certain amount of time,
272
- // We stop the rendering and the websocket when hide and start again when show.
273
- document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);
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
- else if (!noInterpolate && this.useDebounce) {
379
- this.debounceRenderTrajectories(viewState, noInterpolate);
380
- }
381
- else if (!noInterpolate && this.useThrottle) {
382
- this.throttleRenderTrajectories(viewState, noInterpolate);
383
- }
384
- else {
385
- this.renderTrajectoriesInternal(viewState, noInterpolate);
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
- this.api.bbox = bbox;
410
- }
411
- setMode(mode) {
412
- if (this.mode === mode) {
413
- return;
414
- }
415
- this.mode = mode;
416
- this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
417
- this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, this.isUpdateBboxOnMoveEnd);
418
- }
419
- /**
420
- * Get the duration before the next update depending on zoom level.
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
- return nextTick;
443
- }
444
- /**
445
- * Get vehicle.
446
- * @param {function} filterFc A function use to filter results.
447
- * @return {Array<Object>} Array of vehicle.
448
- */
449
- getVehicle(filterFc) {
450
- return Object.values(this.trajectories).filter(filterFc);
451
- }
452
- /**
453
- * Request feature information for a given coordinate.
454
- *
455
- * @param {ol/coordinate~Coordinate} coordinate Coordinate.
456
- * @param {Object} options Options See child classes to see which options are supported.
457
- * @param {number} [options.resolution=1] The resolution of the map.
458
- * @param {number} [options.nb=Infinity] The max number of vehicles to return.
459
- * @return {Promise<FeatureInfo>} Promise with features, layer and coordinate.
460
- */
461
- getFeatureInfoAtCoordinate(coordinate, options = {}) {
462
- const { resolution, nb } = options;
463
- const ext = buffer([...coordinate, ...coordinate], this.hitTolerance * resolution);
464
- let trajectories = Object.values(this.trajectories);
465
- if (this.sort) {
466
- trajectories = trajectories.sort(this.sort);
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
- const vehicles = [];
469
- for (let i = 0; i < trajectories.length; i += 1) {
470
- if (trajectories[i].properties.coordinate &&
471
- containsCoordinate(ext, trajectories[i].properties.coordinate)) {
472
- vehicles.push(trajectories[i]);
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
- if (vehicles.length === nb) {
475
- break;
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
- return Promise.resolve({
479
- layer: this,
480
- features: vehicles.map((vehicle) => this.format.readFeature(vehicle)),
481
- coordinate,
482
- });
483
- }
484
- /**
485
- * Request the stopSequence and the fullTrajectory informations for a vehicle.
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
- return false;
525
- }
526
- /**
527
- * Add a trajectory.
528
- * @param {RealtimeTrajectory} trajectory The trajectory to add.
529
- * @private
530
- */
531
- addTrajectory(trajectory) {
532
- if (this.filter && !this.filter(trajectory)) {
533
- return;
534
- }
535
- this.trajectories[trajectory.properties.train_id] = trajectory;
536
- this.renderTrajectories();
537
- }
538
- removeTrajectory(id) {
539
- delete this.trajectories[id];
540
- }
541
- /**
542
- * On zoomend we adjust the time interval of the update of vehicles positions.
543
- *
544
- * @param evt Event that triggered the function.
545
- * @private
546
- */
547
- // eslint-disable-next-line no-unused-vars
548
- onZoomEnd(evt) {
549
- this.startUpdateTime();
550
- }
551
- onDocumentVisibilityChange() {
552
- if (!this.visible) {
553
- return;
554
- }
555
- if (document.hidden) {
556
- this.stop();
557
- }
558
- else {
559
- this.start();
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
- // console.time(`onTrajectoryMessage${data.content.properties.train_id}`);
579
- if (this.purgeTrajectory(trajectory)) {
580
- return;
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
- if (this.debug &&
583
- this.mode === RealtimeModes.TOPOGRAPHIC &&
584
- rawCoordinates) {
585
- trajectory.properties.olGeometry = {
586
- type: 'Point',
587
- coordinates: fromLonLat(rawCoordinates, this.map.getView().getProjection()),
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
- else {
591
- trajectory.properties.olGeometry = this.format.readGeometry(geometry);
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
- // TODO Make sure the timeOffset is useful. May be we can remove it.
594
- trajectory.properties.timeOffset = Date.now() - data.timestamp;
595
- this.addTrajectory(trajectory);
596
- }
597
- /**
598
- * Callback on websocket's deleted_vehicles channel events.
599
- * It removes the trajectory from the list.
600
- *
601
- * @private
602
- * @override
603
- */
604
- onDeleteTrajectoryMessage(data) {
605
- if (!data.content) {
606
- return;
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
- this.removeTrajectory(data.content);
609
- }
610
- /**
611
- * Callback when user moves the mouse/pointer over the map.
612
- * It sets the layer's hoverVehicleId property with the current hovered vehicle's id.
613
- *
614
- * @private
615
- * @override
616
- */
617
- onFeatureHover(features, layer, coordinate) {
618
- const [feature] = features;
619
- let id = null;
620
- if (feature) {
621
- id = feature.get('train_id');
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
- if (this.hoverVehicleId !== id) {
624
- /** @ignore */
625
- this.hoverVehicleId = id;
626
- this.renderTrajectories(true);
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
- * Callback when user clicks on the map.
631
- * It sets the layer's selectedVehicleId property with the current selected vehicle's id.
632
- *
633
- * @private
634
- * @override
635
- */
636
- onFeatureClick(features, layer, coordinate) {
637
- const [feature] = features;
638
- let id = null;
639
- if (feature) {
640
- id = feature.get('train_id');
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
- if (this.selectedVehicleId !== id) {
643
- /** @ignore */
644
- this.selectedVehicleId = id;
645
- this.selectedVehicle = feature;
646
- this.renderTrajectories(true);
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;