mobility-toolbox-js 2.0.0-beta.33 → 2.0.0-beta.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/RealtimeAPI.d.ts +6 -6
- package/api/RealtimeAPI.d.ts.map +1 -1
- package/api/RealtimeAPI.js +613 -0
- package/api/RoutingAPI.d.ts.map +1 -1
- package/api/RoutingAPI.js +35 -0
- package/api/StopsAPI.d.ts +1 -1
- package/api/StopsAPI.d.ts.map +1 -1
- package/api/StopsAPI.js +38 -0
- package/api/index.d.ts +3 -4
- package/api/index.d.ts.map +1 -1
- package/api/index.js +3 -0
- package/api/typedefs.js +73 -0
- package/common/api/HttpAPI.d.ts.map +1 -1
- package/common/api/HttpAPI.js +57 -0
- package/common/api/WebSocketAPI.d.ts +2 -2
- package/common/api/WebSocketAPI.d.ts.map +1 -1
- package/common/api/WebSocketAPI.js +290 -0
- package/common/controls/Control.d.ts +5 -5
- package/common/controls/Control.d.ts.map +1 -1
- package/common/controls/Control.js +137 -0
- package/common/index.js +2 -0
- package/common/layers/Layer.d.ts +11 -11
- package/common/layers/Layer.d.ts.map +1 -1
- package/common/layers/Layer.js +223 -0
- package/common/mixins/CopyrightMixin.js +43 -0
- package/common/mixins/MapboxLayerMixin.js +198 -0
- package/common/mixins/RealtimeLayerMixin.js +650 -0
- package/common/mixins/StopFinderMixin.d.ts +3 -3
- package/common/mixins/StopFinderMixin.d.ts.map +1 -1
- package/common/mixins/StopFinderMixin.js +156 -0
- package/common/mixins/UserInteractionsLayerMixin.js +192 -0
- package/common/styles/index.js +4 -0
- package/common/styles/realtimeDefaultStyle.js +239 -0
- package/common/styles/realtimeDelayStyle.js +13 -0
- package/common/styles/realtimeSimpleStyle.js +22 -0
- package/common/typedefs.js +22 -0
- package/common/utils/cleanStopTime.js +28 -0
- package/common/utils/compareDepartures.d.ts +1 -1
- package/common/utils/compareDepartures.d.ts.map +1 -1
- package/common/utils/compareDepartures.js +34 -0
- package/common/utils/createCanvas.js +27 -0
- package/common/utils/createTrackerFilters.d.ts +1 -1
- package/common/utils/createTrackerFilters.d.ts.map +1 -1
- package/common/utils/createTrackerFilters.js +67 -0
- package/common/utils/getLayersAsFlatArray.js +14 -0
- package/common/utils/getMapboxMapCopyrights.js +24 -0
- package/common/utils/getMapboxRender.js +74 -0
- package/common/utils/getMaplibreRender.js +35 -0
- package/common/utils/getRealtimeModeSuffix.js +7 -0
- package/common/utils/getUrlWithParams.js +18 -0
- package/common/utils/getVehiclePosition.js +63 -0
- package/common/utils/index.js +12 -0
- package/common/utils/removeDuplicate.d.ts +1 -1
- package/common/utils/removeDuplicate.d.ts.map +1 -1
- package/common/utils/removeDuplicate.js +15 -0
- package/common/utils/renderTrajectories.js +107 -0
- package/common/utils/sortByDelay.js +20 -0
- package/common/utils/timeUtils.js +39 -0
- package/common/utils/trackerConfig.js +170 -0
- package/iife.js +5 -0
- package/index.d.ts +4 -0
- package/index.js +10 -0
- package/mapbox/controls/CopyrightControl.d.ts +0 -1
- package/mapbox/controls/CopyrightControl.d.ts.map +1 -1
- package/mapbox/controls/CopyrightControl.js +53 -0
- package/mapbox/controls/index.js +2 -0
- package/mapbox/index.js +4 -0
- package/mapbox/layers/Layer.d.ts +1 -1
- package/mapbox/layers/Layer.d.ts.map +1 -1
- package/mapbox/layers/Layer.js +97 -0
- package/mapbox/layers/RealtimeLayer.d.ts +4 -4
- package/mapbox/layers/RealtimeLayer.d.ts.map +1 -1
- package/mapbox/layers/RealtimeLayer.js +270 -0
- package/mapbox/layers/index.js +2 -0
- package/mapbox/utils.js +43 -0
- package/mbt.js +6 -5
- package/mbt.js.map +2 -2
- package/mbt.min.js +2 -2
- package/mbt.min.js.map +2 -2
- package/ol/controls/CopyrightControl.js +69 -0
- package/ol/controls/RoutingControl.d.ts +6 -5
- package/ol/controls/RoutingControl.d.ts.map +1 -1
- package/ol/controls/RoutingControl.js +622 -0
- package/ol/controls/StopFinderControl.js +36 -0
- package/ol/controls/index.js +3 -0
- package/ol/index.js +5 -0
- package/ol/layers/Layer.d.ts +1 -1
- package/ol/layers/Layer.d.ts.map +1 -1
- package/ol/layers/Layer.js +148 -0
- package/ol/layers/MapboxLayer.d.ts +7 -7
- package/ol/layers/MapboxLayer.d.ts.map +1 -1
- package/ol/layers/MapboxLayer.js +101 -0
- package/ol/layers/MapboxStyleLayer.d.ts +3 -3
- package/ol/layers/MapboxStyleLayer.d.ts.map +1 -1
- package/ol/layers/MapboxStyleLayer.js +340 -0
- package/ol/layers/MaplibreLayer.d.ts +1 -1
- package/ol/layers/MaplibreLayer.d.ts.map +1 -1
- package/ol/layers/MaplibreLayer.js +35 -0
- package/ol/layers/RealtimeLayer.d.ts +2 -2
- package/ol/layers/RealtimeLayer.d.ts.map +1 -1
- package/ol/layers/RealtimeLayer.js +294 -0
- package/ol/layers/RoutingLayer.d.ts +2 -2
- package/ol/layers/RoutingLayer.d.ts.map +1 -1
- package/ol/layers/RoutingLayer.js +84 -0
- package/ol/layers/VectorLayer.d.ts +1 -1
- package/ol/layers/VectorLayer.d.ts.map +1 -1
- package/ol/layers/VectorLayer.js +38 -0
- package/ol/layers/WMSLayer.d.ts +1 -1
- package/ol/layers/WMSLayer.d.ts.map +1 -1
- package/ol/layers/WMSLayer.js +72 -0
- package/ol/layers/index.js +8 -0
- package/ol/styles/fullTrajectoryDelayStyle.js +33 -0
- package/ol/styles/fullTrajectoryStyle.js +44 -0
- package/ol/styles/index.js +2 -0
- package/package.json +2 -2
- package/setupTests.js +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compareDepartures.d.ts","sourceRoot":"","sources":["../../../src/common/utils/compareDepartures.js"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,
|
|
1
|
+
{"version":3,"file":"compareDepartures.d.ts","sourceRoot":"","sources":["../../../src/common/utils/compareDepartures.js"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,sCAJW,MAAM,KACN,MAAM,0CAiChB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare two given departures for sort alogithm,
|
|
3
|
+
* @param {Object} a First departure.
|
|
4
|
+
* @param {Object} b Second departure.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
const compareDepartures = (a, b, sortByMinArrivalTime = false) => {
|
|
8
|
+
// First LEAVING and HIDDEN, then BOARDING and then sorted by time.
|
|
9
|
+
const topStates = ['HIDDEN', 'LEAVING', 'BOARDING'];
|
|
10
|
+
const aTop = a.has_fzo && topStates.indexOf(a.state) > -1;
|
|
11
|
+
const bTop = b.has_fzo && topStates.indexOf(b.state) > -1;
|
|
12
|
+
if (aTop || bTop) {
|
|
13
|
+
if (aTop !== bTop) {
|
|
14
|
+
return aTop ? -1 : 1;
|
|
15
|
+
}
|
|
16
|
+
if (a.state !== b.state) {
|
|
17
|
+
// one is leaving
|
|
18
|
+
return topStates.indexOf(a.state) - topStates.indexOf(b.state);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
let aDuration = null;
|
|
22
|
+
let bDuration = null;
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
if (sortByMinArrivalTime) {
|
|
25
|
+
aDuration = new Date(a.min_arrival_time || a.time).getTime() - now;
|
|
26
|
+
bDuration = new Date(b.min_arrival_time || b.time).getTime() - now;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
aDuration = new Date(a.time).getTime() - now;
|
|
30
|
+
bDuration = new Date(b.time).getTime() - now;
|
|
31
|
+
}
|
|
32
|
+
return aDuration - bDuration;
|
|
33
|
+
};
|
|
34
|
+
export default compareDepartures;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function try to create a canvas element and return it.
|
|
3
|
+
* it uses document.createElement('canvas') if document is available
|
|
4
|
+
* or new OffscreenCanvas(width, height) if OffscreenCanvas is avalaible (for web worker)
|
|
5
|
+
* or it returns null if neither is available.
|
|
6
|
+
*/
|
|
7
|
+
const createCanvas = (width, height) => {
|
|
8
|
+
let canvas = null;
|
|
9
|
+
// Prevent SSR errors
|
|
10
|
+
if (typeof window === 'undefined') {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (document === null || document === void 0 ? void 0 : document.createElement) {
|
|
14
|
+
canvas = document.createElement('canvas');
|
|
15
|
+
canvas.width = width;
|
|
16
|
+
canvas.height = height;
|
|
17
|
+
}
|
|
18
|
+
else if (OffscreenCanvas) {
|
|
19
|
+
canvas = new OffscreenCanvas(width, height);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.error("We didn't find a way to create a canvas element, document.createElement('canvas') and new OffscrenCanvas() are not supported");
|
|
24
|
+
}
|
|
25
|
+
return canvas;
|
|
26
|
+
};
|
|
27
|
+
export default createCanvas;
|
|
@@ -8,5 +8,5 @@ export default createFilters;
|
|
|
8
8
|
* @param {Regexp} regexLine - A regex aplly of vehcile's name.
|
|
9
9
|
* @private
|
|
10
10
|
*/
|
|
11
|
-
declare function createFilters(line: string | Array<string>, route: string | Array<string>, operator: string | Array<string>, regexLine: Regexp): (t: any) => boolean;
|
|
11
|
+
declare function createFilters(line: string | Array<string>, route: string | Array<string>, operator: string | Array<string>, regexLine: Regexp): ((t: any) => boolean) | null;
|
|
12
12
|
//# sourceMappingURL=createTrackerFilters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTrackerFilters.d.ts","sourceRoot":"","sources":["../../../src/common/utils/createTrackerFilters.js"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,qCANW,MAAM,GAAC,MAAM,MAAM,CAAC,SACpB,MAAM,GAAC,MAAM,MAAM,CAAA,YACnB,MAAM,GAAC,MAAM,MAAM,CAAA,
|
|
1
|
+
{"version":3,"file":"createTrackerFilters.d.ts","sourceRoot":"","sources":["../../../src/common/utils/createTrackerFilters.js"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,qCANW,MAAM,GAAC,MAAM,MAAM,CAAC,SACpB,MAAM,GAAC,MAAM,MAAM,CAAA,YACnB,MAAM,GAAC,MAAM,MAAM,CAAA,mDA+E7B"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return a filter functions based on some parameters of a vehicle.
|
|
3
|
+
*
|
|
4
|
+
* @param {string|Array<string>} line - A list of vehicle's name to filter. Names can be separated by a comma. Ex: 'S1,S2,S3'
|
|
5
|
+
* @param {string|Array<string} route - A list of vehicle's route (contained in routeIdentifier property) to filter. Indentifiers can be separated by a comma. Ex: 'id1,id2,id3'
|
|
6
|
+
* @param {string|Array<string} operator A list of vehicle's operator to filter. Operators can be separated by a comma. Ex: 'SBB,DB'
|
|
7
|
+
* @param {Regexp} regexLine - A regex aplly of vehcile's name.
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
const createFilters = (line, route, operator, regexLine) => {
|
|
11
|
+
const filterList = [];
|
|
12
|
+
if (!line && !route && !operator && !regexLine) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (regexLine) {
|
|
16
|
+
const regexLineList = typeof regexLine === 'string' ? [regexLine] : regexLine;
|
|
17
|
+
const lineFilter = (item) => {
|
|
18
|
+
const name = item.properties.name ||
|
|
19
|
+
(item.properties.line && item.properties.line.name) ||
|
|
20
|
+
'';
|
|
21
|
+
if (!name) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return regexLineList.some((regexStr) => new RegExp(regexStr, 'i').test(name));
|
|
25
|
+
};
|
|
26
|
+
filterList.push(lineFilter);
|
|
27
|
+
}
|
|
28
|
+
if (line) {
|
|
29
|
+
const lineFiltersList = typeof line === 'string' ? line.split(',') : line;
|
|
30
|
+
const lineList = lineFiltersList.map((l) => l.replace(/\s+/g, '').toUpperCase());
|
|
31
|
+
const lineFilter = (item) => {
|
|
32
|
+
const { line: linee, name } = item.properties;
|
|
33
|
+
const lineName = (name || (linee && linee.name) || '').toUpperCase();
|
|
34
|
+
if (!lineName) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return lineList.includes(lineName);
|
|
38
|
+
};
|
|
39
|
+
filterList.push(lineFilter);
|
|
40
|
+
}
|
|
41
|
+
if (route) {
|
|
42
|
+
const routes = typeof route === 'string' ? route.split(',') : route;
|
|
43
|
+
const routeList = routes.map((item) => parseInt(item, 10));
|
|
44
|
+
const routeFilter = (item) => {
|
|
45
|
+
const routeId = parseInt(item.properties.routeIdentifier.split('.')[0], 10);
|
|
46
|
+
return routeList.includes(routeId);
|
|
47
|
+
};
|
|
48
|
+
filterList.push(routeFilter);
|
|
49
|
+
}
|
|
50
|
+
if (operator) {
|
|
51
|
+
const operatorList = typeof operator === 'string' ? [operator] : operator;
|
|
52
|
+
const operatorFilter = (item) => operatorList.some((op) => new RegExp(op, 'i').test(item.properties.operator));
|
|
53
|
+
filterList.push(operatorFilter);
|
|
54
|
+
}
|
|
55
|
+
if (!filterList.length) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return (t) => {
|
|
59
|
+
for (let i = 0; i < filterList.length; i += 1) {
|
|
60
|
+
if (!filterList[i](t)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
export default createFilters;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getLayersAsFlatArray = (layersOrLayer) => {
|
|
2
|
+
let layers = layersOrLayer;
|
|
3
|
+
if (!Array.isArray(layers)) {
|
|
4
|
+
layers = [layersOrLayer];
|
|
5
|
+
}
|
|
6
|
+
let flatLayers = [];
|
|
7
|
+
layers.forEach((layer) => {
|
|
8
|
+
flatLayers.push(layer);
|
|
9
|
+
const { children } = layer;
|
|
10
|
+
flatLayers = flatLayers.concat(getLayersAsFlatArray(children || []));
|
|
11
|
+
});
|
|
12
|
+
return flatLayers;
|
|
13
|
+
};
|
|
14
|
+
export default getLayersAsFlatArray;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import removeDuplicate from './removeDuplicate';
|
|
2
|
+
/**
|
|
3
|
+
* Return the copyright a Mapbox map.
|
|
4
|
+
* @param {mapboxgl.Map} map A Mapbox map
|
|
5
|
+
* @ignore
|
|
6
|
+
*/
|
|
7
|
+
const getMapboxMapCopyrights = (map) => {
|
|
8
|
+
if (!map || !map.style) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const { sourceCaches } = map.style;
|
|
12
|
+
let copyrights = [];
|
|
13
|
+
Object.values(sourceCaches).forEach((sourceCache) => {
|
|
14
|
+
if (sourceCache.used) {
|
|
15
|
+
const source = sourceCache.getSource();
|
|
16
|
+
const attribution = source.attribution || (source.options && source.options.attribution);
|
|
17
|
+
if (attribution) {
|
|
18
|
+
copyrights = copyrights.concat(attribution.replace(/©/g, '©').split(/(<a.*?<\/a>)/));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return removeDuplicate(copyrights);
|
|
23
|
+
};
|
|
24
|
+
export default getMapboxMapCopyrights;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import { toLonLat } from 'ol/proj';
|
|
3
|
+
/**
|
|
4
|
+
* Return the render function fo the olLayer of a MaplibreLayer
|
|
5
|
+
*/
|
|
6
|
+
export default function getMapboxRender(mapoxLayer) {
|
|
7
|
+
return (frameState) => {
|
|
8
|
+
const { map, mbMap, renderState, olLayer } = mapoxLayer;
|
|
9
|
+
if (!map || !mbMap) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
let changed = false;
|
|
13
|
+
const canvas = mbMap.getCanvas();
|
|
14
|
+
const { viewState } = frameState;
|
|
15
|
+
const visible = olLayer.getVisible();
|
|
16
|
+
if (renderState.visible !== visible) {
|
|
17
|
+
canvas.style.display = visible ? 'block' : 'none';
|
|
18
|
+
renderState.visible = visible;
|
|
19
|
+
// Needed since mapbox-gl 1.9.0.
|
|
20
|
+
// Without you don't see others ol layers on top.
|
|
21
|
+
canvas.style.position = 'absolute';
|
|
22
|
+
}
|
|
23
|
+
const opacity = olLayer.getOpacity();
|
|
24
|
+
if (renderState.opacity !== opacity) {
|
|
25
|
+
canvas.style.opacity = opacity;
|
|
26
|
+
renderState.opacity = opacity;
|
|
27
|
+
}
|
|
28
|
+
// adjust view parameters in mapbox
|
|
29
|
+
const { rotation } = viewState;
|
|
30
|
+
if (renderState.rotation !== rotation) {
|
|
31
|
+
mbMap.rotateTo((-(rotation || 0) * 180) / Math.PI, {
|
|
32
|
+
animate: false,
|
|
33
|
+
});
|
|
34
|
+
changed = true;
|
|
35
|
+
renderState.rotation = rotation;
|
|
36
|
+
}
|
|
37
|
+
if (renderState.zoom !== viewState.zoom ||
|
|
38
|
+
renderState.center[0] !== viewState.center[0] ||
|
|
39
|
+
renderState.center[1] !== viewState.center[1]) {
|
|
40
|
+
mbMap.jumpTo({
|
|
41
|
+
center: toLonLat(viewState.center),
|
|
42
|
+
zoom: viewState.zoom - 1,
|
|
43
|
+
animate: false,
|
|
44
|
+
});
|
|
45
|
+
changed = true;
|
|
46
|
+
renderState.zoom = viewState.zoom;
|
|
47
|
+
renderState.center = viewState.center;
|
|
48
|
+
}
|
|
49
|
+
const size = map.getSize();
|
|
50
|
+
if (renderState.size[0] !== size[0] || renderState.size[1] !== size[1]) {
|
|
51
|
+
changed = true;
|
|
52
|
+
renderState.size = size;
|
|
53
|
+
}
|
|
54
|
+
// cancel the scheduled update & trigger synchronous redraw
|
|
55
|
+
// see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
|
|
56
|
+
// NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX
|
|
57
|
+
if (mbMap && mbMap.style && mbMap.isStyleLoaded() && changed) {
|
|
58
|
+
try {
|
|
59
|
+
if (mbMap._frame) {
|
|
60
|
+
mbMap._frame.cancel();
|
|
61
|
+
mbMap._frame = null;
|
|
62
|
+
}
|
|
63
|
+
mbMap._render();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
// ignore render errors because it's probably related to
|
|
67
|
+
// a render during an update of the style.
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.warn(err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return mbMap.getContainer();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
return (frameState) => {
|
|
8
|
+
const { map, mbMap, olLayer } = maplibreLayer;
|
|
9
|
+
if (!map || !mbMap) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const canvas = mbMap.getCanvas();
|
|
13
|
+
const { viewState } = frameState;
|
|
14
|
+
const opacity = olLayer.getOpacity();
|
|
15
|
+
canvas.style.opacity = opacity;
|
|
16
|
+
// adjust view parameters in mapbox
|
|
17
|
+
mbMap.jumpTo({
|
|
18
|
+
center: toLonLat(viewState.center),
|
|
19
|
+
zoom: viewState.zoom - 1,
|
|
20
|
+
bearing: toDegrees(-viewState.rotation),
|
|
21
|
+
animate: false,
|
|
22
|
+
});
|
|
23
|
+
if (!canvas.isConnected) {
|
|
24
|
+
// The canvas is not connected to the DOM, request a map rendering at the next animation frame
|
|
25
|
+
// to set the canvas size.
|
|
26
|
+
map.render();
|
|
27
|
+
}
|
|
28
|
+
else if (canvas.width !== frameState.size[0] ||
|
|
29
|
+
canvas.height !== frameState.size[1]) {
|
|
30
|
+
mbMap.resize();
|
|
31
|
+
}
|
|
32
|
+
mbMap.redraw();
|
|
33
|
+
return mbMap.getContainer();
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -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,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,63 @@
|
|
|
1
|
+
import GeomType from 'ol/geom/GeometryType';
|
|
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
|
+
*/
|
|
10
|
+
const getVehiclePosition = (now, trajectory, noInterpolate) => {
|
|
11
|
+
const { time_intervals: timeIntervals, olGeometry: geometry, coordinate, } = trajectory.properties;
|
|
12
|
+
let coord;
|
|
13
|
+
let rotation;
|
|
14
|
+
if (noInterpolate && coordinate) {
|
|
15
|
+
coord = coordinate;
|
|
16
|
+
}
|
|
17
|
+
else if (geometry.getType() === GeomType.POINT) {
|
|
18
|
+
coord = geometry.getCoordinates();
|
|
19
|
+
}
|
|
20
|
+
else if (geometry.getType() === GeomType.LINE_STRING) {
|
|
21
|
+
const intervals = timeIntervals || [[]];
|
|
22
|
+
const firstInterval = intervals[0];
|
|
23
|
+
const lastInterval = intervals[intervals.length - 1];
|
|
24
|
+
// Between the last time interval of a trajectory event and the beginning
|
|
25
|
+
// of the new trajectory event, there is few seconds, can be 6 to 30
|
|
26
|
+
// seconds (that's why the vehicle jumps sometimes).
|
|
27
|
+
// So we make the choice here to display the last (or the first) position
|
|
28
|
+
// of an trajectory event instead of removing them, if the current date is
|
|
29
|
+
// outside the time intervals we display the vehicle at the last (or first) position known.
|
|
30
|
+
if (now < firstInterval[0]) {
|
|
31
|
+
// Display first position known.
|
|
32
|
+
[, , rotation] = firstInterval;
|
|
33
|
+
coord = geometry.getFirstCoordinate();
|
|
34
|
+
}
|
|
35
|
+
else if (now > lastInterval[0]) {
|
|
36
|
+
// Display last position known.
|
|
37
|
+
[, , rotation] = lastInterval;
|
|
38
|
+
coord = geometry.getLastCoordinate();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Interpolate position using time intervals.
|
|
42
|
+
for (let j = 0; j < intervals.length - 1; j += 1) {
|
|
43
|
+
// Rotation only available in realtime layer.
|
|
44
|
+
const [start, startFrac] = intervals[j];
|
|
45
|
+
const [end, endFrac] = intervals[j + 1];
|
|
46
|
+
if (start <= now && now <= end) {
|
|
47
|
+
// interpolate position inside the time interval.
|
|
48
|
+
const timeFrac = Math.min((now - start) / (end - start), 1);
|
|
49
|
+
const geomFrac = timeFrac * (endFrac - startFrac) + startFrac;
|
|
50
|
+
coord = geometry.getCoordinateAt(geomFrac);
|
|
51
|
+
[, , rotation] = intervals[j];
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.error('This geometry type is not supported. Only Point or LineString are. Current geometry: ', geometry);
|
|
60
|
+
}
|
|
61
|
+
return { coord, rotation };
|
|
62
|
+
};
|
|
63
|
+
export default getVehiclePosition;
|
|
@@ -0,0 +1,12 @@
|
|
|
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 createTrackerFilters } from './createTrackerFilters';
|
|
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
|
+
import * as trackerConfig_1 from './trackerConfig';
|
|
12
|
+
export { trackerConfig_1 as trackerConfig };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"removeDuplicate.d.ts","sourceRoot":"","sources":["../../../src/common/utils/removeDuplicate.js"],"names":[],"mappings":";AAAA;;;;;;GAMG;AACH,
|
|
1
|
+
{"version":3,"file":"removeDuplicate.d.ts","sourceRoot":"","sources":["../../../src/common/utils/removeDuplicate.js"],"names":[],"mappings":";AAAA;;;;;;GAMG;AACH,oDAYC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function remove duplicates lower case string value of an array.
|
|
3
|
+
* It removes also null, undefined or non string values.
|
|
4
|
+
*
|
|
5
|
+
* @param {array} array Array of values.
|
|
6
|
+
* @ignore
|
|
7
|
+
*/
|
|
8
|
+
const removeDuplicate = (array) => {
|
|
9
|
+
const arrWithoutEmptyValues = array.filter((val) => val !== undefined && val !== null && val.trim && val.trim());
|
|
10
|
+
const lowerCasesValues = arrWithoutEmptyValues.map((str) => str.toLowerCase());
|
|
11
|
+
const uniqueLowerCaseValues = [...new Set(lowerCasesValues)];
|
|
12
|
+
const uniqueValues = uniqueLowerCaseValues.map((uniqueStr) => arrWithoutEmptyValues.find((str) => str.toLowerCase() === uniqueStr));
|
|
13
|
+
return uniqueValues;
|
|
14
|
+
};
|
|
15
|
+
export default removeDuplicate;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
import { compose, apply, create } from 'ol/transform';
|
|
3
|
+
import getVehiclePosition from './getVehiclePosition';
|
|
4
|
+
/**
|
|
5
|
+
* Draw all the trajectories available in a canvas.
|
|
6
|
+
* @param {HTMLCanvas|HTMLOffscreenCanvas} The canvas where to draw the trajectories.
|
|
7
|
+
* @param {ViewState} trajectories An array of trajectories.
|
|
8
|
+
* @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.
|
|
9
|
+
* @param {ViewState} viewState The view state of the map.
|
|
10
|
+
* @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.
|
|
11
|
+
* @param {boolean} options.selectedVehicleId The id of the vehicle to select.
|
|
12
|
+
* @param {boolean} options.noInterpolate If true trajectories are not interpolated but
|
|
13
|
+
* drawn at the last known coordinate. Use this for performance optimization
|
|
14
|
+
* during map navigation.
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
const renderTrajectories = (canvas, trajectories, style, viewState, options) => {
|
|
18
|
+
if (!canvas) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
const { time = Date.now(), size = [], center, resolution, rotation = 0, pixelRatio, } = viewState;
|
|
22
|
+
const { noInterpolate = false, hoverVehicleId, selectedVehicleId } = options;
|
|
23
|
+
const context = canvas.getContext('2d');
|
|
24
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
25
|
+
const [width, height] = size;
|
|
26
|
+
if (width && height && (canvas.width !== width || canvas.height !== height)) {
|
|
27
|
+
[canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];
|
|
28
|
+
}
|
|
29
|
+
const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);
|
|
30
|
+
// Offscreen canvas has not style attribute
|
|
31
|
+
if (canvas.style) {
|
|
32
|
+
canvas.style.width = `${canvas.width / pixelRatio}px`;
|
|
33
|
+
canvas.style.height = `${canvas.height / pixelRatio}px`;
|
|
34
|
+
}
|
|
35
|
+
let hoverVehicleImg;
|
|
36
|
+
let hoverVehiclePx;
|
|
37
|
+
let hoverVehicleWidth;
|
|
38
|
+
let hoverVehicleHeight;
|
|
39
|
+
let selectedVehicleImg;
|
|
40
|
+
let selectedVehiclePx;
|
|
41
|
+
let selectedVehicleWidth;
|
|
42
|
+
let selectedVehicleHeight;
|
|
43
|
+
const renderedTrajectories = [];
|
|
44
|
+
for (let i = trajectories.length - 1; i >= 0; i -= 1) {
|
|
45
|
+
const trajectory = trajectories[i];
|
|
46
|
+
// We simplify the trajectory object
|
|
47
|
+
const { train_id: id, timeOffset } = trajectory.properties;
|
|
48
|
+
// We set the rotation and the timeFraction of the trajectory (used by tralis).
|
|
49
|
+
// if rotation === null that seems there is no rotation available.
|
|
50
|
+
const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);
|
|
51
|
+
// We store the current vehicle position to the trajectory.
|
|
52
|
+
trajectories[i].properties.coordinate = coord;
|
|
53
|
+
trajectories[i].properties.rotation = rotationIcon;
|
|
54
|
+
if (!coord) {
|
|
55
|
+
// eslint-disable-next-line no-continue
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
let px = apply(coordinateToPixelTransform, [...coord]);
|
|
59
|
+
if (!px) {
|
|
60
|
+
// eslint-disable-next-line no-continue
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
px = px.map((p) => p * pixelRatio);
|
|
64
|
+
if (px[0] < 0 ||
|
|
65
|
+
px[0] > canvas.width ||
|
|
66
|
+
px[1] < 0 ||
|
|
67
|
+
px[1] > canvas.height) {
|
|
68
|
+
// eslint-disable-next-line no-continue
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const vehicleImg = style(trajectory, viewState, options);
|
|
72
|
+
if (!vehicleImg) {
|
|
73
|
+
// eslint-disable-next-line no-continue
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const imgWidth = vehicleImg.width;
|
|
77
|
+
const imgHeight = vehicleImg.height;
|
|
78
|
+
if (hoverVehicleId !== id && selectedVehicleId !== id) {
|
|
79
|
+
context.drawImage(vehicleImg, px[0] - imgWidth / 2, px[1] - imgHeight / 2, imgWidth, imgHeight);
|
|
80
|
+
}
|
|
81
|
+
if (hoverVehicleId && hoverVehicleId === id) {
|
|
82
|
+
// Store the canvas to draw it at the end
|
|
83
|
+
hoverVehicleImg = vehicleImg;
|
|
84
|
+
hoverVehiclePx = px;
|
|
85
|
+
hoverVehicleWidth = imgWidth;
|
|
86
|
+
hoverVehicleHeight = imgHeight;
|
|
87
|
+
}
|
|
88
|
+
if (selectedVehicleId && selectedVehicleId === id) {
|
|
89
|
+
// Store the canvas to draw it at the end
|
|
90
|
+
selectedVehicleImg = vehicleImg;
|
|
91
|
+
selectedVehiclePx = px;
|
|
92
|
+
selectedVehicleWidth = imgWidth;
|
|
93
|
+
selectedVehicleHeight = imgHeight;
|
|
94
|
+
}
|
|
95
|
+
renderedTrajectories.push(trajectory);
|
|
96
|
+
}
|
|
97
|
+
if (selectedVehicleImg) {
|
|
98
|
+
context.drawImage(selectedVehicleImg, selectedVehiclePx[0] - selectedVehicleWidth / 2, selectedVehiclePx[1] - selectedVehicleHeight / 2, selectedVehicleWidth, selectedVehicleHeight);
|
|
99
|
+
}
|
|
100
|
+
if (hoverVehicleImg) {
|
|
101
|
+
context.drawImage(hoverVehicleImg, hoverVehiclePx[0] - hoverVehicleWidth / 2, hoverVehiclePx[1] - hoverVehicleHeight / 2, hoverVehicleWidth, hoverVehicleHeight);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
renderedTrajectories,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export default renderTrajectories;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const sortByDelay = (traj1, traj2) => {
|
|
2
|
+
const props1 = traj1.properties;
|
|
3
|
+
const props2 = traj2.properties;
|
|
4
|
+
if (props1.delay === null && props2.delay !== null) {
|
|
5
|
+
return 1;
|
|
6
|
+
}
|
|
7
|
+
if (props2.delay === null && props1.delay !== null) {
|
|
8
|
+
return -1;
|
|
9
|
+
}
|
|
10
|
+
// We put cancelled train inbetween green and yellow trains
|
|
11
|
+
// >=180000ms corresponds to yellow train
|
|
12
|
+
if (props1.cancelled && !props2.cancelled) {
|
|
13
|
+
return props2.delay < 180000 ? -1 : 1;
|
|
14
|
+
}
|
|
15
|
+
if (props2.cancelled && !props1.cancelled) {
|
|
16
|
+
return props1.delay < 180000 ? 1 : -1;
|
|
17
|
+
}
|
|
18
|
+
return props2.delay - props1.delay;
|
|
19
|
+
};
|
|
20
|
+
export default sortByDelay;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a Date object as UTC date string .
|
|
3
|
+
* ex: 2019 09 01
|
|
4
|
+
* @ignore
|
|
5
|
+
*/
|
|
6
|
+
export const getUTCDateString = (now = new Date()) => {
|
|
7
|
+
let month = (now.getUTCMonth() + 1).toString();
|
|
8
|
+
month = month.length === 1 ? `0${month}` : month;
|
|
9
|
+
let day = now.getUTCDate().toString();
|
|
10
|
+
day = day.length === 1 ? `0${day}` : day;
|
|
11
|
+
return [now.getUTCFullYear(), month, day].join('');
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Get the UTC time string of Date object.
|
|
15
|
+
* ex: 09:05:01.123
|
|
16
|
+
* @ignore
|
|
17
|
+
*/
|
|
18
|
+
export const getUTCTimeString = (date) => [
|
|
19
|
+
date.getUTCHours(),
|
|
20
|
+
date.getUTCMinutes(),
|
|
21
|
+
`${date.getUTCSeconds()}.${date.getUTCMilliseconds()}`,
|
|
22
|
+
].join(':');
|
|
23
|
+
/**
|
|
24
|
+
* Returns a string representation of a number, with a zero if the number is lower than 10.
|
|
25
|
+
* @ignore
|
|
26
|
+
*/
|
|
27
|
+
export const pad = (integer) => (integer < 10 ? `0${integer}` : integer);
|
|
28
|
+
/**
|
|
29
|
+
* Returns a 'hh:mm' string from a time in ms.
|
|
30
|
+
* @param {Number} timeInMs Time in milliseconds.
|
|
31
|
+
* @ignore
|
|
32
|
+
*/
|
|
33
|
+
export const getHoursAndMinutes = (timeInMs) => {
|
|
34
|
+
if (!timeInMs || timeInMs <= 0) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
const date = new Date(timeInMs);
|
|
38
|
+
return `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
39
|
+
};
|