mobility-toolbox-js 2.0.1-beta.13 → 2.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/api/RealtimeAPI.d.ts +281 -0
  2. package/api/RealtimeAPI.d.ts.map +1 -0
  3. package/api/RealtimeAPI.js +490 -0
  4. package/api/RoutingAPI.d.ts +37 -0
  5. package/api/RoutingAPI.d.ts.map +1 -0
  6. package/api/RoutingAPI.js +32 -12
  7. package/api/StopsAPI.d.ts +38 -0
  8. package/api/StopsAPI.d.ts.map +1 -0
  9. package/api/StopsAPI.js +33 -9
  10. package/api/index.d.ts +4 -0
  11. package/api/index.d.ts.map +1 -0
  12. package/api/index.js +3 -3
  13. package/api/typedefs.d.ts +179 -0
  14. package/api/typedefs.d.ts.map +1 -0
  15. package/api/typedefs.js +75 -0
  16. package/common/api/HttpAPI.d.ts +31 -0
  17. package/common/api/HttpAPI.d.ts.map +1 -0
  18. package/common/api/HttpAPI.js +54 -27
  19. package/common/api/WebSocketAPI.d.ts +153 -0
  20. package/common/api/WebSocketAPI.d.ts.map +1 -0
  21. package/common/api/WebSocketAPI.js +330 -164
  22. package/common/controls/ControlCommon.d.ts +76 -0
  23. package/common/controls/ControlCommon.d.ts.map +1 -0
  24. package/common/controls/ControlCommon.js +150 -0
  25. package/common/controls/CopyrightControlCommon.d.ts +13 -0
  26. package/common/controls/CopyrightControlCommon.d.ts.map +1 -0
  27. package/common/controls/CopyrightControlCommon.js +34 -0
  28. package/common/controls/StopFinderControlCommon.d.ts +55 -0
  29. package/common/controls/StopFinderControlCommon.d.ts.map +1 -0
  30. package/common/controls/StopFinderControlCommon.js +144 -0
  31. package/common/index.d.ts +3 -0
  32. package/common/index.d.ts.map +1 -0
  33. package/common/index.js +2 -4
  34. package/common/layers/LayerCommon.d.ts +94 -0
  35. package/common/layers/LayerCommon.d.ts.map +1 -0
  36. package/common/layers/LayerCommon.js +244 -0
  37. package/common/mixins/RealtimeLayerMixin.d.ts +286 -0
  38. package/common/mixins/RealtimeLayerMixin.d.ts.map +1 -0
  39. package/common/mixins/RealtimeLayerMixin.js +779 -0
  40. package/common/mixins/UserInteractionsLayerMixin.d.ts +60 -0
  41. package/common/mixins/UserInteractionsLayerMixin.d.ts.map +1 -0
  42. package/common/mixins/UserInteractionsLayerMixin.js +241 -0
  43. package/common/styles/index.d.ts +5 -0
  44. package/common/styles/index.d.ts.map +1 -0
  45. package/common/styles/index.js +4 -4
  46. package/common/styles/realtimeDefaultStyle.d.ts +36 -0
  47. package/common/styles/realtimeDefaultStyle.d.ts.map +1 -0
  48. package/common/styles/realtimeDefaultStyle.js +275 -0
  49. package/common/styles/realtimeDelayStyle.d.ts +12 -0
  50. package/common/styles/realtimeDelayStyle.d.ts.map +1 -0
  51. package/common/styles/realtimeDelayStyle.js +13 -0
  52. package/common/styles/realtimeHeadingStyle.d.ts +12 -0
  53. package/common/styles/realtimeHeadingStyle.d.ts.map +1 -0
  54. package/common/styles/realtimeHeadingStyle.js +85 -0
  55. package/common/styles/realtimeSimpleStyle.d.ts +4 -0
  56. package/common/styles/realtimeSimpleStyle.d.ts.map +1 -0
  57. package/common/styles/realtimeSimpleStyle.js +23 -0
  58. package/common/typedefs.d.ts +111 -0
  59. package/common/typedefs.d.ts.map +1 -0
  60. package/common/typedefs.js +52 -0
  61. package/common/utils/compareDepartures.d.ts +11 -0
  62. package/common/utils/compareDepartures.d.ts.map +1 -0
  63. package/common/utils/compareDepartures.js +35 -0
  64. package/common/utils/createCanvas.d.ts +10 -0
  65. package/common/utils/createCanvas.d.ts.map +1 -0
  66. package/common/utils/createCanvas.js +27 -0
  67. package/common/utils/createRealtimeFilters.d.ts +13 -0
  68. package/common/utils/createRealtimeFilters.d.ts.map +1 -0
  69. package/common/utils/createRealtimeFilters.js +74 -0
  70. package/common/utils/debounceDeparturesMessages.d.ts +12 -0
  71. package/common/utils/debounceDeparturesMessages.d.ts.map +1 -0
  72. package/common/utils/debounceDeparturesMessages.js +24 -0
  73. package/common/utils/debounceWebsocketMessages.d.ts +11 -0
  74. package/common/utils/debounceWebsocketMessages.d.ts.map +1 -0
  75. package/common/utils/debounceWebsocketMessages.js +29 -0
  76. package/common/utils/getLayersAsFlatArray.d.ts +3 -0
  77. package/common/utils/getLayersAsFlatArray.d.ts.map +1 -0
  78. package/common/utils/getLayersAsFlatArray.js +15 -0
  79. package/common/utils/getMapboxMapCopyrights.d.ts +18 -0
  80. package/common/utils/getMapboxMapCopyrights.d.ts.map +1 -0
  81. package/common/utils/getMapboxMapCopyrights.js +26 -15
  82. package/common/utils/getMapboxRender.d.ts +7 -0
  83. package/common/utils/getMapboxRender.d.ts.map +1 -0
  84. package/common/utils/getMapboxRender.js +87 -0
  85. package/common/utils/getMaplibreRender.d.ts +7 -0
  86. package/common/utils/getMaplibreRender.d.ts.map +1 -0
  87. package/common/utils/getMaplibreRender.js +38 -0
  88. package/common/utils/getRealtimeModeSuffix.d.ts +10 -0
  89. package/common/utils/getRealtimeModeSuffix.d.ts.map +1 -0
  90. package/common/utils/getRealtimeModeSuffix.js +7 -0
  91. package/common/utils/getUrlWithParams.d.ts +9 -0
  92. package/common/utils/getUrlWithParams.d.ts.map +1 -0
  93. package/common/utils/getUrlWithParams.js +18 -0
  94. package/common/utils/getVehiclePosition.d.ts +16 -0
  95. package/common/utils/getVehiclePosition.d.ts.map +1 -0
  96. package/common/utils/getVehiclePosition.js +67 -37
  97. package/common/utils/index.d.ts +17 -0
  98. package/common/utils/index.d.ts.map +1 -0
  99. package/common/utils/index.js +17 -5
  100. package/common/utils/realtimeConfig.d.ts +49 -0
  101. package/common/utils/realtimeConfig.d.ts.map +1 -0
  102. package/common/utils/realtimeConfig.js +173 -0
  103. package/common/utils/removeDuplicate.d.ts +10 -0
  104. package/common/utils/removeDuplicate.d.ts.map +1 -0
  105. package/common/utils/removeDuplicate.js +12 -5
  106. package/common/utils/renderTrajectories.d.ts +17 -0
  107. package/common/utils/renderTrajectories.d.ts.map +1 -0
  108. package/common/utils/renderTrajectories.js +110 -0
  109. package/common/utils/sortAndFilterDepartures.d.ts +16 -0
  110. package/common/utils/sortAndFilterDepartures.d.ts.map +1 -0
  111. package/common/utils/sortAndFilterDepartures.js +58 -0
  112. package/common/utils/sortByDelay.d.ts +3 -0
  113. package/common/utils/sortByDelay.d.ts.map +1 -0
  114. package/common/utils/sortByDelay.js +17 -15
  115. package/common/utils/timeUtils.d.ts +24 -0
  116. package/common/utils/timeUtils.d.ts.map +1 -0
  117. package/common/utils/timeUtils.js +34 -15
  118. package/iife.d.ts +3 -0
  119. package/iife.d.ts.map +1 -0
  120. package/iife.js +5 -0
  121. package/index.d.ts +10 -0
  122. package/index.d.ts.map +1 -0
  123. package/index.js +8 -6
  124. package/mapbox/controls/CopyrightControl.d.ts +29 -0
  125. package/mapbox/controls/CopyrightControl.d.ts.map +1 -0
  126. package/mapbox/controls/CopyrightControl.js +44 -25
  127. package/mapbox/controls/index.d.ts +2 -0
  128. package/mapbox/controls/index.d.ts.map +1 -0
  129. package/mapbox/controls/index.js +2 -1
  130. package/mapbox/index.d.ts +6 -0
  131. package/mapbox/index.d.ts.map +1 -0
  132. package/mapbox/index.js +5 -4
  133. package/mapbox/layers/Layer.d.ts +59 -0
  134. package/mapbox/layers/Layer.d.ts.map +1 -0
  135. package/mapbox/layers/Layer.js +99 -55
  136. package/mapbox/layers/RealtimeLayer.d.ts +181 -0
  137. package/mapbox/layers/RealtimeLayer.d.ts.map +1 -0
  138. package/mapbox/layers/RealtimeLayer.js +276 -0
  139. package/mapbox/layers/index.d.ts +3 -0
  140. package/mapbox/layers/index.d.ts.map +1 -0
  141. package/mapbox/layers/index.js +2 -2
  142. package/mapbox/utils/getMercatorResolution.d.ts +9 -0
  143. package/mapbox/utils/getMercatorResolution.d.ts.map +1 -0
  144. package/mapbox/utils/getMercatorResolution.js +18 -0
  145. package/mapbox/utils/getSourceCoordinates.d.ts +9 -0
  146. package/mapbox/utils/getSourceCoordinates.d.ts.map +1 -0
  147. package/mapbox/utils/getSourceCoordinates.js +27 -0
  148. package/mapbox/utils/index.d.ts +3 -0
  149. package/mapbox/utils/index.d.ts.map +1 -0
  150. package/mapbox/utils/index.js +2 -0
  151. package/mbt.js +26074 -16501
  152. package/mbt.js.map +4 -4
  153. package/mbt.min.js +205 -126
  154. package/mbt.min.js.map +4 -4
  155. package/ol/controls/CopyrightControl.d.ts +31 -0
  156. package/ol/controls/CopyrightControl.d.ts.map +1 -0
  157. package/ol/controls/CopyrightControl.js +62 -36
  158. package/ol/controls/RoutingControl.d.ts +193 -0
  159. package/ol/controls/RoutingControl.d.ts.map +1 -0
  160. package/ol/controls/RoutingControl.js +601 -357
  161. package/ol/controls/StopFinderControl.d.ts +30 -0
  162. package/ol/controls/StopFinderControl.d.ts.map +1 -0
  163. package/ol/controls/StopFinderControl.js +30 -8
  164. package/ol/controls/index.d.ts +4 -0
  165. package/ol/controls/index.d.ts.map +1 -0
  166. package/ol/controls/index.js +3 -3
  167. package/ol/index.d.ts +6 -0
  168. package/ol/index.d.ts.map +1 -0
  169. package/ol/index.js +5 -5
  170. package/ol/layers/Layer.d.ts +86 -0
  171. package/ol/layers/Layer.d.ts.map +1 -0
  172. package/ol/layers/Layer.js +163 -77
  173. package/ol/layers/MapGlLayer.d.ts +67 -0
  174. package/ol/layers/MapGlLayer.d.ts.map +1 -0
  175. package/ol/layers/MapGlLayer.js +218 -0
  176. package/ol/layers/MapboxLayer.d.ts +50 -0
  177. package/ol/layers/MapboxLayer.d.ts.map +1 -0
  178. package/ol/layers/MapboxLayer.js +99 -193
  179. package/ol/layers/MapboxStyleLayer.d.ts +129 -0
  180. package/ol/layers/MapboxStyleLayer.d.ts.map +1 -0
  181. package/ol/layers/MapboxStyleLayer.js +362 -171
  182. package/ol/layers/MaplibreLayer.d.ts +28 -0
  183. package/ol/layers/MaplibreLayer.d.ts.map +1 -0
  184. package/ol/layers/MaplibreLayer.js +30 -135
  185. package/ol/layers/RealtimeLayer.d.ts +202 -0
  186. package/ol/layers/RealtimeLayer.d.ts.map +1 -0
  187. package/ol/layers/RealtimeLayer.js +340 -0
  188. package/ol/layers/RoutingLayer.d.ts +34 -0
  189. package/ol/layers/RoutingLayer.d.ts.map +1 -0
  190. package/ol/layers/RoutingLayer.js +72 -48
  191. package/ol/layers/VectorLayer.d.ts +25 -0
  192. package/ol/layers/VectorLayer.d.ts.map +1 -0
  193. package/ol/layers/VectorLayer.js +34 -18
  194. package/ol/layers/WMSLayer.d.ts +42 -0
  195. package/ol/layers/WMSLayer.d.ts.map +1 -0
  196. package/ol/layers/WMSLayer.js +84 -34
  197. package/ol/layers/index.d.ts +9 -0
  198. package/ol/layers/index.d.ts.map +1 -0
  199. package/ol/layers/index.js +8 -8
  200. package/ol/styles/fullTrajectoryDelayStyle.d.ts +4 -0
  201. package/ol/styles/fullTrajectoryDelayStyle.d.ts.map +1 -0
  202. package/ol/styles/fullTrajectoryDelayStyle.js +26 -24
  203. package/ol/styles/fullTrajectoryStyle.d.ts +5 -0
  204. package/ol/styles/fullTrajectoryStyle.d.ts.map +1 -0
  205. package/ol/styles/fullTrajectoryStyle.js +40 -39
  206. package/ol/styles/index.d.ts +3 -0
  207. package/ol/styles/index.d.ts.map +1 -0
  208. package/ol/styles/index.js +2 -2
  209. package/package.json +81 -133
  210. package/setupTests.d.ts +2 -0
  211. package/setupTests.d.ts.map +1 -0
  212. package/setupTests.js +26 -0
  213. package/types/common.d.ts +122 -0
  214. package/types/index.d.ts +13 -0
  215. package/types/realtime.d.ts +320 -0
  216. package/types/routing.d.ts +206 -0
  217. package/types/stops.d.ts +143 -0
  218. package/README.md +0 -23
  219. package/api/RoutingAPI.test.js +0 -25
  220. package/api/StopsAPI.test.js +0 -22
  221. package/api/TralisAPI.js +0 -359
  222. package/api/TralisAPI.test.js +0 -67
  223. package/api/TralisAPIUtils.js +0 -43
  224. package/common/Tracker.js +0 -93
  225. package/common/api/HttpAPI.test.js +0 -50
  226. package/common/api/WebSocketAPI.test.js +0 -311
  227. package/common/controls/Control.js +0 -81
  228. package/common/controls/Control.test.js +0 -87
  229. package/common/layers/Layer.js +0 -213
  230. package/common/layers/Layer.test.js +0 -526
  231. package/common/mixins/CopyrightMixin.js +0 -24
  232. package/common/mixins/SearchMixin.js +0 -110
  233. package/common/mixins/TralisLayerMixin.js +0 -479
  234. package/common/styles/trackerDefaultStyle.js +0 -197
  235. package/common/styles/trackerDelayStyle.js +0 -8
  236. package/common/styles/trackerSimpleStyle.js +0 -18
  237. package/common/trackerConfig.js +0 -152
  238. package/common/trackerConfig.test.js +0 -23
  239. package/common/utils/createTrackerFilters.js +0 -56
  240. package/common/utils/createTrackerFilters.test.js +0 -79
  241. package/common/utils/getMapboxMapCopyrights.test.js +0 -40
  242. package/common/utils/getMapboxStyleUrl.js +0 -22
  243. package/common/utils/removeDuplicate.test.js +0 -19
  244. package/common/utils/timeUtils.test.js +0 -10
  245. package/mapbox/layers/Layer.test.js +0 -182
  246. package/mapbox/layers/TralisLayer.js +0 -182
  247. package/mapbox/layers/TralisLayer.test.js +0 -38
  248. package/mapbox/utils.js +0 -32
  249. package/ol/controls/CopyrightControl.test.js +0 -165
  250. package/ol/controls/RoutingControl.test.js +0 -151
  251. package/ol/controls/StopFinderControl.test.js +0 -48
  252. package/ol/layers/Layer.test.js +0 -174
  253. package/ol/layers/MapboxLayer.test.js +0 -160
  254. package/ol/layers/MapboxStyleLayer.test.js +0 -231
  255. package/ol/layers/RoutingLayer.test.js +0 -40
  256. package/ol/layers/TralisLayer.js +0 -185
  257. package/ol/layers/TralisLayer.test.js +0 -79
  258. package/ol/layers/VectorLayer.test.js +0 -87
  259. package/ol/layers/WMSLayer.test.js +0 -76
@@ -1,19 +1,30 @@
1
- import removeDuplicate from "./removeDuplicate";
1
+ import removeDuplicate from './removeDuplicate';
2
+ /**
3
+ * Return the copyright a Mapbox map.
4
+ * @param {mapboxgl.Map | maplibregl.Map} map A Mapbox map
5
+ * @ignore
6
+ */
2
7
  const getMapboxMapCopyrights = (map) => {
3
- if (!map || !map.style) {
4
- return [];
5
- }
6
- const { sourceCaches } = map.style;
7
- let copyrights = [];
8
- Object.values(sourceCaches).forEach((sourceCache) => {
9
- if (sourceCache.used) {
10
- const source = sourceCache.getSource();
11
- const attribution = source.attribution || source.options && source.options.attribution;
12
- if (attribution) {
13
- copyrights = copyrights.concat(attribution.replace(/&copy;/g, "\xA9").split(/(<a.*?<\/a>)/));
14
- }
8
+ if (!map) {
9
+ return [];
15
10
  }
16
- });
17
- return removeDuplicate(copyrights);
11
+ // @ts-ignore
12
+ const { style } = map;
13
+ if (!style) {
14
+ return [];
15
+ }
16
+ const { sourceCaches } = style;
17
+ let copyrights = [];
18
+ Object.values(sourceCaches).forEach((sourceCache) => {
19
+ if (sourceCache.used) {
20
+ const source = sourceCache.getSource();
21
+ const attribution = // @ts-ignore
22
+ source.attribution || (source.options && source.options.attribution);
23
+ if (attribution) {
24
+ copyrights = copyrights.concat(attribution.replace(/&copy;/g, '©').split(/(<a.*?<\/a>)/));
25
+ }
26
+ }
27
+ });
28
+ return removeDuplicate(copyrights);
18
29
  };
19
30
  export default getMapboxMapCopyrights;
@@ -0,0 +1,7 @@
1
+ import { RenderFunction } from 'ol/layer/Layer';
2
+ import type { MapboxLayer } from '../../ol';
3
+ /**
4
+ * Return the render function fo the olLayer of a MaplibreLayer
5
+ */
6
+ export default function getMapboxRender(mapoxLayer: MapboxLayer): RenderFunction;
7
+ //# sourceMappingURL=getMapboxRender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMapboxRender.d.ts","sourceRoot":"","sources":["../../../src/common/utils/getMapboxRender.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,UAAU,EAAE,WAAW,GACtB,cAAc,CA4FhB"}
@@ -0,0 +1,87 @@
1
+ import { toLonLat } from 'ol/proj';
2
+ /**
3
+ * Return the render function fo the olLayer of a MaplibreLayer
4
+ */
5
+ export default function getMapboxRender(mapoxLayer) {
6
+ // We cretae emptyDiv only in render finction to work with serverside rendering
7
+ let emptyDiv;
8
+ return (frameState) => {
9
+ const { map, mbMap, renderState, olLayer } = mapoxLayer;
10
+ if (!map || !mbMap) {
11
+ if (!emptyDiv) {
12
+ emptyDiv = document.createElement('div');
13
+ }
14
+ return emptyDiv;
15
+ }
16
+ let changed = false;
17
+ const canvas = mbMap.getCanvas();
18
+ const { viewState } = frameState;
19
+ const visible = olLayer === null || olLayer === void 0 ? void 0 : olLayer.getVisible();
20
+ if (renderState && (renderState === null || renderState === void 0 ? void 0 : renderState.visible) !== visible) {
21
+ canvas.style.display = visible ? 'block' : 'none';
22
+ renderState.visible = visible;
23
+ // Needed since mapbox-gl 1.9.0.
24
+ // Without you don't see others ol layers on top.
25
+ canvas.style.position = 'absolute';
26
+ }
27
+ const opacity = olLayer === null || olLayer === void 0 ? void 0 : olLayer.getOpacity();
28
+ if (canvas && renderState && renderState.opacity !== opacity) {
29
+ // @ts-ignore
30
+ canvas.style.opacity = opacity;
31
+ renderState.opacity = opacity;
32
+ }
33
+ // adjust view parameters in mapbox
34
+ const { rotation } = viewState;
35
+ if (renderState && renderState.rotation !== rotation) {
36
+ mbMap.rotateTo((-(rotation || 0) * 180) / Math.PI, {
37
+ animate: false,
38
+ });
39
+ changed = true;
40
+ renderState.rotation = rotation;
41
+ }
42
+ if (renderState &&
43
+ renderState.center &&
44
+ (renderState.zoom !== viewState.zoom ||
45
+ renderState.center[0] !== viewState.center[0] ||
46
+ renderState.center[1] !== viewState.center[1])) {
47
+ mbMap.jumpTo({
48
+ center: toLonLat(viewState.center),
49
+ zoom: viewState.zoom - 1,
50
+ });
51
+ changed = true;
52
+ renderState.zoom = viewState.zoom;
53
+ renderState.center = viewState.center;
54
+ }
55
+ const size = map.getSize() || [0, 0];
56
+ if (renderState &&
57
+ renderState.size &&
58
+ (renderState.size[0] !== size[0] || renderState.size[1] !== size[1])) {
59
+ changed = true;
60
+ renderState.size = size;
61
+ }
62
+ // cancel the scheduled update & trigger synchronous redraw
63
+ // see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
64
+ // NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX
65
+ // @ts-ignore
66
+ if (mbMap && mbMap.style && mbMap.isStyleLoaded() && changed) {
67
+ try {
68
+ // @ts-ignore
69
+ if (mbMap._frame) {
70
+ // @ts-ignore
71
+ mbMap._frame.cancel();
72
+ // @ts-ignore
73
+ mbMap._frame = null;
74
+ }
75
+ // @ts-ignore
76
+ mbMap._render();
77
+ }
78
+ catch (err) {
79
+ // ignore render errors because it's probably related to
80
+ // a render during an update of the style.
81
+ // eslint-disable-next-line no-console
82
+ console.warn(err);
83
+ }
84
+ }
85
+ return mbMap.getContainer();
86
+ };
87
+ }
@@ -0,0 +1,7 @@
1
+ import type { RenderFunction } from 'ol/layer/Layer';
2
+ import type { MaplibreLayer } from '../../ol';
3
+ /**
4
+ * Return the render function fo the olLayer of a MaplibreLayer
5
+ */
6
+ export default function getMaplibreRender(maplibreLayer: MaplibreLayer): RenderFunction;
7
+ //# sourceMappingURL=getMaplibreRender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMaplibreRender.d.ts","sourceRoot":"","sources":["../../../src/common/utils/getMaplibreRender.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AAEH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,aAAa,EAAE,aAAa,GAC3B,cAAc,CAuChB"}
@@ -0,0 +1,38 @@
1
+ import { toLonLat } from 'ol/proj';
2
+ import { toDegrees } from 'ol/math';
3
+ /**
4
+ * Return the render function fo the olLayer of a MaplibreLayer
5
+ */
6
+ export default function getMaplibreRender(maplibreLayer) {
7
+ let emptyDiv;
8
+ return (frameState) => {
9
+ const { map, mbMap, olLayer } = maplibreLayer;
10
+ if (!map || !mbMap) {
11
+ if (!emptyDiv) {
12
+ emptyDiv = document.createElement('div');
13
+ }
14
+ return emptyDiv;
15
+ }
16
+ const canvas = mbMap.getCanvas();
17
+ const { viewState } = frameState;
18
+ const opacity = (olLayer === null || olLayer === void 0 ? void 0 : olLayer.getOpacity()) || 1;
19
+ canvas.style.opacity = `${opacity}`;
20
+ // adjust view parameters in mapbox
21
+ mbMap.jumpTo({
22
+ center: toLonLat(viewState.center),
23
+ zoom: viewState.zoom - 1,
24
+ bearing: toDegrees(-viewState.rotation),
25
+ });
26
+ if (!canvas.isConnected) {
27
+ // The canvas is not connected to the DOM, request a map rendering at the next animation frame
28
+ // to set the canvas size.
29
+ map.render();
30
+ }
31
+ else if (canvas.width !== frameState.size[0] ||
32
+ canvas.height !== frameState.size[1]) {
33
+ mbMap.resize();
34
+ }
35
+ mbMap.redraw();
36
+ return mbMap.getContainer();
37
+ };
38
+ }
@@ -0,0 +1,10 @@
1
+ import type { RealtimeMode } from '../../types';
2
+ import type { RealtimeModesType } from '../../api/RealtimeAPI';
3
+ /**
4
+ * Get the websocket channel suffix, depending on the current mode.
5
+ * @param {String} mode Mode 'topographic' ou 'schematic'.
6
+ * @private
7
+ */
8
+ declare const getModeSuffix: (mode: RealtimeMode, modes: RealtimeModesType) => string;
9
+ export default getModeSuffix;
10
+ //# sourceMappingURL=getRealtimeModeSuffix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRealtimeModeSuffix.d.ts","sourceRoot":"","sources":["../../../src/common/utils/getRealtimeModeSuffix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;GAIG;AACH,QAAA,MAAM,aAAa,SAAU,YAAY,SAAS,iBAAiB,KAAG,MACxB,CAAC;AAE/C,eAAe,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Get the websocket channel suffix, depending on the current mode.
3
+ * @param {String} mode Mode 'topographic' ou 'schematic'.
4
+ * @private
5
+ */
6
+ const getModeSuffix = (mode, modes) => mode === modes.SCHEMATIC ? '_schematic' : '';
7
+ export default getModeSuffix;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Return the styleUrl with apiKey parameters set.
3
+ * @param {string} url a url.
4
+ * @param {Object<String,String>} params a list of key/value pair to add to the url.
5
+ * @ignore
6
+ */
7
+ declare const getUrlWithParams: (url: string, params: Object) => URL;
8
+ export default getUrlWithParams;
9
+ //# sourceMappingURL=getUrlWithParams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getUrlWithParams.d.ts","sourceRoot":"","sources":["../../../src/common/utils/getUrlWithParams.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,QAAA,MAAM,gBAAgB,QAAS,MAAM,UAAU,MAAM,KAAG,GAYvD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Return the styleUrl with apiKey parameters set.
3
+ * @param {string} url a url.
4
+ * @param {Object<String,String>} params a list of key/value pair to add to the url.
5
+ * @ignore
6
+ */
7
+ const getUrlWithParams = (url, params) => {
8
+ // Clean requets parameters, removing undefined and null values.
9
+ const newUrl = new URL(url);
10
+ const searchParams = params || {};
11
+ Object.entries(searchParams).forEach(([key, value]) => {
12
+ if (value !== undefined && value !== null) {
13
+ newUrl.searchParams.set(key, value);
14
+ }
15
+ });
16
+ return newUrl;
17
+ };
18
+ export default getUrlWithParams;
@@ -0,0 +1,16 @@
1
+ import { Coordinate } from 'ol/coordinate';
2
+ export type VehiclePosition = {
3
+ coord: Coordinate;
4
+ rotation: number;
5
+ };
6
+ /**
7
+ * Interpolate or not the vehicle position from a trajectory at a specific date.
8
+ *
9
+ * @param {number} now Current date to interpolate a position with. In ms.
10
+ * @param {RealtimeTrajectory} trajectory The trajectory to interpolate.
11
+ * @param {boolean} noInterpolate If true, the vehicle position is not interpolated on each render but only once.
12
+ * @returns
13
+ */
14
+ declare const getVehiclePosition: (now: number, trajectory: GeoJSONFeature, noInterpolate: boolean) => VehiclePosition;
15
+ export default getVehiclePosition;
16
+ //# sourceMappingURL=getVehiclePosition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getVehiclePosition.d.ts","sourceRoot":"","sources":["../../../src/common/utils/getVehiclePosition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,kBAAkB,QACjB,MAAM,6CAEI,OAAO,KACrB,eAoEF,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -1,42 +1,72 @@
1
- import GeomType from "ol/geom/GeometryType";
1
+ import { LineString } from 'ol/geom';
2
+ /**
3
+ * Interpolate or not the vehicle position from a trajectory at a specific date.
4
+ *
5
+ * @param {number} now Current date to interpolate a position with. In ms.
6
+ * @param {RealtimeTrajectory} trajectory The trajectory to interpolate.
7
+ * @param {boolean} noInterpolate If true, the vehicle position is not interpolated on each render but only once.
8
+ * @returns
9
+ */
2
10
  const getVehiclePosition = (now, trajectory, noInterpolate) => {
3
- const {
4
- time_intervals: timeIntervals,
5
- olGeometry: geometry,
6
- coordinate
7
- } = trajectory.properties;
8
- let coord;
9
- let rotation;
10
- if (noInterpolate && coordinate) {
11
- coord = coordinate;
12
- } else if (geometry.getType() === GeomType.POINT) {
13
- coord = geometry.getCoordinates();
14
- } else if (geometry.getType() === GeomType.LINE_STRING) {
15
- const intervals = timeIntervals || [[]];
16
- const firstInterval = intervals[0];
17
- const lastInterval = intervals[intervals.length - 1];
18
- if (now < firstInterval[0]) {
19
- [, , rotation] = firstInterval;
20
- coord = geometry.getFirstCoordinate();
21
- } else if (now > lastInterval[0]) {
22
- [, , rotation] = lastInterval;
23
- coord = geometry.getLastCoordinate();
24
- } else {
25
- for (let j = 0; j < intervals.length - 1; j += 1) {
26
- const [start, startFrac] = intervals[j];
27
- const [end, endFrac] = intervals[j + 1];
28
- if (start <= now && now <= end) {
29
- const timeFrac = Math.min((now - start) / (end - start), 1);
30
- const geomFrac = timeFrac * (endFrac - startFrac) + startFrac;
31
- coord = geometry.getCoordinateAt(geomFrac);
32
- [, , rotation] = intervals[j];
33
- break;
11
+ const { time_intervals: timeIntervals, olGeometry, coordinate, } = trajectory.properties;
12
+ const { coordinates } = trajectory.geometry;
13
+ let { type } = trajectory.geometry;
14
+ let geometry = olGeometry;
15
+ let coord;
16
+ let rotation;
17
+ if (olGeometry) {
18
+ type = geometry.getType();
19
+ }
20
+ if (noInterpolate && coordinate) {
21
+ coord = coordinate;
22
+ }
23
+ else if (type === 'Point') {
24
+ coord = coordinates;
25
+ }
26
+ else if (type === 'LineString') {
27
+ if (!geometry) {
28
+ geometry = new LineString(coordinates);
29
+ }
30
+ const intervals = timeIntervals || [[]];
31
+ const firstInterval = intervals[0];
32
+ const lastInterval = intervals[intervals.length - 1];
33
+ // Between the last time interval of a trajectory event and the beginning
34
+ // of the new trajectory event, there is few seconds, can be 6 to 30
35
+ // seconds (that's why the vehicle jumps sometimes).
36
+ // So we make the choice here to display the last (or the first) position
37
+ // of an trajectory event instead of removing them, if the current date is
38
+ // outside the time intervals we display the vehicle at the last (or first) position known.
39
+ if (now < firstInterval[0]) {
40
+ // Display first position known.
41
+ [, , rotation] = firstInterval;
42
+ coord = geometry.getFirstCoordinate();
34
43
  }
35
- }
44
+ else if (now > lastInterval[0]) {
45
+ // Display last position known.
46
+ [, , rotation] = lastInterval;
47
+ coord = geometry.getLastCoordinate();
48
+ }
49
+ else {
50
+ // Interpolate position using time intervals.
51
+ for (let j = 0; j < intervals.length - 1; j += 1) {
52
+ // Rotation only available in realtime layer.
53
+ const [start, startFrac] = intervals[j];
54
+ const [end, endFrac] = intervals[j + 1];
55
+ if (start <= now && now <= end) {
56
+ // interpolate position inside the time interval.
57
+ const timeFrac = Math.min((now - start) / (end - start), 1);
58
+ const geomFrac = timeFrac * (endFrac - startFrac) + startFrac;
59
+ coord = geometry.getCoordinateAt(geomFrac);
60
+ [, , rotation] = intervals[j];
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ }
66
+ else {
67
+ // eslint-disable-next-line no-console
68
+ console.error('This geometry type is not supported. Only Point or LineString are. Current geometry: ', geometry);
36
69
  }
37
- } else {
38
- console.error("This geometry type is not supported. Only Point or LineString are. Current geometry: ", geometry);
39
- }
40
- return { coord, rotation };
70
+ return { coord, rotation };
41
71
  };
42
72
  export default getVehiclePosition;
@@ -0,0 +1,17 @@
1
+ export { default as getUrlWithParams } from "./getUrlWithParams";
2
+ export { default as getMapboxMapCopyrights } from "./getMapboxMapCopyrights";
3
+ export { default as removeDuplicate } from "./removeDuplicate";
4
+ export { default as createRealtimeFilters } from "./createRealtimeFilters";
5
+ export { default as getLayersAsFlatArray } from "./getLayersAsFlatArray";
6
+ export * from "./timeUtils";
7
+ export { default as sortByDelay } from "./sortByDelay";
8
+ export { default as renderTrajectories } from "./renderTrajectories";
9
+ export { default as getMaplibreRender } from "./getMaplibreRender";
10
+ export { default as getMapboxRender } from "./getMapboxRender";
11
+ export { default as debounceDeparturesMessages } from "./debounceDeparturesMessages";
12
+ export { default as debounceWebsocketMessages } from "./debounceWebsocketMessages";
13
+ export { default as sortAndFilterDepartures } from "./sortAndFilterDepartures";
14
+ export { default as compareDepartures } from "./compareDepartures";
15
+ export { default as createCanvas } from "./createCanvas";
16
+ export * as realtimeConfig from "./realtimeConfig";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/common/utils/index.js"],"names":[],"mappings":""}
@@ -1,5 +1,17 @@
1
- export { default as getMapboxStyleUrl } from "./getMapboxStyleUrl";
2
- export { default as getMapboxMapCopyrights } from "./getMapboxMapCopyrights";
3
- export { default as removeDuplicate } from "./removeDuplicate";
4
- export * from "./timeUtils";
5
- export { default as sortByDelay } from "./sortByDelay";
1
+ export { default as getUrlWithParams } from './getUrlWithParams';
2
+ export { default as getMapboxMapCopyrights } from './getMapboxMapCopyrights';
3
+ export { default as removeDuplicate } from './removeDuplicate';
4
+ export { default as createRealtimeFilters } from './createRealtimeFilters';
5
+ export { default as getLayersAsFlatArray } from './getLayersAsFlatArray';
6
+ export * from './timeUtils';
7
+ export { default as sortByDelay } from './sortByDelay';
8
+ export { default as renderTrajectories } from './renderTrajectories';
9
+ export { default as getMaplibreRender } from './getMaplibreRender';
10
+ export { default as getMapboxRender } from './getMapboxRender';
11
+ export { default as debounceDeparturesMessages } from './debounceDeparturesMessages';
12
+ export { default as debounceWebsocketMessages } from './debounceWebsocketMessages';
13
+ export { default as sortAndFilterDepartures } from './sortAndFilterDepartures';
14
+ export { default as compareDepartures } from './compareDepartures';
15
+ export { default as createCanvas } from './createCanvas';
16
+ import * as realtimeConfig_1 from './realtimeConfig';
17
+ export { realtimeConfig_1 as realtimeConfig };
@@ -0,0 +1,49 @@
1
+ import { AnyCanvasContext, RealtimeMot } from '../../types';
2
+ /**
3
+ * Trajserv value: 'Tram', 'Subway / Metro / S-Bahn', 'Train', 'Bus', 'Ferry', 'Cable Car', 'Gondola', 'Funicular', 'Long distance bus', 'Rail',
4
+ * New endpoint use Rail instead of Train.
5
+ * New tracker values: null, "tram", "subway", "rail", "bus", "ferry", "cablecar", "gondola", "funicular", "coach".
6
+ *
7
+ * @ignore
8
+ */
9
+ export declare const types: RegExp[];
10
+ /**
11
+ * @ignore
12
+ */
13
+ export declare const bgColors: string[];
14
+ /**
15
+ * @ignore
16
+ */
17
+ export declare const textColors: string[];
18
+ /**
19
+ * @ignore
20
+ */
21
+ export declare const getTypeIndex: (type: RealtimeMot) => number;
22
+ /**
23
+ * @ignore
24
+ */
25
+ export declare const getRadius: (type: RealtimeMot, zoom: number) => number;
26
+ /**
27
+ * @ignore
28
+ */
29
+ export declare const getBgColor: (type: RealtimeMot) => string;
30
+ /**
31
+ * @ignore
32
+ */
33
+ export declare const getTextColor: (type: RealtimeMot) => string;
34
+ /**
35
+ * @ignore
36
+ */
37
+ export declare const getTextSize: (ctx: AnyCanvasContext, markerSize: number, text: string, fontSize: number) => number;
38
+ /**
39
+ * @ignore
40
+ * @param {number} delayInMs Delay in milliseconds.
41
+ * @param {boolean} cancelled true if the journey is cancelled.
42
+ * @param {boolean} isDelayText true if the color is used for delay text of the symbol.
43
+ */
44
+ export declare const getDelayColor: (delayInMs: number | null, cancelled?: boolean, isDelayText?: boolean) => string;
45
+ /**
46
+ * @ignore
47
+ */
48
+ export declare const getDelayText: (delayInMs: number, cancelled: boolean) => string;
49
+ //# sourceMappingURL=realtimeConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtimeConfig.d.ts","sourceRoot":"","sources":["../../../src/common/utils/realtimeConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAe5D;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,EAAE,MAAM,EAWzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,EAW5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,EAW9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,SAAU,WAAW,KAAG,MAKhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,SAAU,WAAW,QAAQ,MAAM,KAAG,MAO3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,SAAU,WAAW,KAAG,MAO9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,SAAU,WAAW,KAAG,MAOhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,QACjB,gBAAgB,cACT,MAAM,QACZ,MAAM,YACF,MAAM,KACf,MAkBF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,cACb,MAAM,GAAG,IAAI,cACZ,OAAO,gBACL,OAAO,KACpB,MAoBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,cAAe,MAAM,aAAa,OAAO,KAAG,MAmBpE,CAAC"}
@@ -0,0 +1,173 @@
1
+ const radiusMapping = [
2
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
3
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
4
+ [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],
5
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
6
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
7
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
8
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
9
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
10
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
11
+ [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],
12
+ ];
13
+ /**
14
+ * Trajserv value: 'Tram', 'Subway / Metro / S-Bahn', 'Train', 'Bus', 'Ferry', 'Cable Car', 'Gondola', 'Funicular', 'Long distance bus', 'Rail',
15
+ * New endpoint use Rail instead of Train.
16
+ * New tracker values: null, "tram", "subway", "rail", "bus", "ferry", "cablecar", "gondola", "funicular", "coach".
17
+ *
18
+ * @ignore
19
+ */
20
+ export const types = [
21
+ /^Tram/i,
22
+ /^Subway( \/ Metro \/ S-Bahn)?/i,
23
+ /^Train/i,
24
+ /^Bus/i,
25
+ /^Ferry/i,
26
+ /^Cable ?Car/i,
27
+ /^Gondola/i,
28
+ /^Funicular/i,
29
+ /^(Long distance bus|coach)/i,
30
+ /^Rail/i, // New endpoint use Rail instead of Train.
31
+ ];
32
+ /**
33
+ * @ignore
34
+ */
35
+ export const bgColors = [
36
+ '#ffb400',
37
+ '#ff5400',
38
+ '#ff8080',
39
+ '#ea0000',
40
+ '#3000ff',
41
+ '#ffb400',
42
+ '#41a27b',
43
+ '#00d237',
44
+ '#b5b5b5',
45
+ '#ff8080',
46
+ ];
47
+ /**
48
+ * @ignore
49
+ */
50
+ export const textColors = [
51
+ '#000000',
52
+ '#ffffff',
53
+ '#000000',
54
+ '#ffffff',
55
+ '#ffffff',
56
+ '#000000',
57
+ '#ffffff',
58
+ '#000000',
59
+ '#000000',
60
+ '#000000',
61
+ ];
62
+ /**
63
+ * @ignore
64
+ */
65
+ export const getTypeIndex = (type) => {
66
+ if (typeof type === 'string') {
67
+ return types.findIndex((t) => t.test(type));
68
+ }
69
+ return type;
70
+ };
71
+ /**
72
+ * @ignore
73
+ */
74
+ export const getRadius = (type, zoom) => {
75
+ try {
76
+ const typeIdx = getTypeIndex(type || 0);
77
+ return radiusMapping[typeIdx][zoom];
78
+ }
79
+ catch (e) {
80
+ return 1;
81
+ }
82
+ };
83
+ /**
84
+ * @ignore
85
+ */
86
+ export const getBgColor = (type) => {
87
+ try {
88
+ const typeIdx = getTypeIndex(type);
89
+ return bgColors[typeIdx];
90
+ }
91
+ catch (e) {
92
+ return '#ffffff';
93
+ }
94
+ };
95
+ /**
96
+ * @ignore
97
+ */
98
+ export const getTextColor = (type) => {
99
+ try {
100
+ const typeIdx = getTypeIndex(type);
101
+ return textColors[typeIdx];
102
+ }
103
+ catch (e) {
104
+ return '#ffffff';
105
+ }
106
+ };
107
+ /**
108
+ * @ignore
109
+ */
110
+ export const getTextSize = (ctx, markerSize, text, fontSize) => {
111
+ if (!ctx) {
112
+ return 0;
113
+ }
114
+ ctx.font = `bold ${fontSize}px Arial`;
115
+ let newText = ctx.measureText(text);
116
+ const maxiter = 25;
117
+ let i = 0;
118
+ while (newText.width > markerSize - 6 && i < maxiter) {
119
+ // eslint-disable-next-line no-param-reassign
120
+ fontSize -= 0.5;
121
+ ctx.font = `bold ${fontSize}px arial, sans-serif`;
122
+ newText = ctx.measureText(text);
123
+ i += 1;
124
+ }
125
+ return fontSize;
126
+ };
127
+ /**
128
+ * @ignore
129
+ * @param {number} delayInMs Delay in milliseconds.
130
+ * @param {boolean} cancelled true if the journey is cancelled.
131
+ * @param {boolean} isDelayText true if the color is used for delay text of the symbol.
132
+ */
133
+ export const getDelayColor = (delayInMs, cancelled, isDelayText) => {
134
+ if (cancelled) {
135
+ return isDelayText ? '#ff0000' : '#a0a0a0'; // red or gray
136
+ }
137
+ if (delayInMs === null) {
138
+ return '#a0a0a0'; // grey { r: 160, g: 160, b: 160, s: '160,160,160' };
139
+ }
140
+ if (delayInMs >= 3600000) {
141
+ return '#ed004c'; // pink { r: 237, g: 0, b: 76, s: '237,0,76' };
142
+ }
143
+ if (delayInMs >= 500000) {
144
+ return '#e80000'; // red { r: 232, g: 0, b: 0, s: '232,0,0' };
145
+ }
146
+ if (delayInMs >= 300000) {
147
+ return '#ff4a00'; // orange { r: 255, g: 74, b: 0, s: '255,74,0' };
148
+ }
149
+ if (delayInMs >= 180000) {
150
+ return '#f7bf00'; // yellow { r: 247, g: 191, b: 0, s: '247,191,0' };
151
+ }
152
+ return '#00a00c'; // green { r: 0, g: 160, b: 12, s: '0,160,12' };
153
+ };
154
+ /**
155
+ * @ignore
156
+ */
157
+ export const getDelayText = (delayInMs, cancelled) => {
158
+ if (cancelled) {
159
+ return String.fromCodePoint(0x00d7);
160
+ }
161
+ if (delayInMs > 3600000) {
162
+ const rounded = Math.round(delayInMs / 3600000);
163
+ return `+${rounded}h`;
164
+ }
165
+ if (delayInMs > 59000) {
166
+ const rounded = Math.round(delayInMs / 60000);
167
+ return `+${rounded}m`;
168
+ }
169
+ if (delayInMs > 0) {
170
+ return `+${delayInMs}s`;
171
+ }
172
+ return '';
173
+ };