From 1cf1cf7d1e19b2bfb98560b5d3bf4d7fa02811a0 Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Fri, 27 Feb 2026 16:20:04 +0100 Subject: [PATCH 1/6] fix: add offset when vehicle are drawn on the same pixel --- dev.js | 1 + src/common/utils/renderTrajectories.ts | 27 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/dev.js b/dev.js index a8fb8ec8..5e3252dd 100644 --- a/dev.js +++ b/dev.js @@ -39,6 +39,7 @@ const realtimeLayer = new RealtimeLayer({ url: 'wss://api.geops.io/tracker-ws/v1/', // prod // url: 'wss://api.geops.io/realtime-ws/v1/', // sbm styleOptions: { + showHeading: true, // useHeadingStyle: true, // useDelayStyle: true, }, diff --git a/src/common/utils/renderTrajectories.ts b/src/common/utils/renderTrajectories.ts index f9d4d1aa..4f1e0888 100644 --- a/src/common/utils/renderTrajectories.ts +++ b/src/common/utils/renderTrajectories.ts @@ -104,6 +104,9 @@ const renderTrajectories = ( let selectedVehicleImg; let selectedVehiclePx; const renderedTrajectories = []; + const cachePixel: Record = {}; + const cacheNbTrainAtPixel: Record = {}; + const cacheDistanceOffset: Record = {}; for (let i = trajectories.length - 1; i >= 0; i -= 1) { const trajectory = trajectories[i]; @@ -156,6 +159,28 @@ const renderTrajectories = ( continue; } + if (resolution < 1) { + const roundedPX = px.map((p) => { + return Math.round(p); + }); + const key = `${roundedPX.toString()}`; + if (!cachePixel[key]) { + cachePixel[key] = px; + cacheNbTrainAtPixel[key] = 1; + cacheDistanceOffset[key] = 40 * resolution; + } else { + // if (!hoverVehicleId) { + px[0] += 40 * cacheNbTrainAtPixel[key]; + // // } + trajectories[i].properties.coordinate = [ + coord[0] + cacheDistanceOffset[key], + coord[1], + ]; + cacheNbTrainAtPixel[key]++; + cacheDistanceOffset[key] += 40 * resolution; + } + } + if (hoverVehicleId !== id && selectedVehicleId !== id) { // To optimize the performance we use integer as pixel coordinate // to avoid an additional work by the browser on zoom level < 12. @@ -164,6 +189,7 @@ const renderTrajectories = ( [px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState, ); + context?.drawImage(vehicleImg, x, y); } @@ -171,6 +197,7 @@ const renderTrajectories = ( // Store the canvas to draw it at the end hoverVehicleImg = vehicleImg; hoverVehiclePx = px; + // console.log(resolution); } if (selectedVehicleId && selectedVehicleId === id) { From 33a2262d36009621db9d15fc5fb0454371aa6229 Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Fri, 27 Feb 2026 16:44:02 +0100 Subject: [PATCH 2/6] fix: show heading --- doc/public/static/examples/ol-realtime.js | 3 + doc/src/components/Esdoc/index.json | 1919 ++++++++++++--------- doc/yarn.lock | 127 +- src/common/utils/renderTrajectories.ts | 6 + 4 files changed, 1168 insertions(+), 887 deletions(-) diff --git a/doc/public/static/examples/ol-realtime.js b/doc/public/static/examples/ol-realtime.js index 2ddb9507..bd0875a7 100644 --- a/doc/public/static/examples/ol-realtime.js +++ b/doc/public/static/examples/ol-realtime.js @@ -11,6 +11,9 @@ export default () => { // Creates the Realtime layer const realtime = new RealtimeLayer({ apiKey: window.apiKey, + styleOptions: { + showHeading: true, + }, }); // Creates the map diff --git a/doc/src/components/Esdoc/index.json b/doc/src/components/Esdoc/index.json index 0577ee1e..01fa08a5 100644 --- a/doc/src/components/Esdoc/index.json +++ b/doc/src/components/Esdoc/index.json @@ -986,6 +986,18 @@ { "__docId__": 84, "kind": "external", + "name": "RealtimeFullTrajectoryCollection", + "externalLink": "https://developer.geops.io/apis/realtime#model-FullTrajectoryCollection", + "memberof": "build/.externals.js", + "static": true, + "longname": "build/.externals.js~RealtimeFullTrajectoryCollection", + "access": "private", + "description": "", + "builtinExternal": true + }, + { + "__docId__": 85, + "kind": "external", "name": "RealtimeFullTrajectory", "externalLink": "https://developer.geops.io/apis/realtime#model-FullTrajectory", "memberof": "build/.externals.js", @@ -996,7 +1008,7 @@ "builtinExternal": true }, { - "__docId__": 85, + "__docId__": 86, "kind": "external", "name": "RealtimeStation", "externalLink": "https://developer.geops.io/apis/realtime", @@ -1008,7 +1020,7 @@ "builtinExternal": true }, { - "__docId__": 86, + "__docId__": 87, "kind": "external", "name": "RealtimeNews", "externalLink": "https://developer.geops.io/apis/realtime", @@ -1020,7 +1032,7 @@ "builtinExternal": true }, { - "__docId__": 87, + "__docId__": 88, "kind": "external", "name": "RealtimeStopSequence", "externalLink": "https://developer.geops.io/apis/realtime#model-StopSequence", @@ -1032,7 +1044,7 @@ "builtinExternal": true }, { - "__docId__": 88, + "__docId__": 89, "kind": "external", "name": "RealtimeTrajectory", "externalLink": "https://developer.geops.io/apis/realtime#model-TrackerTrajectory", @@ -1044,7 +1056,7 @@ "builtinExternal": true }, { - "__docId__": 89, + "__docId__": 90, "kind": "external", "name": "RealtimeDeparture", "externalLink": "https://developer.geops.io/apis/realtime#model-Departure", @@ -1056,7 +1068,7 @@ "builtinExternal": true }, { - "__docId__": 90, + "__docId__": 91, "kind": "external", "name": "RealtimeStationId", "externalLink": "https://developer.geops.io/apis/realtime", @@ -1068,7 +1080,7 @@ "builtinExternal": true }, { - "__docId__": 91, + "__docId__": 92, "kind": "external", "name": "RealtimeTenant", "externalLink": "https://developer.geops.io/apis/realtime", @@ -1080,7 +1092,7 @@ "builtinExternal": true }, { - "__docId__": 92, + "__docId__": 93, "kind": "external", "name": "RoutingParameters", "externalLink": "https://developer.geops.io/apis/routing", @@ -1092,7 +1104,7 @@ "builtinExternal": true }, { - "__docId__": 93, + "__docId__": 94, "kind": "external", "name": "RoutingResponse", "externalLink": "https://developer.geops.io/apis/routing", @@ -1104,7 +1116,7 @@ "builtinExternal": true }, { - "__docId__": 94, + "__docId__": 95, "kind": "external", "name": "geoblocks/ol-maplibre-layer/MapLibreLayer", "externalLink": "https://geoblocks.github.io/ol-maplibre-layer/api/modules/MapLibreLayer.html", @@ -1116,10 +1128,10 @@ "builtinExternal": true }, { - "__docId__": 95, + "__docId__": 96, "kind": "file", "name": "build/api/HttpAPI.js", - "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport getUrlWithParams from '../common/utils/getUrlWithParams';\n/**\n * Common class to access to a geOps api using http.\n * @private\n */\nclass HttpAPI {\n constructor(options) {\n this.url = options.url;\n this.apiKey = options.apiKey;\n }\n /**\n * Append the apiKey before sending the request.\n *\n * @private\n */\n fetch(path, params, config) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.url) {\n throw new Error(`No url defined for request to ${this.url}/${path}`);\n }\n if (!this.url &&\n (!this.apiKey || this.apiKey === 'public') &&\n !this.url.includes('key=')) {\n throw new Error(`No apiKey defined for request to ${this.url}`);\n }\n const url = getUrlWithParams(`${this.url}${path || ''}`, Object.assign({ key: !this.apiKey || this.apiKey === 'public' ? undefined : this.apiKey }, (params || {})));\n const response = yield fetch(url.toString(), config);\n const data = (yield response.json());\n if (data.error) {\n throw new Error(data.error);\n }\n return data;\n });\n }\n}\nexport default HttpAPI;\n", + "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport getUrlWithParams from '../common/utils/getUrlWithParams';\nimport getUrlWithPath from '../common/utils/getUrlWithPath';\n/**\n * Common class to access to a geOps api using http.\n * @private\n */\nclass HttpAPI {\n constructor(options) {\n this.url = options.url;\n this.apiKey = options.apiKey;\n }\n /**\n * Append the apiKey before sending the request.\n *\n * @private\n */\n fetch(path, params, config) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.url) {\n throw new Error(`No url defined for request to ${this.url}/${path}`);\n }\n if (!this.url &&\n (!this.apiKey || this.apiKey === 'public') &&\n !this.url.includes('key=')) {\n throw new Error(`No apiKey defined for request to ${this.url}`);\n }\n const url = getUrlWithParams(getUrlWithPath(this.url, path), Object.assign({ key: !this.apiKey || this.apiKey === 'public' ? undefined : this.apiKey }, (params || {})));\n const response = yield fetch(url.toString(), config);\n const data = (yield response.json());\n if (data.error) {\n throw new Error(data.error);\n }\n return data;\n });\n }\n}\nexport default HttpAPI;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/HttpAPI.js", "access": "private", @@ -1127,7 +1139,7 @@ "lineNumber": 1 }, { - "__docId__": 96, + "__docId__": 97, "kind": "variable", "name": "__awaiter", "memberof": "build/api/HttpAPI.js", @@ -1148,7 +1160,7 @@ "ignore": true }, { - "__docId__": 97, + "__docId__": 98, "kind": "class", "name": "HttpAPI", "memberof": "build/api/HttpAPI.js", @@ -1159,11 +1171,11 @@ "importPath": "mobility-toolbox-js/build/api/HttpAPI.js", "importStyle": "HttpAPI", "description": "Common class to access to a geOps api using http.", - "lineNumber": 15, + "lineNumber": 16, "interface": false }, { - "__docId__": 98, + "__docId__": 99, "kind": "constructor", "name": "constructor", "memberof": "build/api/HttpAPI.js~HttpAPI", @@ -1173,11 +1185,11 @@ "longname": "build/api/HttpAPI.js~HttpAPI#constructor", "access": "private", "description": null, - "lineNumber": 16, + "lineNumber": 17, "undocument": true }, { - "__docId__": 99, + "__docId__": 100, "kind": "member", "name": "url", "memberof": "build/api/HttpAPI.js~HttpAPI", @@ -1185,7 +1197,7 @@ "longname": "build/api/HttpAPI.js~HttpAPI#url", "access": "private", "description": null, - "lineNumber": 17, + "lineNumber": 18, "undocument": true, "type": { "types": [ @@ -1194,7 +1206,7 @@ } }, { - "__docId__": 100, + "__docId__": 101, "kind": "member", "name": "apiKey", "memberof": "build/api/HttpAPI.js~HttpAPI", @@ -1202,7 +1214,7 @@ "longname": "build/api/HttpAPI.js~HttpAPI#apiKey", "access": "private", "description": null, - "lineNumber": 18, + "lineNumber": 19, "undocument": true, "type": { "types": [ @@ -1211,7 +1223,7 @@ } }, { - "__docId__": 101, + "__docId__": 102, "kind": "method", "name": "fetch", "memberof": "build/api/HttpAPI.js~HttpAPI", @@ -1221,7 +1233,7 @@ "longname": "build/api/HttpAPI.js~HttpAPI#fetch", "access": "private", "description": "Append the apiKey before sending the request.", - "lineNumber": 25, + "lineNumber": 26, "params": [ { "name": "path", @@ -1249,7 +1261,7 @@ } }, { - "__docId__": 102, + "__docId__": 103, "kind": "file", "name": "build/api/MapsetApi.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport HttpAPI from './HttpAPI';\n/**\n * This class provides convenience methods to use the [geOps Mapset API](https://geops.com/de/solution/mapset).\n *\n * @example\n * import { MapsetAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new MapsetAPI({\n * apiKey: 'yourApiKey',\n * // tenants: ['geopstest'],\n * // url: 'https://editor.mapset.io/api/v1',\n * });\n *\n * const plans = await api.getPlans({\n * bbox: [8.5, 47.3, 8.6, 47.4],\n * zoom: 10,\n * // timestamp: (new Date()).toISOString(),\n * });\n *\n * console.log('Log route:', JSON.stringify(plans));\n *\n * @public\n */\nclass MapsetAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string[]} [options.tags] Array of tags to filter plans.\n * @param {string[]} [options.tenants=[\"geopstest\"]] Array of tenants to filter plans.\n * @param {string} [options.url='https://editor.mapset.io/api/v1/'] Url of the [geOps Mapset API](https://geops.com/de/solution/mapset).\n */\n constructor(options) {\n var _a, _b;\n super(Object.assign(Object.assign({}, options), { \n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n url: options.url || 'https://editor.mapset.io/api/v1/' }));\n this.tags = [];\n this.tenants = [];\n this.tags = (_a = options.tags) !== null && _a !== void 0 ? _a : [];\n this.tenants = (_b = options.tenants) !== null && _b !== void 0 ? _b : ['geopstest'];\n }\n /**\n * Get single mapset plan by ID.\n *\n * @param {string} id Mapset Plan identifier.\n * @param {FetchOptions} config Options for the fetch request.\n * @return {Promise} A mapset plan.\n * @public\n */\n getPlanById(id_1) {\n return __awaiter(this, arguments, void 0, function* (id, config = {}) {\n return yield this.fetch(`meta/kml/${id}/`, {}, Object.assign({ method: 'GET' }, config));\n });\n }\n /**\n * Get a list of mapset plans.\n *\n * @param {MapsetGetPlansParameters} params Request parameters.\n * @param {FetchOptions} config Options for the fetch request.\n * @return {Promise} An array of mapset plan objects with kml strings in data attribute.\n * @public\n */\n getPlans(params_1) {\n return __awaiter(this, arguments, void 0, function* (params, config = {}) {\n var _a, _b, _c;\n const res = yield this.fetch('export/kml/', Object.assign({ defaultplans: ((_a = this.tags) === null || _a === void 0 ? void 0 : _a.toString()) ? 'false' : 'true', key: this.apiKey, tags: (_b = this.tags) === null || _b === void 0 ? void 0 : _b.toString(), tenants: (_c = this.tenants) === null || _c === void 0 ? void 0 : _c.toString() }, (params || {})), config);\n if (res === null || res === void 0 ? void 0 : res.detail) {\n throw new Error(res.detail);\n }\n return (res === null || res === void 0 ? void 0 : res.results) || [];\n });\n }\n}\nexport default MapsetAPI;\n", @@ -1260,7 +1272,7 @@ "lineNumber": 1 }, { - "__docId__": 103, + "__docId__": 104, "kind": "variable", "name": "__awaiter", "memberof": "build/api/MapsetApi.js", @@ -1281,7 +1293,7 @@ "ignore": true }, { - "__docId__": 104, + "__docId__": 105, "kind": "class", "name": "MapsetAPI", "memberof": "build/api/MapsetApi.js", @@ -1302,7 +1314,7 @@ ] }, { - "__docId__": 105, + "__docId__": 106, "kind": "constructor", "name": "constructor", "memberof": "build/api/MapsetApi.js~MapsetAPI", @@ -1373,7 +1385,7 @@ ] }, { - "__docId__": 106, + "__docId__": 107, "kind": "member", "name": "tags", "memberof": "build/api/MapsetApi.js~MapsetAPI", @@ -1390,7 +1402,7 @@ } }, { - "__docId__": 107, + "__docId__": 108, "kind": "member", "name": "tenants", "memberof": "build/api/MapsetApi.js~MapsetAPI", @@ -1407,7 +1419,7 @@ } }, { - "__docId__": 110, + "__docId__": 111, "kind": "method", "name": "getPlanById", "memberof": "build/api/MapsetApi.js~MapsetAPI", @@ -1450,7 +1462,7 @@ } }, { - "__docId__": 111, + "__docId__": 112, "kind": "method", "name": "getPlans", "memberof": "build/api/MapsetApi.js~MapsetAPI", @@ -1493,7 +1505,7 @@ } }, { - "__docId__": 112, + "__docId__": 113, "kind": "file", "name": "build/api/MocoAPI.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport HttpAPI from './HttpAPI';\n/**\n * This class provides convenience methods to use to the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n *\n * @example\n * import { MocoAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new MocoAPI({\n * // url: 'https://moco.geops.io/api/v2/',\n * // tenant: \"geopstest\",\n * });\n *\n * const notifications = await api.export();\n *\n * console.log('Log route:', JSON.stringify(notifications));\n *\n * @private\n */\nclass MocoAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {Object} options Options.\n *\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.url='https://moco.geops.io/api/v2/'] Service url.\n * @param {string} [options.tenant='geopstest'] SSO config to get notifications from.\n */\n constructor(options) {\n super(Object.assign(Object.assign({}, options), { url: options.url || 'https://moco.geops.io/api/v2/' }));\n this.tenant = 'geopstest';\n if (options.tenant) {\n this.tenant = options.tenant;\n }\n }\n /**\n * Get paginated situations.\n */\n export() {\n return __awaiter(this, arguments, void 0, function* (params = {}, config = {}) {\n const response = yield this.fetch(`${this.tenant}/export/`, Object.assign({}, params), config);\n return response;\n });\n }\n /**\n * Get a situation. Not all parameters are\n * relevant, only the text related are useful\n * (contentXXX, de, fr, it, en, includeXXX).\n */\n exportById(id_1) {\n return __awaiter(this, arguments, void 0, function* (id, params = {}, config = {}) {\n var _a, _b;\n const response = yield this.fetch(`${this.tenant}/export/${id}`, params, config);\n return (_b = (_a = response === null || response === void 0 ? void 0 : response.paginatedSituations) === null || _a === void 0 ? void 0 : _a.results) === null || _b === void 0 ? void 0 : _b[0];\n });\n }\n}\nexport default MocoAPI;\n", @@ -1504,7 +1516,7 @@ "lineNumber": 1 }, { - "__docId__": 113, + "__docId__": 114, "kind": "variable", "name": "__awaiter", "memberof": "build/api/MocoAPI.js", @@ -1525,7 +1537,7 @@ "ignore": true }, { - "__docId__": 114, + "__docId__": 115, "kind": "class", "name": "MocoAPI", "memberof": "build/api/MocoAPI.js", @@ -1546,7 +1558,7 @@ ] }, { - "__docId__": 115, + "__docId__": 116, "kind": "constructor", "name": "constructor", "memberof": "build/api/MocoAPI.js~MocoAPI", @@ -1605,7 +1617,7 @@ ] }, { - "__docId__": 116, + "__docId__": 117, "kind": "member", "name": "tenant", "memberof": "build/api/MocoAPI.js~MocoAPI", @@ -1622,7 +1634,7 @@ } }, { - "__docId__": 118, + "__docId__": 119, "kind": "method", "name": "export", "memberof": "build/api/MocoAPI.js~MocoAPI", @@ -1641,7 +1653,7 @@ } }, { - "__docId__": 119, + "__docId__": 120, "kind": "method", "name": "exportById", "memberof": "build/api/MocoAPI.js~MocoAPI", @@ -1667,10 +1679,10 @@ } }, { - "__docId__": 120, + "__docId__": 121, "kind": "file", "name": "build/api/RealtimeAPI.js", - "content": "import debounceWebsocketMessages from '../common/utils/debounceWebsocketMessages';\nimport getModeSuffix from '../common/utils/getRealtimeModeSuffix';\nimport WebSocketAPI from './WebSocketAPI';\n/**\n * Enum for Realtime modes.\n * @readonly\n * @typedef {string} RealtimeMode\n * @property {string} RAW \"raw\"\n * @property {string} SCHEMATIC \"schematic\"\n * @property {string} TOPOGRAPHIC \"topographic\"\n * @enum {RealtimeMode}\n * @public\n */\nexport const RealtimeModes = {\n RAW: 'raw',\n SCHEMATIC: 'schematic',\n TOPOGRAPHIC: 'topographic',\n};\n/**\n * This class provides convenience methods to use to the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { RealtimeAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new RealtimeAPI({\n * apiKey: \"yourApiKey\",\n * bbox: [782001, 5888803, 923410, 5923660, 11, \"mots=rail\"],\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n * // Open the websocket connection\n * api.open();\n *\n * // Subscribe to channel\n * api.subscribeTrajectory('topographic', (data) => {\n * console.log('Log trajectories:', JSON.stringify(data.content));\n * });\n *\n * // Close the websocket connection\n * api.close();\n *\n * @public\n */\nclass RealtimeAPI {\n /**\n * This callback type is called `requestCallback` and is displayed as a global symbol.\n *\n * @callback onFullTrajectoryMessageCallback\n * @param {number} responseCode\n * @param {string} responseMessage\n */\n /**\n * The bounding box to receive data from.\\\n * Example: [minX, minY, maxX, maxY, zoom, mots , gen_level, tenant, ...]\\\n *  \\\n * Where:\n * - **minX**: a string representation of an integer (not a float) representing the minimal X coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **minY**: a string representation of an integer (not a float) representing the minimal Y coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **maxX**: a string representation of an integer (not a float) representing the maximal X coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **maxY**: a string representation of an integer (not a float) representing the maximal Y coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **zoom**: a string representation of an integer representing the zoom level (from 4 to 22). When zoom < 8 only the trains are displayed for performance reasons.\\\n *  \n * - **mots**: A comma separated list of modes of transport. **Optional**.\\\n * Example: \"mots=rail,subway\".\\\n *  \n * - **gen_level**: An integer representing the generalization level. **Optional**.\\\n * Example: \"gen_level=5\"\\\n *  \n * - **tenant**: A string representing the tenant. **Optional**.\\\n * Example: \"tenant=sbb\"\\\n *  \n * - ...: Any other values added to the bbox will be send to the server\n *\n * @type {string[]}\n *\n * @public\n */\n get bbox() {\n return this._bbox;\n }\n set bbox(newBbox) {\n if (JSON.stringify(newBbox) !== JSON.stringify(this._bbox)) {\n this._bbox = newBbox;\n if (this.wsApi && this._bbox) {\n this.wsApi.send(`BBOX ${this._bbox.join(' ')}`);\n }\n }\n }\n get buffer() {\n return this._buffer;\n }\n set buffer(newBuffer) {\n if (JSON.stringify(newBuffer) !== JSON.stringify(this._buffer)) {\n this._buffer = newBuffer;\n if (this.wsApi && this._buffer) {\n this.wsApi.send(`BUFFER ${this._buffer.join(' ')}`);\n }\n }\n }\n get url() {\n return this._url;\n }\n set url(newUrl) {\n if (this._url !== newUrl) {\n this._url = newUrl;\n // Update the websocket only if the url has changed and the websocket is already open or is opening.\n if (this.wsApi.open || this.wsApi.connecting) {\n this.open();\n }\n }\n }\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {string[]} options.bbox The bounding box to receive data from.\n * @param {string} [options.url='wss://api.geops.io/tracker-ws/v1/'] Url of the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n * @public\n */\n constructor(options = {}) {\n this.version = '2';\n let opt = options;\n if (typeof options === 'string') {\n opt = { url: options };\n }\n const { apiKey } = opt;\n const { url } = opt;\n const wsApi = new WebSocketAPI();\n let suffix = '';\n if (apiKey && !(url === null || url === void 0 ? void 0 : url.includes('key='))) {\n suffix = `?key=${apiKey}`;\n }\n this._url = (url || 'wss://api.geops.io/tracker-ws/v1/') + suffix;\n this._buffer = opt.buffer || [100, 100];\n this._bbox = opt.bbox;\n this.version = opt.version || '2';\n /**\n * Interval between PING request in ms.\n * If equal to 0, no PING request are sent.\n * @type {number}\n */\n this.pingIntervalMs = opt.pingIntervalMs || 10000;\n /**\n * Timeout in ms after an automatic reconnection when the websoscket has been closed by the server.\n * @type {number}\n */\n this.reconnectTimeoutMs = opt.reconnectTimeoutMs || 100;\n /**\n * The websocket helper class to connect the websocket.\n */\n this.wsApi = wsApi;\n }\n /**\n * Close the websocket connection without reconnection.\n *\n * @public\n */\n close() {\n this.wsApi.close();\n }\n /**\n * Send GET to a channel.\n *\n * @param {string | WebSocketAPIParameters} channelOrParams Name of the websocket channel to send GET or an object representing parameters to send\n * @return {Promise>} A websocket response.\n * @public\n */\n get(channelOrParams) {\n let params = channelOrParams;\n if (typeof channelOrParams === 'string') {\n params = { channel: channelOrParams };\n }\n return new Promise((resolve, reject) => {\n this.wsApi.get(params, resolve, reject);\n });\n }\n /**\n * Get a full trajectory of a vehicule .\n *\n * @param {string} id A vehicle id.\n * @param {RealtimeMode} mode Realtime mode.\n * @param {string} generalizationLevel The generalization level to request. Can be one of 5 (more generalized), 10, 30, 100, undefined (less generalized).\n * @return {Promise<{data: { content: RealtimeFullTrajectory }}>} Return a full trajectory.\n * @public\n */\n getFullTrajectory(id, mode, generalizationLevel) {\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n const channel = [`full_trajectory${suffix}`];\n if (id) {\n channel.push(id);\n }\n if ((!mode || mode === RealtimeModes.TOPOGRAPHIC) && generalizationLevel) {\n channel.push(`gen${generalizationLevel}`);\n }\n return this.get(channel.join('_'));\n }\n /**\n * Return a station with a given uic number and a mode.\n *\n * @param {number} uic UIC of the station.\n * @param {RealtimeMode} mode Realtime mode.\n * @return {Promise<{data: { content: RealtimeStation }}>} A station.\n * @public\n */\n getStation(uic, mode) {\n const params = {\n args: uic,\n channel: `station${getModeSuffix(mode, RealtimeModes)}`,\n };\n return this.get(params);\n }\n /**\n * Get the list of ststions available for a specifc mode. The promise is resolved every 100ms\n * @param {RealtimeMode} mode Realtime mode.\n * @param {number} timeout = 100 Duration in ms between each promise resolve calls.\n * @return {Promise} An array of stations.\n * @public\n */\n getStations(mode, timeout = 100) {\n return new Promise((resolve, reject) => {\n this.get(`station${getModeSuffix(mode, RealtimeModes)}`)\n // @ts-expect-error check this\n .then(debounceWebsocketMessages(resolve, undefined, timeout))\n .catch(reject);\n });\n }\n /**\n * Get the list of stops for this vehicle.\n *\n * @param {string} id A vehicle id.\n * @return {Promise<{data: { content: RealtimeStopSequence[] }}>} Returns a stop sequence object.\n * @public\n */\n getStopSequence(id) {\n return this.get(`stopsequence_${id}`);\n }\n /**\n * Return a partial trajectory with a given id and a mode.\n *\n * @param {number} id The identifier of a trajectory.\n * @param {RealtimeMode} mode Realtime mode.\n * @return {Promise<{data: { content: RealtimeTrajectory }}>} A trajectory.\n * @public\n */\n getTrajectory(id, mode) {\n return this.get(`partial_trajectory${getModeSuffix(mode, RealtimeModes)}_${id}`);\n }\n /**\n * Callback when the websocket is closed by the server.\n * It auto reconnects after a timeout.\n * @private\n */\n onClose() {\n window.clearTimeout(this.pingInterval);\n window.clearTimeout(this.reconnectTimeout);\n if (this.reconnectTimeoutMs) {\n this.reconnectTimeout = window.setTimeout(() => {\n return this.open();\n }, this.reconnectTimeoutMs);\n }\n }\n /**\n * Callback when the websocket is opened and ready.\n * It applies the bbox and the projection.\n * @private\n */\n onOpen() {\n if (this.bbox) {\n this.wsApi.send(`BBOX ${this.bbox.join(' ')}`);\n }\n if (this.buffer) {\n this.wsApi.send(`BUFFER ${this.buffer.join(' ')}`);\n }\n /**\n * Keep websocket alive\n */\n if (this.pingIntervalMs) {\n window.clearInterval(this.pingInterval);\n this.pingInterval = window.setInterval(() => {\n this.wsApi.send('PING');\n }, this.pingIntervalMs);\n }\n }\n /**\n * Open the websocket connection.\n *\n * @public\n */\n open() {\n this.wsApi.connect(this.url, this.onOpen.bind(this));\n // Register reconnection on close.\n if (this.wsApi.websocket) {\n this.wsApi.websocket.onclose = () => {\n this.onClose();\n };\n }\n }\n /**\n * Unsubscribe trajectory and deleted_vehicles channels. To resubscribe you have to set a new BBOX.\n */\n reset() {\n this.wsApi.send('RESET');\n }\n /**\n * Subscribe to a channel.\n *\n * @param {string} channel Name of the websocket channel to subscribe.\n * @param {function} onSuccess Callback when the subscription succeeds.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribe(channel, onSuccess, onError = () => { }, quiet = false) {\n if (!channel || !onSuccess) {\n return;\n }\n this.wsApi.subscribe({ channel }, onSuccess, onError, quiet);\n }\n /**\n * Subscribe to deleted_vhicles channel.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeTrainId })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeDeletedVehicles(mode, onMessage, onError = () => { }, quiet = false) {\n this.unsubscribeDeletedVehicles(onMessage);\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`deleted_vehicles${suffix}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to departures channel of a given station.\n *\n * @param {number} stationId UIC of the station.\n * @param {function(departures: RealtimeDeparture[])} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @deprecated Use subscribeTimetable instead.\n */\n subscribeDepartures(stationId, onMessage, onError = () => { }, quiet = false) {\n this.subscribeTimetable(stationId, onMessage, onError, quiet);\n }\n /**\n * Subscribe to the disruptions channel for tenant.\n *\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {function(data: { content: RealtimeNews[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @deprecated Use subscribeNewsticker instead.\n */\n subscribeDisruptions(tenant, onMessage, onError = () => { }, quiet = false) {\n this.subscribeNewsticker(tenant, onMessage, onError, quiet);\n }\n /**\n * Subscribe to extra_geoms channel.\n *\n * @param {function(data: { content: RealtimeExtraGeom })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n */\n subscribeExtraGeoms(onMessage, onError = () => { }, quiet = false) {\n this.subscribe('extra_geoms', onMessage, onError, quiet);\n }\n /**\n * Subscribe to full_trajectory channel of a given vehicle.\n *\n * @param {string} id A vehicle id.\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data:{content: RealtimeFullTrajectory})} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeFullTrajectory(id, mode, onMessage, onError = () => { }, quiet = false) {\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`full_trajectory${suffix}_${id}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to healthcheck channel.\n * @param {function(data: { content: string })} onMessage Callback when the subscribe to healthcheck channel succeeds.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n */\n subscribeHealthCheck(onMessage, onError = () => { }, quiet = false) {\n this.subscribe('healthcheck', onMessage, onError, quiet);\n }\n /**\n * Subscribe to the newsticker channel for tenant.\n *\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {function(data: { content: RealtimeNews[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeNewsticker(tenant, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`${tenant}_newsticker`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to stations channel.\n * One message pro station.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeStation })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeStations(mode, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`station${getModeSuffix(mode, RealtimeModes)}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to stopsequence channel of a given vehicle.\n *\n * @param {string} id A vehicle id.\n * @param {function(data: { content: RealtimeStopSequence[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeStopSequence(id, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`stopsequence_${id}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to timetable channel of a given station.\n *\n * @param {number} stationId UIC of the station.\n * @param {function(departures: RealtimeDeparture[])} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeTimetable(stationId, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`timetable_${stationId}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to trajectory channel.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeTrajectory })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeTrajectory(mode, onMessage, onError = () => { }, quiet = false) {\n this.unsubscribeTrajectory(onMessage);\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`trajectory${suffix}`, onMessage, onError, quiet);\n }\n /**\n * Unsubscribe both modes of a channel.\n *\n * @param {string} channel Name of the websocket channel to unsubscribe.\n * @param {string} suffix Suffix to add to the channel name.\n * @param {function} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribe(channel, suffix = '', onMessage) {\n const suffixSchenatic = getModeSuffix(RealtimeModes.SCHEMATIC, RealtimeModes);\n const suffixTopographic = getModeSuffix(RealtimeModes.TOPOGRAPHIC, RealtimeModes);\n this.wsApi.unsubscribe(`${channel}${suffixSchenatic}${suffix || ''}`, onMessage);\n this.wsApi.unsubscribe(`${channel}${suffixTopographic}${suffix || ''}`, onMessage);\n }\n /**\n * Unsubscribe to deleted_vhicles channels.\n * @param {function(data: { content: RealtimeTrainId })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeDeletedVehicles(onMessage) {\n this.unsubscribe('deleted_vehicles', '', onMessage);\n }\n /**\n * Unsubscribe from current departures channel.\n * @param {number} stationId UIC of the station.\n * @param {function(data: { content: RealtimeDeparture[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @deprecated Use RealtimeAPI.unsubscribeTimetabe instead.\n */\n unsubscribeDepartures(stationId, onMessage) {\n this.unsubscribeTimetable(stationId, onMessage);\n }\n /**\n * Unsubscribe disruptions.\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {Function(data: { content: RealtimeNews[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @deprecated Use unsubscribeNewsticker instead.\n */\n unsubscribeDisruptions(tenant, onMessage) {\n this.unsubscribeNewsticker(tenant, onMessage);\n }\n /**\n * Unsubscribe to extra_geoms channel.\n * @param {function(data: { content: RealtimeExtraGeom })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n */\n unsubscribeExtraGeoms(onMessage) {\n this.unsubscribe('extra_geoms', '', onMessage);\n }\n /**\n * Unsubscribe from full_trajectory channel\n *\n * @param {string} id A vehicle id.\n * @param {onFullTrajectoryMessageCallback} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeFullTrajectory(id, onMessage) {\n this.unsubscribe('full_trajectory', `_${id}`, onMessage);\n }\n /**\n * Unsubscribe to healthcheck channel.\n * @param {function(data: { content: string })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n */\n unsubscribeHealthCheck(onMessage) {\n this.unsubscribe('healthcheck', '', onMessage);\n }\n /**\n * Unsubscribe disruptions.\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {Function(data: { content: RealtimeNews[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeNewsticker(tenant, onMessage) {\n this.unsubscribe(`${tenant}_newsticker`, '', onMessage);\n }\n /**\n * Unsubscribe to stations channel.\n * @param {function(data: { content: RealtimeStation })} onMessage The listener callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribe.\n * @public\n */\n unsubscribeStations(onMessage) {\n this.unsubscribe('station', '', onMessage);\n }\n /**\n * Unsubscribe from stopsequence channel\n *\n * @param {string} id A vehicle id.\n * @param {function(data: { content: RealtimeStopSequence[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeStopSequence(id, onMessage) {\n this.unsubscribe(`stopsequence`, `_${id}`, onMessage);\n }\n /**\n * Unsubscribe from current departures channel.\n * @param {number} stationId UIC of the station.\n * @param {function(data: { content: RealtimeDeparture[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeTimetable(stationId, onMessage) {\n this.unsubscribe(`timetable_${stationId}`, '', onMessage);\n }\n /**\n * Unsubscribe to trajectory channels.\n * @param {function(data: { content: RealtimeTrajectory })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeTrajectory(onMessage) {\n this.unsubscribe(`trajectory`, '', onMessage);\n }\n}\nexport default RealtimeAPI;\n", + "content": "import debounceWebsocketMessages from '../common/utils/debounceWebsocketMessages';\nimport getModeSuffix from '../common/utils/getRealtimeModeSuffix';\nimport WebSocketAPI from './WebSocketAPI';\n/**\n * Enum for Realtime modes.\n * @readonly\n * @typedef {string} RealtimeMode\n * @property {string} RAW \"raw\"\n * @property {string} SCHEMATIC \"schematic\"\n * @property {string} TOPOGRAPHIC \"topographic\"\n * @enum {RealtimeMode}\n * @public\n */\nexport const RealtimeModes = {\n RAW: 'raw',\n SCHEMATIC: 'schematic',\n TOPOGRAPHIC: 'topographic',\n};\n/**\n * This class provides convenience methods to use to the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { RealtimeAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new RealtimeAPI({\n * apiKey: \"yourApiKey\",\n * bbox: [782001, 5888803, 923410, 5923660, 11, \"mots=rail\"],\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n * // Open the websocket connection\n * api.open();\n *\n * // Subscribe to channel\n * api.subscribeTrajectory('topographic', (data) => {\n * console.log('Log trajectories:', JSON.stringify(data.content));\n * });\n *\n * // Close the websocket connection\n * api.close();\n *\n * @public\n */\nclass RealtimeAPI {\n /**\n * This callback type is called `requestCallback` and is displayed as a global symbol.\n *\n * @callback onFullTrajectoryMessageCallback\n * @param {number} responseCode\n * @param {string} responseMessage\n */\n /**\n * The bounding box to receive data from.\\\n * Example: [minX, minY, maxX, maxY, zoom, mots , gen_level, tenant, ...]\\\n *  \\\n * Where:\n * - **minX**: a string representation of an integer (not a float) representing the minimal X coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **minY**: a string representation of an integer (not a float) representing the minimal Y coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **maxX**: a string representation of an integer (not a float) representing the maximal X coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **maxY**: a string representation of an integer (not a float) representing the maximal Y coordinate (in EPSG:3857) of a bounding box\\\n *  \n * - **zoom**: a string representation of an integer representing the zoom level (from 4 to 22). When zoom < 8 only the trains are displayed for performance reasons.\\\n *  \n * - **mots**: A comma separated list of modes of transport. **Optional**.\\\n * Example: \"mots=rail,subway\".\\\n *  \n * - **gen_level**: An integer representing the generalization level. **Optional**.\\\n * Example: \"gen_level=5\"\\\n *  \n * - **tenant**: A string representing the tenant. **Optional**.\\\n * Example: \"tenant=sbb\"\\\n *  \n * - ...: Any other values added to the bbox will be send to the server\n *\n * @type {string[]}\n *\n * @public\n */\n get bbox() {\n return this._bbox;\n }\n set bbox(newBbox) {\n if (JSON.stringify(newBbox) !== JSON.stringify(this._bbox)) {\n this._bbox = newBbox;\n if (this.wsApi && this._bbox) {\n this.wsApi.send(`BBOX ${this._bbox.join(' ')}`);\n }\n }\n }\n get buffer() {\n return this._buffer;\n }\n set buffer(newBuffer) {\n if (JSON.stringify(newBuffer) !== JSON.stringify(this._buffer)) {\n this._buffer = newBuffer;\n if (this.wsApi && this._buffer) {\n this.wsApi.send(`BUFFER ${this._buffer.join(' ')}`);\n }\n }\n }\n get url() {\n return this._url;\n }\n set url(newUrl) {\n if (this._url !== newUrl) {\n this._url = newUrl;\n // Update the websocket only if the url has changed and the websocket is already open or is opening.\n if (this.wsApi.open || this.wsApi.connecting) {\n this.open();\n }\n }\n }\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {string[]} options.bbox The bounding box to receive data from.\n * @param {string} [options.url='wss://api.geops.io/tracker-ws/v1/'] Url of the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n * @public\n */\n constructor(options = {}) {\n this.version = '2';\n let opt = options;\n if (typeof options === 'string') {\n opt = { url: options };\n }\n const { apiKey } = opt;\n const { url } = opt;\n const wsApi = new WebSocketAPI();\n let suffix = '';\n if (apiKey && !(url === null || url === void 0 ? void 0 : url.includes('key='))) {\n suffix = `?key=${apiKey}`;\n }\n this._url = (url || 'wss://api.geops.io/tracker-ws/v1/') + suffix;\n this._buffer = opt.buffer || [100, 100];\n this._bbox = opt.bbox;\n this.version = opt.version || '2';\n /**\n * Interval between PING request in ms.\n * If equal to 0, no PING request are sent.\n * @type {number}\n */\n this.pingIntervalMs = opt.pingIntervalMs || 10000;\n /**\n * Timeout in ms after an automatic reconnection when the websoscket has been closed by the server.\n * @type {number}\n */\n this.reconnectTimeoutMs = opt.reconnectTimeoutMs || 100;\n /**\n * The websocket helper class to connect the websocket.\n */\n this.wsApi = wsApi;\n }\n /**\n * Close the websocket connection without reconnection.\n *\n * @public\n */\n close() {\n this.wsApi.close();\n }\n /**\n * Send GET to a channel.\n *\n * @param {string | WebSocketAPIParameters} channelOrParams Name of the websocket channel to send GET or an object representing parameters to send\n * @return {Promise>} A websocket response.\n * @public\n */\n get(channelOrParams) {\n let params = channelOrParams;\n if (typeof channelOrParams === 'string') {\n params = { channel: channelOrParams };\n }\n return new Promise((resolve, reject) => {\n this.wsApi.get(params, resolve, reject);\n });\n }\n /**\n * Get a full trajectory of a vehicule .\n *\n * @param {string} id A vehicle id.\n * @param {RealtimeMode} mode Realtime mode.\n * @param {string} generalizationLevel The generalization level to request. Can be one of 5 (more generalized), 10, 30, 100, undefined (less generalized).\n * @return {Promise<{data: { content: RealtimeFullTrajectoryCollection }}>} Return a full trajectory.\n * @public\n */\n getFullTrajectory(id, mode, generalizationLevel) {\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n const channel = [`full_trajectory${suffix}`];\n if (id) {\n channel.push(id);\n }\n if ((!mode || mode === RealtimeModes.TOPOGRAPHIC) && generalizationLevel) {\n channel.push(`gen${generalizationLevel}`);\n }\n return this.get(channel.join('_'));\n }\n /**\n * Return a station with a given uic number and a mode.\n *\n * @param {number} uic UIC of the station.\n * @param {RealtimeMode} mode Realtime mode.\n * @return {Promise<{data: { content: RealtimeStation }}>} A station.\n * @public\n */\n getStation(uic, mode) {\n const params = {\n args: uic,\n channel: `station${getModeSuffix(mode, RealtimeModes)}`,\n };\n return this.get(params);\n }\n /**\n * Get the list of ststions available for a specifc mode. The promise is resolved every 100ms\n * @param {RealtimeMode} mode Realtime mode.\n * @param {number} timeout = 100 Duration in ms between each promise resolve calls.\n * @return {Promise} An array of stations.\n * @public\n */\n getStations(mode, timeout = 100) {\n return new Promise((resolve, reject) => {\n this.get(`station${getModeSuffix(mode, RealtimeModes)}`)\n // @ts-expect-error check this\n .then(debounceWebsocketMessages(resolve, undefined, timeout))\n .catch(reject);\n });\n }\n /**\n * Get the list of stops for this vehicle.\n *\n * @param {string} id A vehicle id.\n * @return {Promise<{data: { content: RealtimeStopSequence[] }}>} Returns a stop sequence object.\n * @public\n */\n getStopSequence(id) {\n return this.get(`stopsequence_${id}`);\n }\n /**\n * Return a partial trajectory with a given id and a mode.\n *\n * @param {number} id The identifier of a trajectory.\n * @param {RealtimeMode} mode Realtime mode.\n * @return {Promise<{data: { content: RealtimeTrajectory }}>} A trajectory.\n * @public\n */\n getTrajectory(id, mode) {\n return this.get(`partial_trajectory${getModeSuffix(mode, RealtimeModes)}_${id}`);\n }\n /**\n * Callback when the websocket is closed by the server.\n * It auto reconnects after a timeout.\n * @private\n */\n onClose() {\n window.clearTimeout(this.pingInterval);\n window.clearTimeout(this.reconnectTimeout);\n if (this.reconnectTimeoutMs) {\n this.reconnectTimeout = window.setTimeout(() => {\n return this.open();\n }, this.reconnectTimeoutMs);\n }\n }\n /**\n * Callback when the websocket is opened and ready.\n * It applies the bbox and the projection.\n * @private\n */\n onOpen() {\n if (this.bbox) {\n this.wsApi.send(`BBOX ${this.bbox.join(' ')}`);\n }\n if (this.buffer) {\n this.wsApi.send(`BUFFER ${this.buffer.join(' ')}`);\n }\n /**\n * Keep websocket alive\n */\n if (this.pingIntervalMs) {\n window.clearInterval(this.pingInterval);\n this.pingInterval = window.setInterval(() => {\n this.wsApi.send('PING');\n }, this.pingIntervalMs);\n }\n }\n /**\n * Open the websocket connection.\n *\n * @public\n */\n open() {\n this.wsApi.connect(this.url, this.onOpen.bind(this));\n // Register reconnection on close.\n if (this.wsApi.websocket) {\n this.wsApi.websocket.onclose = () => {\n this.onClose();\n };\n }\n }\n /**\n * Unsubscribe trajectory and deleted_vehicles channels. To resubscribe you have to set a new BBOX.\n */\n reset() {\n this.wsApi.send('RESET');\n }\n /**\n * Subscribe to a channel.\n *\n * @param {string} channel Name of the websocket channel to subscribe.\n * @param {function} onSuccess Callback when the subscription succeeds.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribe(channel, onSuccess, onError = () => { }, quiet = false) {\n if (!channel || !onSuccess) {\n return;\n }\n this.wsApi.subscribe({ channel }, onSuccess, onError, quiet);\n }\n /**\n * Subscribe to deleted_vhicles channel.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeTrainId })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeDeletedVehicles(mode, onMessage, onError = () => { }, quiet = false) {\n this.unsubscribeDeletedVehicles(onMessage);\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`deleted_vehicles${suffix}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to departures channel of a given station.\n *\n * @param {number} stationId UIC of the station.\n * @param {function(departures: RealtimeDeparture[])} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @deprecated Use subscribeTimetable instead.\n */\n subscribeDepartures(stationId, onMessage, onError = () => { }, quiet = false) {\n this.subscribeTimetable(stationId, onMessage, onError, quiet);\n }\n /**\n * Subscribe to the disruptions channel for tenant.\n *\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {function(data: { content: RealtimeNews[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @deprecated Use subscribeNewsticker instead.\n */\n subscribeDisruptions(tenant, onMessage, onError = () => { }, quiet = false) {\n this.subscribeNewsticker(tenant, onMessage, onError, quiet);\n }\n /**\n * Subscribe to extra_geoms channel.\n *\n * @param {function(data: { content: RealtimeExtraGeom })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n */\n subscribeExtraGeoms(onMessage, onError = () => { }, quiet = false) {\n this.subscribe('extra_geoms', onMessage, onError, quiet);\n }\n /**\n * Subscribe to full_trajectory channel of a given vehicle.\n *\n * @param {string} id A vehicle id.\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data:{content: RealtimeFullTrajectoryCollection})} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeFullTrajectory(id, mode, onMessage, onError = () => { }, quiet = false) {\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`full_trajectory${suffix}_${id}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to healthcheck channel.\n * @param {function(data: { content: string })} onMessage Callback when the subscribe to healthcheck channel succeeds.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n */\n subscribeHealthCheck(onMessage, onError = () => { }, quiet = false) {\n this.subscribe('healthcheck', onMessage, onError, quiet);\n }\n /**\n * Subscribe to the newsticker channel for tenant.\n *\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {function(data: { content: RealtimeNews[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeNewsticker(tenant, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`${tenant}_newsticker`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to stations channel.\n * One message pro station.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeStation })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeStations(mode, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`station${getModeSuffix(mode, RealtimeModes)}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to stopsequence channel of a given vehicle.\n *\n * @param {string} id A vehicle id.\n * @param {function(data: { content: RealtimeStopSequence[] })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeStopSequence(id, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`stopsequence_${id}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to timetable channel of a given station.\n *\n * @param {number} stationId UIC of the station.\n * @param {function(departures: RealtimeDeparture[])} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeTimetable(stationId, onMessage, onError = () => { }, quiet = false) {\n this.subscribe(`timetable_${stationId}`, onMessage, onError, quiet);\n }\n /**\n * Subscribe to trajectory channel.\n *\n * @param {RealtimeMode} mode Realtime mode.\n * @param {function(data: { content: RealtimeTrajectory })} onMessage Function called on each message of the channel.\n * @param {function} onError Callback when the subscription fails.\n * @param {boolean} [quiet=false] If true avoid to store the subscription in the subscriptions list.\n * @public\n */\n subscribeTrajectory(mode, onMessage, onError = () => { }, quiet = false) {\n this.unsubscribeTrajectory(onMessage);\n let suffix = '';\n if (this.version === '1') {\n suffix = getModeSuffix(mode, RealtimeModes);\n }\n this.subscribe(`trajectory${suffix}`, onMessage, onError, quiet);\n }\n /**\n * Unsubscribe both modes of a channel.\n *\n * @param {string} channel Name of the websocket channel to unsubscribe.\n * @param {string} suffix Suffix to add to the channel name.\n * @param {function} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribe(channel, suffix = '', onMessage) {\n const suffixSchenatic = getModeSuffix(RealtimeModes.SCHEMATIC, RealtimeModes);\n const suffixTopographic = getModeSuffix(RealtimeModes.TOPOGRAPHIC, RealtimeModes);\n this.wsApi.unsubscribe(`${channel}${suffixSchenatic}${suffix || ''}`, onMessage);\n this.wsApi.unsubscribe(`${channel}${suffixTopographic}${suffix || ''}`, onMessage);\n }\n /**\n * Unsubscribe to deleted_vhicles channels.\n * @param {function(data: { content: RealtimeTrainId })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeDeletedVehicles(onMessage) {\n this.unsubscribe('deleted_vehicles', '', onMessage);\n }\n /**\n * Unsubscribe from current departures channel.\n * @param {number} stationId UIC of the station.\n * @param {function(data: { content: RealtimeDeparture[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @deprecated Use RealtimeAPI.unsubscribeTimetabe instead.\n */\n unsubscribeDepartures(stationId, onMessage) {\n this.unsubscribeTimetable(stationId, onMessage);\n }\n /**\n * Unsubscribe disruptions.\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {Function(data: { content: RealtimeNews[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @deprecated Use unsubscribeNewsticker instead.\n */\n unsubscribeDisruptions(tenant, onMessage) {\n this.unsubscribeNewsticker(tenant, onMessage);\n }\n /**\n * Unsubscribe to extra_geoms channel.\n * @param {function(data: { content: RealtimeExtraGeom })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n */\n unsubscribeExtraGeoms(onMessage) {\n this.unsubscribe('extra_geoms', '', onMessage);\n }\n /**\n * Unsubscribe from full_trajectory channel\n *\n * @param {string} id A vehicle id.\n * @param {onFullTrajectoryMessageCallback} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeFullTrajectory(id, onMessage) {\n this.unsubscribe('full_trajectory', `_${id}`, onMessage);\n }\n /**\n * Unsubscribe to healthcheck channel.\n * @param {function(data: { content: string })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n */\n unsubscribeHealthCheck(onMessage) {\n this.unsubscribe('healthcheck', '', onMessage);\n }\n /**\n * Unsubscribe disruptions.\n * @param {RealtimeTenant} tenant Tenant's id\n * @param {Function(data: { content: RealtimeNews[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeNewsticker(tenant, onMessage) {\n this.unsubscribe(`${tenant}_newsticker`, '', onMessage);\n }\n /**\n * Unsubscribe to stations channel.\n * @param {function(data: { content: RealtimeStation })} onMessage The listener callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribe.\n * @public\n */\n unsubscribeStations(onMessage) {\n this.unsubscribe('station', '', onMessage);\n }\n /**\n * Unsubscribe from stopsequence channel\n *\n * @param {string} id A vehicle id.\n * @param {function(data: { content: RealtimeStopSequence[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeStopSequence(id, onMessage) {\n this.unsubscribe(`stopsequence`, `_${id}`, onMessage);\n }\n /**\n * Unsubscribe from current departures channel.\n * @param {number} stationId UIC of the station.\n * @param {function(data: { content: RealtimeDeparture[] })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeTimetable(stationId, onMessage) {\n this.unsubscribe(`timetable_${stationId}`, '', onMessage);\n }\n /**\n * Unsubscribe to trajectory channels.\n * @param {function(data: { content: RealtimeTrajectory })} onMessage Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @public\n */\n unsubscribeTrajectory(onMessage) {\n this.unsubscribe(`trajectory`, '', onMessage);\n }\n}\nexport default RealtimeAPI;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/RealtimeAPI.js", "access": "private", @@ -1678,7 +1690,7 @@ "lineNumber": 1 }, { - "__docId__": 121, + "__docId__": 122, "kind": "typedef", "name": "RealtimeMode", "memberof": "build/api/RealtimeAPI.js", @@ -1738,7 +1750,7 @@ } }, { - "__docId__": 122, + "__docId__": 123, "kind": "class", "name": "RealtimeAPI", "memberof": "build/api/RealtimeAPI.js", @@ -1756,7 +1768,7 @@ "interface": false }, { - "__docId__": 123, + "__docId__": 124, "kind": "get", "name": "bbox", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1777,7 +1789,7 @@ } }, { - "__docId__": 124, + "__docId__": 125, "kind": "set", "name": "bbox", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1791,7 +1803,7 @@ "undocument": true }, { - "__docId__": 125, + "__docId__": 126, "kind": "member", "name": "_bbox", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1808,7 +1820,7 @@ } }, { - "__docId__": 126, + "__docId__": 127, "kind": "get", "name": "buffer", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1827,7 +1839,7 @@ } }, { - "__docId__": 127, + "__docId__": 128, "kind": "set", "name": "buffer", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1841,7 +1853,7 @@ "undocument": true }, { - "__docId__": 128, + "__docId__": 129, "kind": "member", "name": "_buffer", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1858,7 +1870,7 @@ } }, { - "__docId__": 129, + "__docId__": 130, "kind": "get", "name": "url", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1877,7 +1889,7 @@ } }, { - "__docId__": 130, + "__docId__": 131, "kind": "set", "name": "url", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1891,7 +1903,7 @@ "undocument": true }, { - "__docId__": 131, + "__docId__": 132, "kind": "member", "name": "_url", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1908,7 +1920,7 @@ } }, { - "__docId__": 132, + "__docId__": 133, "kind": "constructor", "name": "constructor", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1965,7 +1977,7 @@ ] }, { - "__docId__": 133, + "__docId__": 134, "kind": "member", "name": "version", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -1982,7 +1994,7 @@ } }, { - "__docId__": 138, + "__docId__": 139, "kind": "member", "name": "pingIntervalMs", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2001,7 +2013,7 @@ } }, { - "__docId__": 139, + "__docId__": 140, "kind": "member", "name": "reconnectTimeoutMs", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2020,7 +2032,7 @@ } }, { - "__docId__": 140, + "__docId__": 141, "kind": "member", "name": "wsApi", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2036,7 +2048,7 @@ } }, { - "__docId__": 141, + "__docId__": 142, "kind": "method", "name": "close", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2051,7 +2063,7 @@ "return": null }, { - "__docId__": 142, + "__docId__": 143, "kind": "method", "name": "get", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2085,7 +2097,7 @@ } }, { - "__docId__": 143, + "__docId__": 144, "kind": "method", "name": "getFullTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2131,14 +2143,14 @@ "return": { "nullable": null, "types": [ - "Promise<{data: { content: RealtimeFullTrajectory }}>" + "Promise<{data: { content: RealtimeFullTrajectoryCollection }}>" ], "spread": false, "description": "Return a full trajectory." } }, { - "__docId__": 144, + "__docId__": 145, "kind": "method", "name": "getStation", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2181,7 +2193,7 @@ } }, { - "__docId__": 145, + "__docId__": 146, "kind": "method", "name": "getStations", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2224,7 +2236,7 @@ } }, { - "__docId__": 146, + "__docId__": 147, "kind": "method", "name": "getStopSequence", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2257,7 +2269,7 @@ } }, { - "__docId__": 147, + "__docId__": 148, "kind": "method", "name": "getTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2300,7 +2312,7 @@ } }, { - "__docId__": 148, + "__docId__": 149, "kind": "method", "name": "onClose", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2315,7 +2327,7 @@ "return": null }, { - "__docId__": 149, + "__docId__": 150, "kind": "member", "name": "reconnectTimeout", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2332,7 +2344,7 @@ } }, { - "__docId__": 150, + "__docId__": 151, "kind": "method", "name": "onOpen", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2347,7 +2359,7 @@ "return": null }, { - "__docId__": 151, + "__docId__": 152, "kind": "member", "name": "pingInterval", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2364,7 +2376,7 @@ } }, { - "__docId__": 152, + "__docId__": 153, "kind": "method", "name": "open", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2379,7 +2391,7 @@ "return": null }, { - "__docId__": 153, + "__docId__": 154, "kind": "method", "name": "reset", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2394,7 +2406,7 @@ "return": null }, { - "__docId__": 154, + "__docId__": 155, "kind": "method", "name": "subscribe", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2452,7 +2464,7 @@ "return": null }, { - "__docId__": 155, + "__docId__": 156, "kind": "method", "name": "subscribeDeletedVehicles", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2510,7 +2522,7 @@ "return": null }, { - "__docId__": 156, + "__docId__": 157, "kind": "method", "name": "subscribeDepartures", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2569,7 +2581,7 @@ "return": null }, { - "__docId__": 157, + "__docId__": 158, "kind": "method", "name": "subscribeDisruptions", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2628,7 +2640,7 @@ "return": null }, { - "__docId__": 158, + "__docId__": 159, "kind": "method", "name": "subscribeExtraGeoms", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2676,7 +2688,7 @@ "return": null }, { - "__docId__": 159, + "__docId__": 160, "kind": "method", "name": "subscribeFullTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2711,7 +2723,7 @@ { "nullable": null, "types": [ - "function(data:{content: RealtimeFullTrajectory})" + "function(data:{content: RealtimeFullTrajectoryCollection})" ], "spread": false, "optional": false, @@ -2744,7 +2756,7 @@ "return": null }, { - "__docId__": 160, + "__docId__": 161, "kind": "method", "name": "subscribeHealthCheck", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2792,7 +2804,7 @@ "return": null }, { - "__docId__": 161, + "__docId__": 162, "kind": "method", "name": "subscribeNewsticker", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2850,7 +2862,7 @@ "return": null }, { - "__docId__": 162, + "__docId__": 163, "kind": "method", "name": "subscribeStations", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2908,7 +2920,7 @@ "return": null }, { - "__docId__": 163, + "__docId__": 164, "kind": "method", "name": "subscribeStopSequence", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -2966,7 +2978,7 @@ "return": null }, { - "__docId__": 164, + "__docId__": 165, "kind": "method", "name": "subscribeTimetable", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3024,7 +3036,7 @@ "return": null }, { - "__docId__": 165, + "__docId__": 166, "kind": "method", "name": "subscribeTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3082,7 +3094,7 @@ "return": null }, { - "__docId__": 166, + "__docId__": 167, "kind": "method", "name": "unsubscribe", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3128,7 +3140,7 @@ "return": null }, { - "__docId__": 167, + "__docId__": 168, "kind": "method", "name": "unsubscribeDeletedVehicles", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3154,7 +3166,7 @@ "return": null }, { - "__docId__": 168, + "__docId__": 169, "kind": "method", "name": "unsubscribeDepartures", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3191,7 +3203,7 @@ "return": null }, { - "__docId__": 169, + "__docId__": 170, "kind": "method", "name": "unsubscribeDisruptions", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3228,7 +3240,7 @@ "return": null }, { - "__docId__": 170, + "__docId__": 171, "kind": "method", "name": "unsubscribeExtraGeoms", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3254,7 +3266,7 @@ "return": null }, { - "__docId__": 171, + "__docId__": 172, "kind": "method", "name": "unsubscribeFullTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3290,7 +3302,7 @@ "return": null }, { - "__docId__": 172, + "__docId__": 173, "kind": "method", "name": "unsubscribeHealthCheck", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3316,7 +3328,7 @@ "return": null }, { - "__docId__": 173, + "__docId__": 174, "kind": "method", "name": "unsubscribeNewsticker", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3352,7 +3364,7 @@ "return": null }, { - "__docId__": 174, + "__docId__": 175, "kind": "method", "name": "unsubscribeStations", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3378,7 +3390,7 @@ "return": null }, { - "__docId__": 175, + "__docId__": 176, "kind": "method", "name": "unsubscribeStopSequence", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3414,7 +3426,7 @@ "return": null }, { - "__docId__": 176, + "__docId__": 177, "kind": "method", "name": "unsubscribeTimetable", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3450,7 +3462,7 @@ "return": null }, { - "__docId__": 177, + "__docId__": 178, "kind": "method", "name": "unsubscribeTrajectory", "memberof": "build/api/RealtimeAPI.js~RealtimeAPI", @@ -3465,18 +3477,221 @@ { "nullable": null, "types": [ - "function(data: { content: RealtimeTrajectory })" - ], - "spread": false, - "optional": false, - "name": "onMessage", - "description": "Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed." + "function(data: { content: RealtimeTrajectory })" + ], + "spread": false, + "optional": false, + "name": "onMessage", + "description": "Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed." + } + ], + "return": null + }, + { + "__docId__": 179, + "kind": "file", + "name": "build/api/RealtimeRestAPI.js", + "content": "import HttpAPI from './HttpAPI';\n/**\n * This class provides convenience methods to use to the [geOps Realtime REST API](https://developer.geops.io/apis/realtime/).\n * For the websocket see {@link RealtimeAPI}.\n *\n * @example\n * import { RealtimeRestAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new RealtimeRestAPI({\n * apiKey: [yourApiKey],\n * tenant: 'trenord',\n * // url: 'https://api.geops.io/tracker-http/v1/',\n * });\n *\n * const feeds = await api.feeds();\n *\n * console.log('Log feeds:', JSON.stringify(feeds));\n *\n */\nclass RealtimeRestAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {string} [options.url='https://api.geops.io/tracker-http/v1/'] Url of the [geOps stops API](https://developer.geops.io/apis/realtime/).\n */\n constructor(options = {}) {\n super(Object.assign(Object.assign({}, options), { url: options.url || 'https://api.geops.io/tracker-http/v1/' }));\n if (options.tenant) {\n this.tenant = options.tenant;\n }\n }\n /**\n * Get list of feeds.\n */\n feeds(params = {}, config) {\n return this.fetch('feeds/', params, config);\n }\n /**\n * Search for trains by route identifier.\n */\n trainsByRouteIdentifier(params = {\n exact_match: true,\n }, config) {\n return this.fetch(`trains_by_route_identifier/${this.tenant}/`, params, config);\n }\n /**\n * Get trajectories for a tenant.\n */\n trajectories(params = {}, config) {\n return this.fetch(`trajectories/${this.tenant}/`, params, config);\n }\n}\nexport default RealtimeRestAPI;\n", + "static": true, + "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/RealtimeRestAPI.js", + "access": "private", + "description": null, + "lineNumber": 1 + }, + { + "__docId__": 180, + "kind": "class", + "name": "RealtimeRestAPI", + "memberof": "build/api/RealtimeRestAPI.js", + "static": true, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "access": "private", + "export": true, + "importPath": "mobility-toolbox-js/build/api/RealtimeRestAPI.js", + "importStyle": "RealtimeRestAPI", + "description": "This class provides convenience methods to use to the [geOps Realtime REST API](https://developer.geops.io/apis/realtime/).\nFor the websocket see {@link RealtimeAPI}.", + "examples": [ + "import { RealtimeRestAPI } from 'mobility-toolbox-js/api';\n\nconst api = new RealtimeRestAPI({\n apiKey: [yourApiKey],\n tenant: 'trenord',\n // url: 'https://api.geops.io/tracker-http/v1/',\n});\n\nconst feeds = await api.feeds();\n\nconsole.log('Log feeds:', JSON.stringify(feeds));" + ], + "lineNumber": 20, + "interface": false, + "extends": [ + "build/api/HttpAPI.js~HttpAPI" + ] + }, + { + "__docId__": 181, + "kind": "constructor", + "name": "constructor", + "memberof": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "generator": false, + "async": false, + "static": false, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI#constructor", + "access": "private", + "description": "Constructor", + "lineNumber": 28, + "params": [ + { + "nullable": null, + "types": [ + "Object" + ], + "spread": false, + "optional": false, + "name": "options", + "description": "Options." + }, + { + "nullable": null, + "types": [ + "string" + ], + "spread": false, + "optional": false, + "name": "options.apiKey", + "description": "Access key for [geOps apis](https://developer.geops.io/)." + }, + { + "nullable": null, + "types": [ + "string" + ], + "spread": false, + "optional": true, + "defaultValue": "'https://api.geops.io/tracker-http/v1/'", + "defaultRaw": "'https://api.geops.io/tracker-http/v1/'", + "name": "options.url", + "description": "Url of the [geOps stops API](https://developer.geops.io/apis/realtime/)." + } + ] + }, + { + "__docId__": 182, + "kind": "member", + "name": "tenant", + "memberof": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "static": false, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI#tenant", + "access": "private", + "description": null, + "lineNumber": 31, + "undocument": true, + "type": { + "types": [ + "*" + ] + } + }, + { + "__docId__": 183, + "kind": "method", + "name": "feeds", + "memberof": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "generator": false, + "async": false, + "static": false, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI#feeds", + "access": "private", + "description": "Get list of feeds.", + "lineNumber": 37, + "params": [ + { + "name": "params", + "optional": true, + "types": [ + "{}" + ], + "defaultRaw": {}, + "defaultValue": "{}" + }, + { + "name": "config", + "types": [ + "*" + ] + } + ], + "return": { + "types": [ + "*" + ] + } + }, + { + "__docId__": 184, + "kind": "method", + "name": "trainsByRouteIdentifier", + "memberof": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "generator": false, + "async": false, + "static": false, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI#trainsByRouteIdentifier", + "access": "private", + "description": "Search for trains by route identifier.", + "lineNumber": 43, + "params": [ + { + "name": "params", + "optional": true, + "types": [ + "{\"exact_match\": boolean}" + ], + "defaultRaw": { + "exact_match": true + }, + "defaultValue": "{\"exact_match\":true}" + }, + { + "name": "config", + "types": [ + "*" + ] + } + ], + "return": { + "types": [ + "*" + ] + } + }, + { + "__docId__": 185, + "kind": "method", + "name": "trajectories", + "memberof": "build/api/RealtimeRestAPI.js~RealtimeRestAPI", + "generator": false, + "async": false, + "static": false, + "longname": "build/api/RealtimeRestAPI.js~RealtimeRestAPI#trajectories", + "access": "private", + "description": "Get trajectories for a tenant.", + "lineNumber": 51, + "params": [ + { + "name": "params", + "optional": true, + "types": [ + "{}" + ], + "defaultRaw": {}, + "defaultValue": "{}" + }, + { + "name": "config", + "types": [ + "*" + ] } ], - "return": null + "return": { + "types": [ + "*" + ] + } }, { - "__docId__": 178, + "__docId__": 186, "kind": "file", "name": "build/api/RoutingAPI.js", "content": "import HttpAPI from './HttpAPI';\n/**\n * This class provides convenience methods to use to the [geOps Routing API](https://developer.geops.io/apis/routing).\n *\n * @example\n * import { RoutingAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new RoutingAPI({\n * apiKey: [yourApiKey],\n * // url: 'https://api.geops.io/routing/v1/',\n * });\n *\n * const route = await api.route({\n * via: \"freiburg|basel%20sbb|bern\",\n * mot: \"rail\"\n * });\n *\n * console.log('Log route:', JSON.stringify(route));\n *\n * @public\n */\nclass RoutingAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).\n * @param {string} [options.url='https://api.geops.io/routing/v1/'] Service url.\n * @public\n */\n constructor(options = {}) {\n super(Object.assign({ url: 'https://api.geops.io/routing/v1/' }, options));\n }\n /**\n * Calculate a route.\n *\n * @param {RoutingParameters} params Request parameters. See [geOps Routing API](https://developer.geops.io/apis/routing/).\n * @param {FetchOptions} config Options for the fetch request.\n * @return {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).\n * @public\n */\n route(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default RoutingAPI;\n", @@ -3487,7 +3702,7 @@ "lineNumber": 1 }, { - "__docId__": 179, + "__docId__": 187, "kind": "class", "name": "RoutingAPI", "memberof": "build/api/RoutingAPI.js", @@ -3508,7 +3723,7 @@ ] }, { - "__docId__": 180, + "__docId__": 188, "kind": "constructor", "name": "constructor", "memberof": "build/api/RoutingAPI.js~RoutingAPI", @@ -3555,7 +3770,7 @@ ] }, { - "__docId__": 181, + "__docId__": 189, "kind": "method", "name": "route", "memberof": "build/api/RoutingAPI.js~RoutingAPI", @@ -3598,7 +3813,7 @@ } }, { - "__docId__": 182, + "__docId__": 190, "kind": "file", "name": "build/api/StopsAPI.js", "content": "import HttpAPI from './HttpAPI';\n/**\n * This class provides convenience methods to use to the [geOps Stops API](https://developer.geops.io/apis/stops/).\n *\n * @example\n * import { StopsAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new StopsAPI({\n * apiKey: [yourApiKey],\n * // url: 'https://api.geops.io/stops/v1/',\n * });\n *\n * const stops = await api.search({ q:\"Bern\" });\n *\n * console.log('Log stops:', JSON.stringify(stops));\n *\n * @public\n */\nclass StopsAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {Object} options Options.\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] Url of the [geOps stops API](https://developer.geops.io/apis/stops/).\n * @public\n */\n constructor(options = {}) {\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n super(Object.assign(Object.assign({}, options), { url: options.url || 'https://api.geops.io/stops/v1/' }));\n }\n /**\n * Search for stops.\n *\n * @param {StopsParameters} params Request parameters. See [Stops API documentation](https://developer.geops.io/apis/stops).\n * @param {FetchOptions} config Options for the fetch request.\n * @returns {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326). See [Stops API documentation](https://developer.geops.io/apis/stops).\n * @public\n */\n search(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default StopsAPI;\n", @@ -3609,7 +3824,7 @@ "lineNumber": 1 }, { - "__docId__": 183, + "__docId__": 191, "kind": "class", "name": "StopsAPI", "memberof": "build/api/StopsAPI.js", @@ -3630,7 +3845,7 @@ ] }, { - "__docId__": 184, + "__docId__": 192, "kind": "constructor", "name": "constructor", "memberof": "build/api/StopsAPI.js~StopsAPI", @@ -3677,7 +3892,7 @@ ] }, { - "__docId__": 185, + "__docId__": 193, "kind": "method", "name": "search", "memberof": "build/api/StopsAPI.js~StopsAPI", @@ -3726,7 +3941,7 @@ } }, { - "__docId__": 186, + "__docId__": 194, "kind": "file", "name": "build/api/WebSocketAPI.js", "content": "/**\n * Class used to facilitate connection to a WebSocketAPI and\n * also to manage properly messages send to the WebSocketAPI.\n * This class must not contain any specific implementation.\n * @private\n */\nclass WebSocketAPI {\n constructor() {\n this.defineProperties();\n }\n /**\n * Get the websocket request string.\n *\n * @param {string} method Request mehtod {GET, SUB}.\n * @param {WebSocketParameters} params Request parameters.\n * @param {string} params.channel Channel name\n * @param {string} [params.args] Request arguments\n * @param {Number|string} [params.id] Request identifier\n * @return {string} request string\n * @private\n */\n static getRequestString(method, params = {}) {\n let reqStr = `${method} ${params.channel}`;\n reqStr += params.args ? ` ${params.args}` : '';\n reqStr += params.id ? ` ${params.id}` : '';\n return reqStr.trim();\n }\n addEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.addEventListener('message', onMessage);\n if (onError) {\n this.websocket.addEventListener('error', onError);\n this.websocket.addEventListener('close', onError);\n }\n }\n }\n /**\n * Close the websocket definitively.\n *\n * @private\n */\n close() {\n if (this.websocket && (this.open || this.connecting)) {\n this.websocket.onclose = () => { };\n this.websocket.close();\n this.messagesOnOpen = [];\n }\n }\n /**\n * (Re)connect the websocket.\n *\n * @param {string} url Websocket url.\n * @param {function} onOpen Callback called when the websocket connection is opened and before subscriptions of previous subscriptions.\n * @private\n */\n connect(url, onOpen = () => { }) {\n var _a;\n // if no url specify, close the current websocket and do nothing.\n if (!url) {\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();\n return;\n }\n // Behavior when a websocket already exists.\n if (this.websocket) {\n // If the current websocket has the same url and is open or is connecting, do nothing.\n if (this.websocket.url === url && (this.open || this.connecting)) {\n return;\n }\n // If the current websocket has not the same url and is open or is connecting, close it.\n if (this.websocket.url !== url && (this.open || this.connecting)) {\n this.websocket.close();\n }\n }\n this.websocket = new WebSocket(url);\n if (!this.open) {\n this.websocket.addEventListener('open', () => {\n onOpen();\n this.subscribePreviousSubscriptions();\n });\n }\n else {\n onOpen();\n this.subscribePreviousSubscriptions();\n }\n }\n defineProperties() {\n Object.defineProperties(this, {\n closed: {\n get: () => {\n return !!(!this.websocket ||\n this.websocket.readyState === this.websocket.CLOSED);\n },\n },\n closing: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CLOSING);\n },\n },\n connecting: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CONNECTING);\n },\n },\n /**\n * Array of message to send on open.\n * @type {Array}\n * @private\n */\n messagesOnOpen: {\n value: [],\n writable: true,\n },\n open: {\n get: () => {\n return !!(this.websocket && this.websocket.readyState === this.websocket.OPEN);\n },\n },\n /**\n * List of channels subscribed.\n * @type {WebSocketSubscribed}\n * @private\n */\n subscribed: {\n value: {},\n writable: true,\n },\n /**\n * Array of subscriptions.\n * @type {Array}\n * @private\n */\n subscriptions: {\n value: [],\n writable: true,\n },\n });\n }\n /**\n * Sends a get request to the websocket.\n * The callback is called only once, when the response is received or when the call returns an error.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on message event\n * @param {function} errorCb Callback on error and close event\n * @private\n */\n get(params, cb, errorCb) {\n const requestString = WebSocketAPI.getRequestString('GET', params);\n this.send(requestString);\n // We wrap the callbacks to make sure they are called only once.\n const once = (callback) => {\n return (...args) => {\n // @ts-expect-error - We know that args is an array\n callback(...args);\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n const { onErrorCb, onMessageCb } = this.requests[index];\n this.removeEvents(onMessageCb, onErrorCb);\n this.requests.splice(index, 1);\n };\n };\n const { onErrorCb, onMessageCb } = this.listen(params, once(cb), errorCb && once(errorCb));\n // Store requests and callbacks to be able to remove them.\n if (!this.requests) {\n this.requests = [];\n }\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n const newReq = {\n cb,\n errorCb,\n onErrorCb,\n onMessageCb,\n params,\n requestString,\n };\n if (index > -1) {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests[index] = newReq;\n }\n else {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests.push(newReq);\n }\n }\n /**\n * Listen to websocket messages.\n *\n * @param {WebSocketParameters} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @return {{onMessage: function, errorCb: function}} Object with onMessage and error callbacks\n * @private\n */\n listen(params, cb, errorCb) {\n // Remove the previous identical callback\n this.unlisten(params, cb);\n // We wrap the message callback to be sure we only propagate the message if it is for the right channel.\n const onMessage = (evt) => {\n let data;\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data = JSON.parse(evt.data);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('WebSocket: unable to parse JSON data', err, evt.data);\n return;\n }\n let source = params.channel;\n source += params.args ? ` ${params.args}` : '';\n // Buffer channel message return a list of other channels to propagate to proper callbacks.\n let contents;\n if (data.source === 'buffer') {\n // @ts-expect-error - We know that the data is a WebSocketAPIBufferMessageEventData\n contents = data\n .content;\n }\n else {\n contents = [data];\n }\n contents.forEach((content) => {\n // Because of backend optimization, the last content is null.\n if ((content === null || content === void 0 ? void 0 : content.source) === source &&\n (!params.id || params.id === data.client_reference)) {\n cb(content);\n }\n });\n };\n this.addEvents(onMessage, errorCb);\n return { onErrorCb: errorCb, onMessageCb: onMessage };\n }\n removeEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.removeEventListener('message', onMessage);\n if (onError) {\n this.websocket.removeEventListener('error', onError);\n this.websocket.removeEventListener('close', onError);\n }\n }\n }\n /**\n * Sends a message to the websocket.\n *\n * @param {message} message Message to send.\n * @private\n */\n send(message) {\n if (!this.websocket || this.closed || this.closing) {\n return;\n }\n const send = () => {\n var _a;\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.send(message);\n };\n if (!this.open) {\n // This 'if' avoid sending 2 identical BBOX message on open,\n if (!this.messagesOnOpen.includes(message)) {\n this.messagesOnOpen.push(message);\n this.websocket.addEventListener('open', () => {\n this.messagesOnOpen = [];\n send();\n });\n this.websocket.addEventListener('close', () => {\n this.messagesOnOpen = [];\n });\n }\n }\n else if (!this.messagesOnOpen.includes(message)) {\n send();\n }\n }\n /**\n * Subscribe to a given channel.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @param {boolean} quiet if false, no GET or SUB requests are send, only the callback is registered.\n * @private\n */\n subscribe(params, cb, errorCb, quiet = false) {\n const { onErrorCb, onMessageCb } = this.listen(params, cb, errorCb);\n const reqStr = WebSocketAPI.getRequestString('', params);\n const index = this.subscriptions.findIndex((subcr) => {\n return params.channel === subcr.params.channel && cb === subcr.cb;\n });\n const newSubscr = { cb, errorCb, onErrorCb, onMessageCb, params, quiet };\n if (index > -1) {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions[index] = newSubscr;\n }\n else {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions.push(newSubscr);\n }\n if (!this.subscribed[reqStr]) {\n if (!newSubscr.quiet) {\n this.send(`GET ${reqStr}`);\n this.send(`SUB ${reqStr}`);\n }\n this.subscribed[reqStr] = true;\n }\n }\n /**\n * After an auto reconnection we need to re-subscribe to the channels.\n */\n subscribePreviousSubscriptions() {\n // Before to subscribe previous subscriptions we make sure they\n // are all defined as unsubscribed, because this code is asynchrone\n // and a subscription could have been added in between.\n Object.keys(this.subscribed).forEach((key) => {\n this.subscribed[key] = false;\n });\n // Subscribe all previous subscriptions.\n [...this.subscriptions].forEach((s) => {\n this.subscribe(s.params, s.cb, s.errorCb, s.quiet);\n });\n }\n /**\n * Unlisten websocket messages.\n *\n * @param {Object} params Parameters for the websocket get request.\n * @param {function} cb Callback used when listen.\n * @private\n */\n unlisten(params, cb) {\n [...(this.subscriptions || []), ...(this.requests || [])]\n .filter((s) => {\n return s.params.channel === params.channel && (!cb || s.cb === cb);\n })\n .forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n }\n /**\n * Unsubscribe from a channel.\n * @param {string} source source to unsubscribe from\n * @param {function} cb Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @private\n */\n unsubscribe(source, cb) {\n const toRemove = this.subscriptions.filter((s) => {\n return s.params.channel === source && (!cb || s.cb === cb);\n });\n toRemove.forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n this.subscriptions = this.subscriptions.filter((s) => {\n return s.params.channel !== source || (cb && s.cb !== cb);\n });\n // If there is no more subscriptions to this channel, and the removed subscriptions didn't register quietly,\n // we DEL it.\n if (source &&\n this.subscribed[source] &&\n !this.subscriptions.find((s) => {\n return s.params.channel === source;\n }) &&\n toRemove.find((subscr) => {\n return !subscr.quiet;\n })) {\n this.send(`DEL ${source}`);\n this.subscribed[source] = false;\n }\n }\n}\nexport default WebSocketAPI;\n", @@ -3737,7 +3952,7 @@ "lineNumber": 1 }, { - "__docId__": 187, + "__docId__": 195, "kind": "class", "name": "WebSocketAPI", "memberof": "build/api/WebSocketAPI.js", @@ -3752,7 +3967,7 @@ "interface": false }, { - "__docId__": 188, + "__docId__": 196, "kind": "constructor", "name": "constructor", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3766,7 +3981,7 @@ "undocument": true }, { - "__docId__": 189, + "__docId__": 197, "kind": "method", "name": "getRequestString", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3840,7 +4055,7 @@ } }, { - "__docId__": 190, + "__docId__": 198, "kind": "method", "name": "addEvents", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3869,7 +4084,7 @@ "return": null }, { - "__docId__": 191, + "__docId__": 199, "kind": "method", "name": "close", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3884,7 +4099,7 @@ "return": null }, { - "__docId__": 192, + "__docId__": 200, "kind": "member", "name": "messagesOnOpen", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3901,7 +4116,7 @@ } }, { - "__docId__": 193, + "__docId__": 201, "kind": "method", "name": "connect", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3937,7 +4152,7 @@ "return": null }, { - "__docId__": 194, + "__docId__": 202, "kind": "member", "name": "websocket", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3954,7 +4169,7 @@ } }, { - "__docId__": 195, + "__docId__": 203, "kind": "method", "name": "defineProperties", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -3970,7 +4185,7 @@ "return": null }, { - "__docId__": 196, + "__docId__": 204, "kind": "method", "name": "get", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4016,7 +4231,7 @@ "return": null }, { - "__docId__": 197, + "__docId__": 205, "kind": "member", "name": "requests", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4033,7 +4248,7 @@ } }, { - "__docId__": 198, + "__docId__": 206, "kind": "method", "name": "listen", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4086,7 +4301,7 @@ } }, { - "__docId__": 199, + "__docId__": 207, "kind": "method", "name": "removeEvents", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4115,7 +4330,7 @@ "return": null }, { - "__docId__": 200, + "__docId__": 208, "kind": "method", "name": "send", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4141,7 +4356,7 @@ "return": null }, { - "__docId__": 203, + "__docId__": 211, "kind": "method", "name": "subscribe", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4197,7 +4412,7 @@ "return": null }, { - "__docId__": 204, + "__docId__": 212, "kind": "method", "name": "subscribePreviousSubscriptions", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4212,7 +4427,7 @@ "return": null }, { - "__docId__": 205, + "__docId__": 213, "kind": "method", "name": "unlisten", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4248,7 +4463,7 @@ "return": null }, { - "__docId__": 206, + "__docId__": 214, "kind": "method", "name": "unsubscribe", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4284,7 +4499,7 @@ "return": null }, { - "__docId__": 207, + "__docId__": 215, "kind": "member", "name": "subscriptions", "memberof": "build/api/WebSocketAPI.js~WebSocketAPI", @@ -4301,10 +4516,10 @@ } }, { - "__docId__": 208, + "__docId__": 216, "kind": "file", "name": "build/api/index.js", - "content": "export { default as MapsetAPI } from './MapsetApi';\nexport { default as MocoAPI } from './MocoAPI';\nexport { default as RealtimeAPI, RealtimeModes } from './RealtimeAPI';\nexport { default as RoutingAPI } from './RoutingAPI';\nexport { default as StopsAPI } from './StopsAPI';\n", + "content": "export { default as MapsetAPI } from './MapsetApi';\nexport { default as MocoAPI } from './MocoAPI';\nexport { default as RealtimeAPI, RealtimeModes } from './RealtimeAPI';\nexport { default as RealtimeRestAPI } from './RealtimeRestAPI';\nexport { default as RoutingAPI } from './RoutingAPI';\nexport { default as StopsAPI } from './StopsAPI';\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/index.js", "access": "private", @@ -4312,7 +4527,7 @@ "lineNumber": 1 }, { - "__docId__": 209, + "__docId__": 217, "kind": "file", "name": "build/api/typedefs.js", "content": "// /**\n// * @typedef {Object} Departure\n// * @property {number} time Timestamp in ms.\n// * @property {boolean} no_stop_between\n// * @property {number} train_number\n// * @property {string[]} to\n// * @property {number} ris_aimed_time Timestamp in ms.\n// * @property {number} updated_at Timestamp in ms.\n// * @property {boolean} new_to\n// * @property {number} min_arrival_time Timestamp in ms.\n// * @property {string[]} next_stoppoints List of next stops. Like value in at_station_ds100.\n// * @property {number} ris_estimated_time Timestamp in ms.\n// * @property {NetworkLine} line\n// * @property {boolean} has_fzo if true this departure has realtime data.\n// * @property {number} train_id\n// * @property {string} platform\n// * @property {?*} state\n// * @property {number} fzo_estimated_time Timestamp in ms.\n// * @property {?*} formation\n// * @property {?*} no_stop_till\n// * @property {number} train_type\n// * @property {number} call_id\n// * @property {string} created_at Timestamp in ms.\n// * @property {string} at_station_ds100\n// * @property {number} timediff Timestamp in ms.\n// *\n// */\n/**\n * @typedef {GeoJSONFeature} Station\n * @property {StationProperties} properties Returns the station's properties.\n * @property {GeoJSONPoint} geometry Returns a point.\n */\n/**\n * @typedef {Object} StationProperties\n * @property {Transfer[]} transfers\n * @property {boolean} elevatorOutOfOrder\n * @property {number} uic\n * @property {string} name\n * @property {NetworkLine[]} networkLines\n * @property {boolean} hasElevator\n * @property {boolean} hasZOB\n * @property {boolean} hasAccessibility\n * @property {string} type\n */\n/**\n * @typedef {Object} NetworkLine\n * @property {number} id Identifier of the line.\n * @property {string} color Color of the line (CSS color string).\n * @property {string} stroke Stroke color of the line (CSS color string).\n * @property {string} name Name of the line.\n * @property {string} text_color Text color of the line (CSS color string).\n */\n/**\n * @typedef {Object} Transfer\n * @property {string} mot Mode of transportation (ex: U-Bahn).\n * @property {string[]} lines Array of lines name (ex: [\"U4\", \"U5\"]).\n */\n// These lines is to block TypeScript to add \"use strict;\" in the outputed file.\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst dummy = () => { };\nexport default dummy;\n", @@ -4323,7 +4538,7 @@ "lineNumber": 1 }, { - "__docId__": 210, + "__docId__": 218, "kind": "typedef", "name": "Station", "memberof": "build/api/typedefs.js", @@ -4362,7 +4577,7 @@ } }, { - "__docId__": 211, + "__docId__": 219, "kind": "typedef", "name": "StationProperties", "memberof": "build/api/typedefs.js", @@ -4471,7 +4686,7 @@ } }, { - "__docId__": 212, + "__docId__": 220, "kind": "typedef", "name": "NetworkLine", "memberof": "build/api/typedefs.js", @@ -4540,7 +4755,7 @@ } }, { - "__docId__": 213, + "__docId__": 221, "kind": "typedef", "name": "Transfer", "memberof": "build/api/typedefs.js", @@ -4580,7 +4795,7 @@ } }, { - "__docId__": 214, + "__docId__": 222, "kind": "file", "name": "build/common/controls/StopFinderControlCommon.js", "content": "import { StopsAPI } from '../../api';\n/**\n * A class representing a stop finder control to display on map.\n * This class only draw the html elements.\n * The geographic logic must be implemented by subclasses.\n *\n * @private\n */\nclass StopFinderControlCommon {\n /**\n * Constructor.\n *\n * @param {Object} options Options\n * @param {HTMLElement} options.element HTML element where to attach input and suggestions.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/). See StopsAPI.\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] Stops service url. See StopsAPI.\n * @param {string} [options.placeholder='Search for a stop...'] Input field placeholder.\n * @param {StopsSearchParams} [options.apiParams={ limit: 20 }] Request parameters. See [Stops service documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).\n */\n constructor(options) {\n const { apiKey, apiParams, placeholder, url } = options || {};\n this.apiParams = Object.assign({ limit: 20 }, (apiParams || {}));\n this.placeholder = placeholder || 'Search for a stop...';\n const apiOptions = { apiKey };\n if (url) {\n apiOptions.url = url;\n }\n this.api = new StopsAPI(apiOptions);\n this.abortController = new AbortController();\n this.createElement(options);\n this.options = options;\n }\n /**\n * Clear the search field and close the control.\n */\n clear() {\n if (!this.suggestionsElt || !this.inputElt || !this.clearElt) {\n return;\n }\n this.inputElt.value = '';\n this.suggestionsElt.innerHTML = '';\n this.clearElt.style.display = 'none';\n }\n createElement({ element }) {\n // Create input element\n this.inputElt = document.createElement('input');\n this.inputElt.type = 'text';\n this.inputElt.placeholder = this.placeholder;\n this.inputElt.autocomplete = 'off';\n this.inputElt.onkeyup = (evt) => {\n var _a;\n (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();\n this.abortController = new AbortController();\n void this.search(evt.target.value, this.abortController);\n };\n Object.assign(this.inputElt.style, {\n padding: '10px 30px 10px 10px',\n });\n element.appendChild(this.inputElt);\n // Create suggestions list element\n this.suggestionsElt = document.createElement('div');\n Object.assign(this.suggestionsElt.style, {\n backgroundColor: 'white',\n cursor: 'pointer',\n overflowY: 'auto',\n });\n element.appendChild(this.suggestionsElt);\n this.clearElt = document.createElement('div');\n Object.assign(this.clearElt.style, {\n cursor: 'pointer',\n display: 'none',\n fontSize: '200%',\n padding: '0 10px',\n position: 'absolute',\n right: '0',\n });\n this.clearElt.innerHTML = '×';\n this.clearElt.onclick = () => {\n return this.clear();\n };\n element.appendChild(this.clearElt);\n }\n render(featureCollection) {\n var _a;\n const suggestions = (_a = featureCollection === null || featureCollection === void 0 ? void 0 : featureCollection.features) !== null && _a !== void 0 ? _a : [];\n if (!this.suggestionsElt) {\n return;\n }\n this.suggestionsElt.style.display = suggestions.length ? 'block' : 'none';\n this.suggestionsElt.innerHTML = '';\n suggestions.forEach((suggestion) => {\n var _a, _b;\n const suggElt = document.createElement('div');\n suggElt.innerHTML = ((_a = suggestion === null || suggestion === void 0 ? void 0 : suggestion.properties) === null || _a === void 0 ? void 0 : _a.name) || '';\n suggElt.onclick = (evt) => {\n var _a, _b;\n (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.onSuggestionClick) === null || _b === void 0 ? void 0 : _b.call(_a, suggestion, evt);\n };\n Object.assign(suggElt.style, {\n padding: '5px 12px',\n });\n (_b = this.suggestionsElt) === null || _b === void 0 ? void 0 : _b.appendChild(suggElt);\n });\n }\n /**\n * Launch a search.\n *\n * @param {String} q The query to search for.\n * @param {AbortController} abortController Abort controller used to cancel the request.\n * @return {Promise>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326).\n */\n search(q, abortController) {\n if (q !== undefined || q !== null) {\n this.apiParams.q = q;\n }\n if (this.clearElt) {\n this.clearElt.style.display = 'block';\n }\n return this.api\n .search(this.apiParams, abortController && { signal: abortController.signal })\n .then((data) => {\n this.render(data);\n })\n .catch(() => {\n this.render();\n });\n }\n}\nexport default StopFinderControlCommon;\n", @@ -4591,7 +4806,7 @@ "lineNumber": 1 }, { - "__docId__": 215, + "__docId__": 223, "kind": "class", "name": "StopFinderControlCommon", "memberof": "build/common/controls/StopFinderControlCommon.js", @@ -4606,7 +4821,7 @@ "interface": false }, { - "__docId__": 216, + "__docId__": 224, "kind": "constructor", "name": "constructor", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4687,7 +4902,7 @@ ] }, { - "__docId__": 217, + "__docId__": 225, "kind": "member", "name": "apiParams", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4704,7 +4919,7 @@ } }, { - "__docId__": 218, + "__docId__": 226, "kind": "member", "name": "placeholder", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4721,7 +4936,7 @@ } }, { - "__docId__": 219, + "__docId__": 227, "kind": "member", "name": "api", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4738,7 +4953,7 @@ } }, { - "__docId__": 220, + "__docId__": 228, "kind": "member", "name": "abortController", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4755,7 +4970,7 @@ } }, { - "__docId__": 221, + "__docId__": 229, "kind": "member", "name": "options", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4772,7 +4987,7 @@ } }, { - "__docId__": 222, + "__docId__": 230, "kind": "method", "name": "clear", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4787,7 +5002,7 @@ "return": null }, { - "__docId__": 223, + "__docId__": 231, "kind": "method", "name": "createElement", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4814,7 +5029,7 @@ "return": null }, { - "__docId__": 224, + "__docId__": 232, "kind": "member", "name": "inputElt", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4831,7 +5046,7 @@ } }, { - "__docId__": 226, + "__docId__": 234, "kind": "member", "name": "suggestionsElt", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4848,7 +5063,7 @@ } }, { - "__docId__": 227, + "__docId__": 235, "kind": "member", "name": "clearElt", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4865,7 +5080,7 @@ } }, { - "__docId__": 228, + "__docId__": 236, "kind": "method", "name": "render", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4888,7 +5103,7 @@ "return": null }, { - "__docId__": 229, + "__docId__": 237, "kind": "method", "name": "search", "memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon", @@ -4931,7 +5146,7 @@ } }, { - "__docId__": 230, + "__docId__": 238, "kind": "file", "name": "build/common/index.js", "content": "export * from './styles';\nexport * from './utils';\n", @@ -4942,7 +5157,7 @@ "lineNumber": 1 }, { - "__docId__": 231, + "__docId__": 239, "kind": "file", "name": "build/common/styles/index.js", "content": "import realtimeByDelayStyle from './realtimeByDelayStyle';\nimport realtimeStyle from './realtimeStyle';\nexport { default as realtimeByDelayStyle } from './realtimeByDelayStyle';\nexport * from './realtimeDrawCanvasUtils';\nexport { default as realtimeSimpleStyle } from './realtimeSimpleStyle';\nexport * from './realtimeStyle';\nexport { default as realtimeStyle } from './realtimeStyle';\n// backward compatibility\nexport const realtimeDefaultStyle = realtimeStyle;\nexport const realtimeDelayStyle = realtimeByDelayStyle;\n", @@ -4953,7 +5168,7 @@ "lineNumber": 1 }, { - "__docId__": 232, + "__docId__": 240, "kind": "variable", "name": "realtimeDefaultStyle", "memberof": "build/common/styles/index.js", @@ -4973,7 +5188,7 @@ } }, { - "__docId__": 233, + "__docId__": 241, "kind": "variable", "name": "realtimeDelayStyle", "memberof": "build/common/styles/index.js", @@ -4993,7 +5208,7 @@ } }, { - "__docId__": 234, + "__docId__": 242, "kind": "file", "name": "build/common/styles/realtimeByDelayStyle.js", "content": "import realtimeStyle from './realtimeStyle';\n/**\n * A tracker style that display the delay as backgroundColor.\n *\n * @param {*} trajectory The trajectory to render.\n * @param {*} viewState The view state of the map.\n * @param {*} options Some options to change the rendering\n * @return a canvas\n * @private\n */\nconst realtimeDelayStyle = (trajectory, viewState, options) => {\n return realtimeStyle(trajectory, viewState, Object.assign(Object.assign({}, options), { useDelayStyle: true }));\n};\nexport default realtimeDelayStyle;\n", @@ -5004,7 +5219,7 @@ "lineNumber": 1 }, { - "__docId__": 235, + "__docId__": 243, "kind": "function", "name": "realtimeDelayStyle", "memberof": "build/common/styles/realtimeByDelayStyle.js", @@ -5060,10 +5275,10 @@ } }, { - "__docId__": 236, + "__docId__": 244, "kind": "file", "name": "build/common/styles/realtimeDrawCanvasUtils.js", - "content": "import createCanvas from '../utils/createCanvas';\nexport const rotateCanvas = (canvas, rotation) => {\n const ctx = canvas.getContext('2d');\n ctx === null || ctx === void 0 ? void 0 : ctx.translate(canvas.width / 2, canvas.height / 2);\n ctx === null || ctx === void 0 ? void 0 : ctx.rotate(rotation);\n ctx === null || ctx === void 0 ? void 0 : ctx.translate(-canvas.width / 2, -canvas.height / 2);\n};\nconst arrowCache = {};\nexport const getArrowCanvas = (arrowSize, fillColor, pixelRatio = 1) => {\n const key = `${arrowSize.toString()},${fillColor},${pixelRatio}`;\n if (!arrowCache[key]) {\n // Create the arrow canvas\n const padding = 0 * pixelRatio;\n const canvas = createCanvas(arrowSize[0] * pixelRatio, arrowSize[1] * pixelRatio);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n ctx.fillStyle = fillColor;\n ctx.beginPath();\n ctx.moveTo(padding, padding);\n ctx.lineTo(canvas.width - padding, canvas.height / 2);\n ctx.lineTo(padding, canvas.height - padding);\n ctx.fill();\n ctx.beginPath();\n ctx.moveTo(padding, padding);\n ctx.lineTo(canvas.width - padding, canvas.height / 2);\n ctx.lineTo(padding, canvas.height - padding);\n ctx.lineTo(padding, padding);\n ctx.stroke();\n }\n arrowCache[key] = canvas;\n }\n return arrowCache[key];\n};\nconst bufferArrowCache = {};\nexport const getBufferArrowCanvas = (width, height, fillColor, arrowSize, rotation = 0, pixelRatio = 1, margin = 0) => {\n if (!arrowSize) {\n return null;\n }\n const bufferKey = `${fillColor},${width},${height},${rotation},${pixelRatio},${margin}.${arrowSize.toString()}`;\n if (!bufferArrowCache[bufferKey]) {\n // Create a buffer canvas around the current vehicle to display properly the arrow\n const arrowCanvas = getArrowCanvas(arrowSize, fillColor, pixelRatio);\n if (arrowCanvas) {\n const bufferCanvas = createCanvas(width + arrowCanvas.width * 2 + margin * 2, height + arrowCanvas.height * 2 + margin * 2);\n if (bufferCanvas) {\n const bufferCtx = bufferCanvas.getContext('2d');\n rotateCanvas(bufferCanvas, -rotation);\n bufferCtx === null || bufferCtx === void 0 ? void 0 : bufferCtx.drawImage(arrowCanvas, bufferCanvas.width - arrowCanvas.width, bufferCanvas.height / 2 - arrowCanvas.height / 2 - margin / 2, arrowCanvas.width, arrowCanvas.height);\n }\n bufferArrowCache[bufferKey] = bufferCanvas;\n }\n }\n return bufferArrowCache[bufferKey];\n};\nconst cacheDelayBg = {};\n/**\n * Draw circle delay background\n */\nexport const getDelayBgCanvas = (radius, color, pixelRatio = 1, blurWidth = 1) => {\n const key = `${radius}, ${color}, ${blurWidth}, ${pixelRatio}`;\n const padding = 1 * pixelRatio; // must be the same as circle padding\n const blur = blurWidth * pixelRatio;\n if (!cacheDelayBg[key]) {\n const size = radius * 2 + padding * 2 + blur * 2 + padding * 2;\n const canvas = createCanvas(size, size);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n ctx.beginPath();\n ctx.arc(size / 2, size / 2, radius + padding + blur, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.filter = `blur(${blur}px)`;\n ctx.fill();\n cacheDelayBg[key] = canvas;\n }\n }\n return cacheDelayBg[key];\n};\nconst cacheCanvasTextSize = {};\nexport const getCanvasTextSize = (text, font, color, outlineColor, outlineWidth, pixelRatio) => {\n const key = `${text}, ${font}, ${color}, ${outlineColor}, ${outlineWidth}, ${pixelRatio}`;\n if (!cacheCanvasTextSize[key]) {\n const canvas = createCanvas(300 * pixelRatio, 300 * pixelRatio);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n // We calcuate the text size first\n ctx.font = font;\n ctx.textBaseline = 'hanging';\n ctx.textAlign = 'left';\n ctx.fillStyle = color;\n ctx.strokeStyle = outlineColor;\n ctx.lineWidth = outlineWidth;\n ctx.strokeText(text, 0, 0);\n ctx.fillText(text, 0, 0);\n const textMetrics = ctx.measureText(text);\n const size = {\n height: textMetrics.fontBoundingBoxAscent +\n textMetrics.fontBoundingBoxDescent,\n width: textMetrics.width,\n };\n cacheCanvasTextSize[key] = size;\n }\n }\n return cacheCanvasTextSize[key];\n};\nconst cacheDelayText = {};\n/**\n * Draw delay text\n */\nexport const getDelayTextCanvas = (text, fontSize, font, color, outlineColor = '#000', pixelRatio = 1) => {\n const key = `${text}, ${font}, ${color}, ${outlineColor}, ${pixelRatio}`;\n const padding = 2 * pixelRatio;\n const lineWidth = 1.5 * pixelRatio;\n if (!cacheDelayText[key]) {\n const textSize = getCanvasTextSize(text, font, color, outlineColor, lineWidth, pixelRatio);\n if ((textSize === null || textSize === void 0 ? void 0 : textSize.width) && (textSize === null || textSize === void 0 ? void 0 : textSize.height)) {\n const canvas = createCanvas(textSize.width + padding * 2, textSize.height + padding * 2);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n // We calcuate the text size first\n ctx.font = font;\n ctx.fillStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = outlineColor;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'ideographic';\n ctx.strokeText(text, padding, canvas.height - padding);\n ctx.fillText(text, padding, canvas.height - padding);\n cacheDelayText[key] = canvas;\n }\n }\n }\n return cacheDelayText[key];\n};\nconst cacheCircle = {};\n/**\n * Draw colored circle with black border\n */\nexport const getCircleCanvas = (radius, color, hasStroke, hasDash, pixelRatio) => {\n const key = `${radius}, ${color}, ${hasStroke}, ${hasDash}, ${pixelRatio}`;\n const padding = 1 * pixelRatio;\n const lineWidth = hasStroke ? 1 * pixelRatio : 0;\n const lineDash = hasDash ? [5 * pixelRatio, 3 * pixelRatio] : null;\n if (!cacheCircle[key]) {\n const canvas = createCanvas(radius * 2 + padding * 2, radius * 2 + padding * 2);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n ctx.fillStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = '#000000';\n ctx.beginPath();\n ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, 2 * Math.PI, false);\n ctx.fill();\n if (lineDash) {\n ctx.setLineDash(lineDash);\n }\n ctx.stroke();\n cacheCircle[key] = canvas;\n }\n }\n return cacheCircle[key];\n};\nconst cacheText = {};\n/**\n * Draw text in the circle\n */\nexport const getTextCanvas = (text, radius, textSize, fillColor, strokeColor, hasStroke, pixelRatio, font) => {\n const key = `${text}, ${radius}, ${textSize}, ${fillColor},${strokeColor}, ${hasStroke}, ${pixelRatio}`;\n if (!cacheText[key]) {\n const canvas = createCanvas(radius * 2, radius * 2);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n // Draw a stroke to the text only if a provider provides realtime but we don't use it.\n if (hasStroke) {\n ctx.save();\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.font = font;\n ctx.strokeStyle = strokeColor;\n ctx.strokeText(text, radius, radius);\n ctx.restore();\n }\n // Draw a text\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.fillStyle = fillColor;\n ctx.font = font;\n ctx.strokeStyle = strokeColor;\n ctx.strokeText(text, radius, radius);\n ctx.fillText(text, radius, radius);\n cacheText[key] = canvas;\n }\n }\n return cacheText[key];\n};\n", + "content": "import createCanvas from '../utils/createCanvas';\nexport const rotateCanvas = (canvas, rotation) => {\n const ctx = canvas.getContext('2d');\n ctx === null || ctx === void 0 ? void 0 : ctx.translate(canvas.width / 2, canvas.height / 2);\n ctx === null || ctx === void 0 ? void 0 : ctx.rotate(rotation);\n ctx === null || ctx === void 0 ? void 0 : ctx.translate(-canvas.width / 2, -canvas.height / 2);\n};\nconst arrowCache = {};\nexport const getArrowCanvas = (arrowSize, fillColor, pixelRatio = 1) => {\n const key = `${arrowSize.toString()},${fillColor},${pixelRatio}`;\n if (!arrowCache[key]) {\n // Create the arrow canvas\n const padding = 0 * pixelRatio;\n const canvas = createCanvas(arrowSize[0] * pixelRatio, arrowSize[1] * pixelRatio);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n ctx.fillStyle = fillColor;\n ctx.beginPath();\n ctx.moveTo(padding, padding);\n ctx.lineTo(canvas.width - padding, canvas.height / 2);\n ctx.lineTo(padding, canvas.height - padding);\n ctx.fill();\n ctx.beginPath();\n ctx.moveTo(padding, padding);\n ctx.lineTo(canvas.width - padding, canvas.height / 2);\n ctx.lineTo(padding, canvas.height - padding);\n ctx.lineTo(padding, padding);\n ctx.stroke();\n }\n arrowCache[key] = canvas;\n }\n return arrowCache[key];\n};\nconst bufferArrowCache = {};\nexport const getBufferArrowCanvas = (width, height, fillColor, arrowSize, rotation = 0, pixelRatio = 1, margin = 0) => {\n if (!arrowSize) {\n return null;\n }\n const bufferKey = `${fillColor},${width},${height},${rotation},${pixelRatio},${margin}.${arrowSize.toString()}`;\n if (!bufferArrowCache[bufferKey]) {\n // Create a buffer canvas around the current vehicle to display properly the arrow\n const arrowCanvas = getArrowCanvas(arrowSize, fillColor, pixelRatio);\n if (arrowCanvas) {\n const bufferCanvas = createCanvas(width + arrowCanvas.width * 2 + margin * 2, height + arrowCanvas.height * 2 + margin * 2);\n if (bufferCanvas) {\n const bufferCtx = bufferCanvas.getContext('2d');\n rotateCanvas(bufferCanvas, -rotation);\n bufferCtx === null || bufferCtx === void 0 ? void 0 : bufferCtx.drawImage(arrowCanvas, bufferCanvas.width - arrowCanvas.width, bufferCanvas.height / 2 - arrowCanvas.height / 2 - margin / 2, arrowCanvas.width, arrowCanvas.height);\n }\n bufferArrowCache[bufferKey] = bufferCanvas;\n }\n }\n return bufferArrowCache[bufferKey];\n};\nconst cacheDelayBg = {};\n/**\n * Draw circle delay background\n */\nexport const getDelayBgCanvas = (radius, color, pixelRatio = 1, blurWidth = 1) => {\n const key = `${radius}, ${color}, ${blurWidth}, ${pixelRatio}`;\n const padding = 1 * pixelRatio; // must be the same as circle padding\n const blur = blurWidth * pixelRatio;\n if (!cacheDelayBg[key]) {\n const size = radius * 2 + padding * 2 + blur * 2 + padding * 2;\n const canvas = createCanvas(size, size);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n ctx.beginPath();\n ctx.arc(size / 2, size / 2, radius + padding + blur, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.filter = `blur(${blur}px)`;\n ctx.fill();\n cacheDelayBg[key] = canvas;\n }\n }\n return cacheDelayBg[key];\n};\nconst cacheCanvasTextSize = {};\nexport const getCanvasTextSize = (text, font, color, outlineColor, outlineWidth, pixelRatio) => {\n const key = `${text}, ${font}, ${color}, ${outlineColor}, ${outlineWidth}, ${pixelRatio}`;\n if (!cacheCanvasTextSize[key]) {\n const canvas = createCanvas(300 * pixelRatio, 300 * pixelRatio);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n // We calcuate the text size first\n ctx.font = font;\n ctx.textBaseline = 'hanging';\n ctx.textAlign = 'left';\n ctx.fillStyle = color;\n ctx.strokeStyle = outlineColor;\n ctx.lineWidth = outlineWidth;\n ctx.strokeText(text, 0, 0);\n ctx.fillText(text, 0, 0);\n const textMetrics = ctx.measureText(text);\n const size = {\n height: textMetrics.fontBoundingBoxAscent +\n textMetrics.fontBoundingBoxDescent,\n width: textMetrics.width,\n };\n cacheCanvasTextSize[key] = size;\n }\n }\n return cacheCanvasTextSize[key];\n};\nconst cacheDelayText = {};\n/**\n * Draw delay text\n */\nexport const getDelayTextCanvas = (text, fontSize, font, color, outlineColor = '#000', pixelRatio = 1) => {\n const key = `${text}, ${font}, ${color}, ${outlineColor}, ${pixelRatio}`;\n const padding = 2 * pixelRatio;\n const lineWidth = 1.5 * pixelRatio;\n if (!cacheDelayText[key]) {\n const textSize = getCanvasTextSize(text, font, color, outlineColor, lineWidth, pixelRatio);\n if ((textSize === null || textSize === void 0 ? void 0 : textSize.width) && (textSize === null || textSize === void 0 ? void 0 : textSize.height)) {\n const canvas = createCanvas(textSize.width + padding * 2, textSize.height + padding * 2);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (canvas && ctx) {\n // We calcuate the text size first\n ctx.font = font;\n ctx.fillStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = outlineColor;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'ideographic';\n ctx.strokeText(text, padding, canvas.height - padding);\n ctx.fillText(text, padding, canvas.height - padding);\n cacheDelayText[key] = canvas;\n }\n }\n }\n return cacheDelayText[key];\n};\nconst cacheCircle = {};\n/**\n * Draw colored circle with black border\n */\nexport const getCircleCanvas = (radius, color, hasStroke, hasDash, pixelRatio) => {\n const key = `${radius}, ${color}, ${hasStroke}, ${hasDash}, ${pixelRatio}`;\n const padding = 1 * pixelRatio;\n const lineWidth = hasStroke ? 1 * pixelRatio : 0;\n const lineDash = hasDash ? [5 * pixelRatio, 3 * pixelRatio] : null;\n if (!cacheCircle[key]) {\n const canvas = createCanvas(radius * 2 + padding * 2, radius * 2 + padding * 2);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n ctx.fillStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = '#000000';\n ctx.beginPath();\n ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, 2 * Math.PI, false);\n ctx.fill();\n if (lineDash) {\n ctx.setLineDash(lineDash);\n }\n if (lineWidth > 0) {\n ctx.stroke();\n }\n cacheCircle[key] = canvas;\n }\n }\n return cacheCircle[key];\n};\nconst cacheText = {};\n/**\n * Draw text in the circle\n */\nexport const getTextCanvas = (text, radius, textSize, fillColor, strokeColor, hasStroke, pixelRatio, font) => {\n const key = `${text}, ${radius}, ${textSize}, ${fillColor},${strokeColor}, ${hasStroke}, ${pixelRatio}`;\n if (!cacheText[key]) {\n const canvas = createCanvas(radius * 2, radius * 2);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n // Draw a stroke to the text only if a provider provides realtime but we don't use it.\n if (hasStroke) {\n ctx.save();\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.font = font;\n ctx.strokeStyle = strokeColor;\n ctx.strokeText(text, radius, radius);\n ctx.restore();\n }\n // Draw a text\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.fillStyle = fillColor;\n ctx.font = font;\n ctx.strokeStyle = strokeColor;\n ctx.strokeText(text, radius, radius);\n ctx.fillText(text, radius, radius);\n cacheText[key] = canvas;\n }\n }\n return cacheText[key];\n};\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/styles/realtimeDrawCanvasUtils.js", "access": "private", @@ -5071,7 +5286,7 @@ "lineNumber": 1 }, { - "__docId__": 237, + "__docId__": 245, "kind": "function", "name": "rotateCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5103,7 +5318,7 @@ "return": null }, { - "__docId__": 238, + "__docId__": 246, "kind": "variable", "name": "arrowCache", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5124,7 +5339,7 @@ "ignore": true }, { - "__docId__": 239, + "__docId__": 247, "kind": "function", "name": "getArrowCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5169,7 +5384,7 @@ } }, { - "__docId__": 240, + "__docId__": 248, "kind": "variable", "name": "bufferArrowCache", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5190,7 +5405,7 @@ "ignore": true }, { - "__docId__": 241, + "__docId__": 249, "kind": "function", "name": "getBufferArrowCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5265,7 +5480,7 @@ } }, { - "__docId__": 242, + "__docId__": 250, "kind": "variable", "name": "cacheDelayBg", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5286,7 +5501,7 @@ "ignore": true }, { - "__docId__": 243, + "__docId__": 251, "kind": "function", "name": "getDelayBgCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5339,7 +5554,7 @@ } }, { - "__docId__": 244, + "__docId__": 252, "kind": "variable", "name": "cacheCanvasTextSize", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5360,7 +5575,7 @@ "ignore": true }, { - "__docId__": 245, + "__docId__": 253, "kind": "function", "name": "getCanvasTextSize", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5420,7 +5635,7 @@ } }, { - "__docId__": 246, + "__docId__": 254, "kind": "variable", "name": "cacheDelayText", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5441,7 +5656,7 @@ "ignore": true }, { - "__docId__": 247, + "__docId__": 255, "kind": "function", "name": "getDelayTextCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5506,7 +5721,7 @@ } }, { - "__docId__": 248, + "__docId__": 256, "kind": "variable", "name": "cacheCircle", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5527,7 +5742,7 @@ "ignore": true }, { - "__docId__": 249, + "__docId__": 257, "kind": "function", "name": "getCircleCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5580,7 +5795,7 @@ } }, { - "__docId__": 250, + "__docId__": 258, "kind": "variable", "name": "cacheText", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5591,7 +5806,7 @@ "importPath": "mobility-toolbox-js/build/common/styles/realtimeDrawCanvasUtils.js", "importStyle": null, "description": null, - "lineNumber": 165, + "lineNumber": 167, "undocument": true, "type": { "types": [ @@ -5601,7 +5816,7 @@ "ignore": true }, { - "__docId__": 251, + "__docId__": 259, "kind": "function", "name": "getTextCanvas", "memberof": "build/common/styles/realtimeDrawCanvasUtils.js", @@ -5614,7 +5829,7 @@ "importPath": "mobility-toolbox-js/build/common/styles/realtimeDrawCanvasUtils.js", "importStyle": "{getTextCanvas}", "description": "Draw text in the circle", - "lineNumber": 169, + "lineNumber": 171, "params": [ { "name": "text", @@ -5672,7 +5887,7 @@ } }, { - "__docId__": 252, + "__docId__": 260, "kind": "file", "name": "build/common/styles/realtimeSimpleStyle.js", "content": "import createCanvas from '../utils/createCanvas';\n/**\n * A very simple tracker style.\n * Display blue point for each train.\n */\nlet canvas;\nconst realtimeSimpleStyle = () => {\n if (!canvas) {\n canvas = createCanvas(15, 15);\n const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if (ctx) {\n ctx.arc(8, 8, 5, 0, 2 * Math.PI, false);\n ctx.fillStyle = '#8ED6FF';\n ctx.fill();\n ctx.lineWidth = 3;\n ctx.strokeStyle = 'black';\n ctx.stroke();\n ctx.lineWidth = 3;\n }\n }\n return canvas;\n};\nexport default realtimeSimpleStyle;\n", @@ -5683,7 +5898,7 @@ "lineNumber": 1 }, { - "__docId__": 253, + "__docId__": 261, "kind": "function", "name": "realtimeSimpleStyle", "memberof": "build/common/styles/realtimeSimpleStyle.js", @@ -5706,10 +5921,10 @@ } }, { - "__docId__": 254, + "__docId__": 262, "kind": "file", "name": "build/common/styles/realtimeStyle.js", - "content": "import createCanvas from '../utils/createCanvas';\nimport { getBufferArrowCanvas, getCircleCanvas, getDelayBgCanvas, getDelayTextCanvas, getTextCanvas, } from './realtimeDrawCanvasUtils';\nconst cache = {};\n/**\n * A realtime style that display a circle, a delay (halo and text) and an arrow (heading).\n * The colors (texts and circle) can be defined in the options.\n *\n * @param {RealtimeTrajectory} trajectory The trajectory to render.\n * @param {ViewState} viewState The view state of the map.\n * @param {RealtimeStyleOptions} options Some options to change the rendering\n * @return a canvas\n */\nconst realtimeStyle = (trajectory, viewState, options) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n const { delayDisplay, delayOutlineColor, getArrowSize, getColor, getDelayColor, getDelayFont, getDelayText, getDelayTextColor, getImage, getMaxRadiusForStrokeAndDelay, getMaxRadiusForText, getRadius, getText, getTextColor, getTextFont, getTextSize, hoverVehicleId, selectedVehicleId, showDelayBg, showDelayText, showHeading, useDelayStyle, } = options;\n const { pixelRatio = 1 } = viewState;\n const { delay, operator_provides_realtime_journey: operatorProvidesRealtime, rotation, state, train_id: id, } = trajectory.properties;\n const name = (getText === null || getText === void 0 ? void 0 : getText(trajectory, viewState)) || '';\n let color = getColor(trajectory, viewState);\n let textColor = getTextColor(trajectory, viewState);\n const cancelled = state === 'JOURNEY_CANCELLED';\n const hover = !!(hoverVehicleId && hoverVehicleId === id);\n const selected = !!(selectedVehicleId && selectedVehicleId === id);\n // Get the text color of the vehicle\n if (useDelayStyle) {\n color = getDelayColor(trajectory, viewState, delay, cancelled);\n textColor = getDelayTextColor(trajectory, viewState, delay, cancelled);\n }\n // Calcul the radius of the circle\n let radius = getRadius(trajectory, viewState) * pixelRatio;\n const isDisplayStrokeAndDelay = radius >= getMaxRadiusForStrokeAndDelay() * pixelRatio;\n if (hover || selected) {\n radius = isDisplayStrokeAndDelay\n ? radius + 5 * pixelRatio\n : 14 * pixelRatio;\n }\n const isDisplayText = radius > getMaxRadiusForText() * pixelRatio;\n // Optimize the cache key, very important in high zoom level\n let key = `${radius}${hover || selected}${showHeading ? rotation : ''}`;\n if (useDelayStyle) {\n key += `${operatorProvidesRealtime}${delay}${cancelled}`;\n }\n else {\n key += `${color}`;\n if (isDisplayStrokeAndDelay) {\n key += `${cancelled}${delay}`;\n }\n }\n if (isDisplayText) {\n key += `${name}${textColor}`;\n }\n if (!cache[key]) {\n if (radius === 0) {\n return null;\n }\n // Get the color of the vehicle\n const circleFillColor = color;\n const hasStroke = isDisplayStrokeAndDelay || hover || selected;\n const hasDash = !!isDisplayStrokeAndDelay &&\n !!useDelayStyle &&\n delay === null &&\n operatorProvidesRealtime === 'yes';\n const hasDelayText = showDelayText &&\n isDisplayStrokeAndDelay &&\n (hover || (delay || 0) >= delayDisplay || cancelled);\n const hasDelayBg = showDelayBg && isDisplayStrokeAndDelay && delay !== null;\n const hasHeading = showHeading && isDisplayText && rotation;\n // Show delay if feature is hovered or if delay is above 5mins\n let fontSize = 0;\n let text = null;\n if (hasDelayText) {\n // Draw delay text\n fontSize =\n Math.max(cancelled ? 19 : 14, Math.min(cancelled ? 19 : 17, radius * 1.2)) * pixelRatio;\n text = getDelayText(trajectory, viewState, delay !== null && delay !== void 0 ? delay : 0, cancelled);\n }\n // Draw colored circle with black border\n const circle = getCircleCanvas(radius, circleFillColor, hasStroke, hasDash, pixelRatio);\n // Draw text in the center of circle\n let circleText = null;\n if (isDisplayText && circle) {\n const image = getImage(trajectory, viewState, name, radius);\n if (image) {\n // If an image is provided we use it instead of text\n circleText = image;\n }\n else {\n const fontSize2 = Math.max(radius, 10);\n const textSize = getTextSize(trajectory, viewState, circle.getContext('2d'), radius * 2, name, fontSize2, getTextFont(trajectory, viewState, fontSize2, name));\n const font = getTextFont(trajectory, viewState, textSize, name);\n const hasStroke2 = !!useDelayStyle &&\n delay === null &&\n operatorProvidesRealtime === 'yes';\n circleText = getTextCanvas(name, radius, textSize, textColor, circleFillColor, hasStroke2, pixelRatio, font);\n }\n }\n // Draw circle delay background\n let delayBg = null;\n if (hasDelayBg) {\n delayBg = getDelayBgCanvas(radius, getDelayColor(trajectory, viewState, delay, cancelled), pixelRatio);\n }\n // Draw delay text\n let delayText = null;\n if (text) {\n delayText = getDelayTextCanvas(text, fontSize, getDelayFont(trajectory, viewState, fontSize, text), getDelayColor(trajectory, viewState, delay, cancelled, true), delayOutlineColor, pixelRatio);\n }\n // Draw rotated arrow and add the circle in it\n let isArrowOnDelaySide = true;\n let bufferArrow = null;\n const canvasRef = delayBg !== null && delayBg !== void 0 ? delayBg : circle;\n if (hasHeading && canvasRef && circle) {\n const radianAdjusted = rotation % (2 * Math.PI);\n if (-0.5 > radianAdjusted || radianAdjusted > 0.5) {\n isArrowOnDelaySide = false;\n }\n bufferArrow = getBufferArrowCanvas(canvasRef.width, canvasRef.height, circleFillColor, getArrowSize(trajectory, viewState, radius / pixelRatio), rotation, pixelRatio);\n }\n // At this point we have the canvases to compose the final canvas.\n // Create the canvas using the biggest width between all the elements\n const biggestCircleWidthWithoutArrow = Math.max((_a = delayBg === null || delayBg === void 0 ? void 0 : delayBg.width) !== null && _a !== void 0 ? _a : 0, (_b = circle === null || circle === void 0 ? void 0 : circle.width) !== null && _b !== void 0 ? _b : 0);\n const biggestCircleWidth = Math.max((_c = bufferArrow === null || bufferArrow === void 0 ? void 0 : bufferArrow.width) !== null && _c !== void 0 ? _c : 0, (_d = delayBg === null || delayBg === void 0 ? void 0 : delayBg.width) !== null && _d !== void 0 ? _d : 0, (_e = circle === null || circle === void 0 ? void 0 : circle.width) !== null && _e !== void 0 ? _e : 0);\n const width = biggestCircleWidth + ((_f = delayText === null || delayText === void 0 ? void 0 : delayText.width) !== null && _f !== void 0 ? _f : 0) * 2;\n const height = (_j = (_h = (_g = bufferArrow === null || bufferArrow === void 0 ? void 0 : bufferArrow.height) !== null && _g !== void 0 ? _g : delayBg === null || delayBg === void 0 ? void 0 : delayBg.height) !== null && _h !== void 0 ? _h : circle === null || circle === void 0 ? void 0 : circle.height) !== null && _j !== void 0 ? _j : 0;\n const canvas = createCanvas(width, height);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n if (bufferArrow) {\n // Draw in the middle of the canvas\n ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(bufferArrow, canvas.width / 2 - bufferArrow.width / 2, canvas.height / 2 - bufferArrow.height / 2);\n }\n if (delayBg) {\n // Draw in the middle of the canvas\n ctx.drawImage(delayBg, canvas.width / 2 - delayBg.width / 2, canvas.height / 2 - delayBg.height / 2);\n }\n if (circle) {\n // Draw in the middle of the canvas\n ctx.drawImage(circle, canvas.width / 2 - circle.width / 2, canvas.height / 2 - circle.height / 2);\n }\n // Draw text in the circle\n if (circleText) {\n // Draw in the middle of the canvas\n ctx.drawImage(circleText, canvas.width / 2 - circleText.width / 2, canvas.height / 2 - circleText.height / 2);\n }\n // Draw delay text\n if (delayText) {\n ctx.drawImage(delayText, canvas.width / 2 +\n (isArrowOnDelaySide\n ? biggestCircleWidth\n : biggestCircleWidthWithoutArrow) /\n 2, canvas.height / 2 - delayText.height / 2);\n }\n cache[key] = canvas;\n }\n }\n return cache[key];\n};\nexport default realtimeStyle;\n", + "content": "import createCanvas from '../utils/createCanvas';\nimport { getBufferArrowCanvas, getCircleCanvas, getDelayBgCanvas, getDelayTextCanvas, getTextCanvas, } from './realtimeDrawCanvasUtils';\nconst cache = {};\n/**\n * A realtime style that display a circle, a delay (halo and text) and an arrow (heading).\n * The colors (texts and circle) can be defined in the options.\n *\n * @param {RealtimeTrajectory} trajectory The trajectory to render.\n * @param {ViewState} viewState The view state of the map.\n * @param {RealtimeStyleOptions} options Some options to change the rendering\n * @return a canvas\n */\nconst realtimeStyle = (trajectory, viewState, options) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n const { delayDisplay, delayOutlineColor, getArrowSize, getColor, getDelayColor, getDelayFont, getDelayText, getDelayTextColor, getImage, getMaxRadiusForStrokeAndDelay, getMaxRadiusForText, getRadius, getText, getTextColor, getTextFont, getTextSize, hoverVehicleId, selectedVehicleId, showDelayBg, showDelayText, showHeading, useDelayStyle, } = options;\n const { pixelRatio = 1 } = viewState;\n const { delay, operator_provides_realtime_journey: operatorProvidesRealtime, rotation, state, train_id: id, } = trajectory.properties;\n const name = (getText === null || getText === void 0 ? void 0 : getText(trajectory, viewState)) || '';\n let color = getColor(trajectory, viewState);\n let textColor = getTextColor(trajectory, viewState);\n const cancelled = state === 'JOURNEY_CANCELLED';\n const hover = !!(hoverVehicleId && hoverVehicleId === id);\n const selected = !!(selectedVehicleId && selectedVehicleId === id);\n // Get the text color of the vehicle\n if (useDelayStyle) {\n color = getDelayColor(trajectory, viewState, delay, cancelled);\n textColor = getDelayTextColor(trajectory, viewState, delay, cancelled);\n }\n // Calcul the radius of the circle\n let radius = getRadius(trajectory, viewState) * pixelRatio;\n const isDisplayStrokeAndDelay = radius >= getMaxRadiusForStrokeAndDelay() * pixelRatio;\n if (hover || selected) {\n radius = isDisplayStrokeAndDelay\n ? radius + 5 * pixelRatio\n : 14 * pixelRatio;\n }\n const isDisplayText = radius > getMaxRadiusForText() * pixelRatio;\n // Optimize the cache key, very important in high zoom level\n let key = `${radius}${hover || selected}${showHeading ? rotation : ''}`;\n if (useDelayStyle) {\n key += `${operatorProvidesRealtime}${delay}${cancelled}`;\n }\n else {\n key += `${color}`;\n if (isDisplayStrokeAndDelay) {\n key += `${cancelled}${delay}`;\n }\n }\n if (isDisplayText) {\n key += `${name}${textColor}`;\n }\n if (!cache[key]) {\n if (radius === 0) {\n return null;\n }\n // Get the color of the vehicle\n const circleFillColor = color;\n const hasStroke = isDisplayStrokeAndDelay || hover || selected;\n const hasDash = !!isDisplayStrokeAndDelay &&\n !!useDelayStyle &&\n delay === null &&\n operatorProvidesRealtime === 'yes';\n const hasDelayText = showDelayText &&\n isDisplayStrokeAndDelay &&\n (hover || (delay || 0) >= delayDisplay || cancelled);\n const hasDelayBg = showDelayBg && isDisplayStrokeAndDelay && delay !== null;\n const hasHeading = showHeading && isDisplayText && rotation;\n // Show delay if feature is hovered or if delay is above 5mins\n let fontSize = 0;\n let text = null;\n if (hasDelayText) {\n // Draw delay text\n fontSize =\n Math.max(cancelled ? 19 : 14, Math.min(cancelled ? 19 : 17, radius * 1.2)) * pixelRatio;\n text = getDelayText(trajectory, viewState, delay !== null && delay !== void 0 ? delay : 0, cancelled);\n }\n // Draw colored circle with black border\n const circle = getCircleCanvas(radius, circleFillColor, hasStroke, hasDash, pixelRatio);\n // Draw text in the center of circle\n let circleText = null;\n if (isDisplayText && circle) {\n const image = getImage(trajectory, viewState, name, radius);\n if (image) {\n // If an image is provided we use it instead of text\n circleText = image;\n }\n else {\n const padding = 6 * pixelRatio;\n const fontSize2 = Math.max(radius, 10);\n // Initialize the context font for calculation\n // The canvas automatically round the font size to 1 number after\n // the comma, so we need to round also the fontSize for calculation\n // when the browser is zoomed.\n const toFontFixed = Number(fontSize2.toFixed(1));\n const textSize = getTextSize(trajectory, viewState, circle.getContext('2d'), radius * 2 - padding, name, toFontFixed, getTextFont(trajectory, viewState, toFontFixed, name));\n const font = getTextFont(trajectory, viewState, textSize, name);\n const hasStroke2 = !!useDelayStyle &&\n delay === null &&\n operatorProvidesRealtime === 'yes';\n circleText = getTextCanvas(name, radius, textSize, textColor, circleFillColor, hasStroke2, pixelRatio, font);\n }\n }\n // Draw circle delay background\n let delayBg = null;\n if (hasDelayBg) {\n delayBg = getDelayBgCanvas(radius, getDelayColor(trajectory, viewState, delay, cancelled), pixelRatio);\n }\n // Draw delay text\n let delayText = null;\n if (text) {\n delayText = getDelayTextCanvas(text, fontSize, getDelayFont(trajectory, viewState, fontSize, text), getDelayColor(trajectory, viewState, delay, cancelled, true), delayOutlineColor, pixelRatio);\n }\n // Draw rotated arrow and add the circle in it\n let isArrowOnDelaySide = true;\n let bufferArrow = null;\n const canvasRef = delayBg !== null && delayBg !== void 0 ? delayBg : circle;\n if (hasHeading && canvasRef && circle) {\n const radianAdjusted = rotation % (2 * Math.PI);\n if (-0.5 > radianAdjusted || radianAdjusted > 0.5) {\n isArrowOnDelaySide = false;\n }\n bufferArrow = getBufferArrowCanvas(canvasRef.width, canvasRef.height, circleFillColor, getArrowSize(trajectory, viewState, radius / pixelRatio), rotation, pixelRatio);\n }\n // At this point we have the canvases to compose the final canvas.\n // Create the canvas using the biggest width between all the elements\n const biggestCircleWidthWithoutArrow = Math.max((_a = delayBg === null || delayBg === void 0 ? void 0 : delayBg.width) !== null && _a !== void 0 ? _a : 0, (_b = circle === null || circle === void 0 ? void 0 : circle.width) !== null && _b !== void 0 ? _b : 0);\n const biggestCircleWidth = Math.max((_c = bufferArrow === null || bufferArrow === void 0 ? void 0 : bufferArrow.width) !== null && _c !== void 0 ? _c : 0, (_d = delayBg === null || delayBg === void 0 ? void 0 : delayBg.width) !== null && _d !== void 0 ? _d : 0, (_e = circle === null || circle === void 0 ? void 0 : circle.width) !== null && _e !== void 0 ? _e : 0);\n const width = biggestCircleWidth + ((_f = delayText === null || delayText === void 0 ? void 0 : delayText.width) !== null && _f !== void 0 ? _f : 0) * 2;\n const height = (_j = (_h = (_g = bufferArrow === null || bufferArrow === void 0 ? void 0 : bufferArrow.height) !== null && _g !== void 0 ? _g : delayBg === null || delayBg === void 0 ? void 0 : delayBg.height) !== null && _h !== void 0 ? _h : circle === null || circle === void 0 ? void 0 : circle.height) !== null && _j !== void 0 ? _j : 0;\n const canvas = createCanvas(width, height);\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n if (bufferArrow) {\n // Draw in the middle of the canvas\n ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(bufferArrow, canvas.width / 2 - bufferArrow.width / 2, canvas.height / 2 - bufferArrow.height / 2);\n }\n if (delayBg) {\n // Draw in the middle of the canvas\n ctx.drawImage(delayBg, canvas.width / 2 - delayBg.width / 2, canvas.height / 2 - delayBg.height / 2);\n }\n if (circle) {\n // Draw in the middle of the canvas\n ctx.drawImage(circle, canvas.width / 2 - circle.width / 2, canvas.height / 2 - circle.height / 2);\n }\n // Draw text in the circle\n if (circleText) {\n // Draw in the middle of the canvas\n ctx.drawImage(circleText, canvas.width / 2 - circleText.width / 2, canvas.height / 2 - circleText.height / 2);\n }\n // Draw delay text\n if (delayText) {\n ctx.drawImage(delayText, canvas.width / 2 +\n (isArrowOnDelaySide\n ? biggestCircleWidth\n : biggestCircleWidthWithoutArrow) /\n 2, canvas.height / 2 - delayText.height / 2);\n }\n cache[key] = canvas;\n }\n }\n return cache[key];\n};\nexport default realtimeStyle;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/styles/realtimeStyle.js", "access": "private", @@ -5717,7 +5932,7 @@ "lineNumber": 1 }, { - "__docId__": 255, + "__docId__": 263, "kind": "variable", "name": "cache", "memberof": "build/common/styles/realtimeStyle.js", @@ -5738,7 +5953,7 @@ "ignore": true }, { - "__docId__": 256, + "__docId__": 264, "kind": "function", "name": "realtimeStyle", "memberof": "build/common/styles/realtimeStyle.js", @@ -5794,7 +6009,7 @@ } }, { - "__docId__": 257, + "__docId__": 265, "kind": "file", "name": "build/common/typedefs.js", "content": "/**\n * @typedef {function} FilterFunction\n * @param {Vehicle} vehicle Vehicle to filter.\n * @returns boolean\n */\n/**\n * @typedef {function} SortFunction\n * @param {any} a Object a to compare.\n * @param {any} b Object b to compare.\n * @returns number\n */\n/**\n * @typedef {function} getMotsByZoomFunction\n * @param {number} zoom Curent zoom level.\n * @param {RealtimeMot[][]} motsByZoom Default array of mots by zoom.\n * @returns number\n */\n/**\n * @typedef {Object} ViewState\n * @property {number|undefined} time A time in ms.\n * @property {number[2]|undefined} center A center in mercator coordinate.\n * @property {number[4]} extent An Extent in mercator coordinates.\n * @property {number[2]} size A size ([width, height]).\n * @property {number} rotation A rotation in radians.\n * @property {number} resolution A resolution.\n * @property {number} zoom A zoom level.\n * @property {number|undefined} pixelRatio A pixel ratio.\n */\n/**\n * @typedef {Object} FeatureInfo\n * @property {Layer} layer A layer.\n * @property {Feature[]} features An array of features.\n * @property {number[2]} coordinate The coordinate where to find the featue.\n */\n/**\n * @typedef {Object} VehiclePosition\n * @property {number[2]} coord Coordinate of the vehicle position in Mercator .\n * @property {number!} rotation An angle in radians representing the direction (from the true north) towards which the vehicle is facing.\n */\n// These lines is to block TypeScript to add \"use strict;\" in the outputed file.\nconst dummy = () => { };\nexport default dummy;\n", @@ -5805,7 +6020,7 @@ "lineNumber": 1 }, { - "__docId__": 258, + "__docId__": 266, "kind": "typedef", "name": "FilterFunction", "memberof": "build/common/typedefs.js", @@ -5848,7 +6063,7 @@ } }, { - "__docId__": 259, + "__docId__": 267, "kind": "typedef", "name": "SortFunction", "memberof": "build/common/typedefs.js", @@ -5901,7 +6116,7 @@ } }, { - "__docId__": 260, + "__docId__": 268, "kind": "typedef", "name": "getMotsByZoomFunction", "memberof": "build/common/typedefs.js", @@ -5954,7 +6169,7 @@ } }, { - "__docId__": 261, + "__docId__": 269, "kind": "typedef", "name": "ViewState", "memberof": "build/common/typedefs.js", @@ -6056,7 +6271,7 @@ } }, { - "__docId__": 262, + "__docId__": 270, "kind": "typedef", "name": "FeatureInfo", "memberof": "build/common/typedefs.js", @@ -6105,7 +6320,7 @@ } }, { - "__docId__": 263, + "__docId__": 271, "kind": "typedef", "name": "VehiclePosition", "memberof": "build/common/typedefs.js", @@ -6145,7 +6360,7 @@ } }, { - "__docId__": 264, + "__docId__": 272, "kind": "file", "name": "build/common/utils/RealtimeEngine.js", "content": "import debounce from 'lodash.debounce';\nimport throttle from 'lodash.throttle';\nimport { buffer, containsCoordinate, intersects } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport { fromLonLat } from 'ol/proj';\nimport { RealtimeAPI, RealtimeModes } from '../../api';\nimport realtimeStyle from '../styles/realtimeStyle';\nimport { MOTS_ONLY_RAIL, MOTS_WITHOUT_CABLE, styleOptionsForMot, } from './realtimeStyleUtils';\nimport renderTrajectories from './renderTrajectories';\n/**\n * Basic style options used by default in the RealtimeEngine.\n */\nexport const defaultStyleOptions = Object.assign({ delayDisplay: 300000, delayOutlineColor: '#000', getArrowSize: (trajectory, viewState, radius = 0) => {\n return [(radius * 3) / 4, radius];\n }, getColor: () => {\n return '#000';\n }, getDelayColor: () => {\n return '#000';\n }, getDelayFont: (traj, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getDelayText: () => {\n return '';\n }, getDelayTextColor: () => {\n return '#000';\n }, getImage: () => {\n return null;\n }, getMaxRadiusForStrokeAndDelay: () => {\n return 7;\n }, getMaxRadiusForText: () => {\n return 10;\n }, getRadius: () => {\n return 5;\n }, getText: ((traj) => {\n var _a, _b;\n return ((_b = (_a = traj === null || traj === void 0 ? void 0 : traj.properties) === null || _a === void 0 ? void 0 : _a.line) === null || _b === void 0 ? void 0 : _b.name) || 'U';\n }), getTextColor: () => {\n return '#fff';\n }, getTextFont: (trajectory, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getTextSize: () => {\n return 14;\n }, showDelayBg: true, showDelayText: true, showHeading: false, useDelayStyle: false }, styleOptionsForMot);\n/**\n * This class is responsible for drawing trajectories from a realtime API in a canvas,\n * depending on the map's view state and at a specific time.\n *\n * This class is totally agnostic from Maplibre or OpenLayers and must stay taht way.\n */\nclass RealtimeEngine {\n get mode() {\n return this._mode;\n }\n set mode(newMode) {\n var _a, _b;\n if (newMode === this._mode) {\n return;\n }\n this._mode = newMode;\n if ((_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.wsApi) === null || _b === void 0 ? void 0 : _b.open) {\n this.stop();\n this.start();\n }\n }\n get speed() {\n return this._speed;\n }\n set speed(newSpeed) {\n this._speed = newSpeed;\n this.start();\n }\n get style() {\n return this._style;\n }\n set style(newStyle) {\n this._style = newStyle;\n this.renderTrajectories();\n }\n get time() {\n return this._time;\n }\n set time(newTime) {\n this._time = (newTime === null || newTime === void 0 ? void 0 : newTime.getTime)\n ? newTime\n : new Date(newTime);\n this.renderTrajectories();\n }\n constructor(options) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;\n this.isIdle = false;\n this.getViewState = () => {\n return {};\n };\n this.shouldRender = () => {\n return true;\n };\n this._mode = options.mode || RealtimeModes.TOPOGRAPHIC;\n this._speed = (_a = options.speed) !== null && _a !== void 0 ? _a : 1; // If live property is true. The speed is ignored.\n this._style = (_b = options.style) !== null && _b !== void 0 ? _b : realtimeStyle;\n this._time = (_c = options.time) !== null && _c !== void 0 ? _c : new Date();\n this.api = (_d = options.api) !== null && _d !== void 0 ? _d : new RealtimeAPI(options);\n this.bboxParameters = options.bboxParameters;\n this.canvas =\n (_e = options.canvas) !== null && _e !== void 0 ? _e : (typeof document !== 'undefined'\n ? document.createElement('canvas')\n : undefined);\n this.debug = (_f = options.debug) !== null && _f !== void 0 ? _f : false;\n this.filter = options.filter;\n this.hoverVehicleId = options.hoverVehicleId;\n /**\n * If true. The layer will always use Date.now() on the next tick to render the trajectories.\n * When true, setting the time property has no effect.\n */\n this.live = options.live !== false;\n this.minZoomInterpolation = (_g = options.minZoomInterpolation) !== null && _g !== void 0 ? _g : 8; // Min zoom level from which trains positions are not interpolated.\n this.pixelRatio =\n (_h = options.pixelRatio) !== null && _h !== void 0 ? _h : (typeof window !== 'undefined' ? window.devicePixelRatio : 1);\n this.selectedVehicleId = options.selectedVehicleId;\n this.sort = options.sort;\n /**\n * Custom options to pass as last parameter of the style function.\n */\n this.styleOptions = Object.assign(Object.assign({}, defaultStyleOptions), ((_j = options.styleOptions) !== null && _j !== void 0 ? _j : {}));\n this.tenant = (_k = options.tenant) !== null && _k !== void 0 ? _k : ''; // sbb,sbh or sbm\n this.trajectories = {};\n this.useDebounce = (_l = options.useDebounce) !== null && _l !== void 0 ? _l : false;\n this.useRequestAnimationFrame = (_m = options.useRequestAnimationFrame) !== null && _m !== void 0 ? _m : false;\n this.useThrottle = options.useThrottle !== false; // the default behavior\n this.getViewState =\n (_o = options.getViewState) !== null && _o !== void 0 ? _o : (() => {\n return {};\n });\n this.shouldRender =\n (_p = options.shouldRender) !== null && _p !== void 0 ? _p : (() => {\n return true;\n });\n this.getRefreshTimeInMs =\n (_q = options.getRefreshTimeInMs) !== null && _q !== void 0 ? _q : this.getRefreshTimeInMs.bind(this);\n this.onRender = options.onRender;\n this.onIdle = options.onIdle;\n this.onStart = options.onStart;\n this.onStop = options.onStop;\n this.format = new GeoJSON();\n // Mots by zoom\n // Server will block non train before zoom 9\n this.motsByZoom = (_r = options.motsByZoom) !== null && _r !== void 0 ? _r : [\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_WITHOUT_CABLE,\n MOTS_WITHOUT_CABLE,\n ];\n this.getMotsByZoom = (zoom) => {\n if (options.getMotsByZoom) {\n return options.getMotsByZoom(zoom, this.motsByZoom);\n }\n if (zoom > this.motsByZoom.length - 1) {\n return this.motsByZoom[this.motsByZoom.length - 1];\n }\n return this.motsByZoom[zoom];\n };\n // Generalization levels by zoom\n this.generalizationLevelByZoom = options.generalizationLevelByZoom || [];\n this.getGeneralizationLevelByZoom = (zoom) => {\n if (options.getGeneralizationLevelByZoom) {\n return options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom);\n }\n if (zoom > this.generalizationLevelByZoom.length - 1) {\n return this.generalizationLevelByZoom[this.generalizationLevelByZoom.length - 1];\n }\n return this.generalizationLevelByZoom[zoom];\n };\n // Graph by zoom\n this.graphByZoom = (_s = options.graphByZoom) !== null && _s !== void 0 ? _s : [];\n this.getGraphByZoom = (zoom) => {\n var _a, _b;\n if (options.getGraphByZoom) {\n return options.getGraphByZoom(zoom, this.graphByZoom);\n }\n if (zoom > this.graphByZoom.length - 1) {\n return (_a = this.graphByZoom) === null || _a === void 0 ? void 0 : _a[this.graphByZoom.length - 1];\n }\n return (_b = this.graphByZoom) === null || _b === void 0 ? void 0 : _b[zoom];\n };\n // Render time interval by zoom\n this.renderTimeIntervalByZoom = options.renderTimeIntervalByZoom || [\n 100000, 50000, 40000, 30000, 20000, 15000, 10000, 5000, 2000, 1000, 400,\n 300, 250, 180, 90, 60, 50, 50, 50, 50, 50,\n ];\n this.getRenderTimeIntervalByZoom = (zoom) => {\n if (options.getRenderTimeIntervalByZoom) {\n return options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom);\n }\n return this.renderTimeIntervalByZoom[zoom];\n };\n // This property will call api.setBbox on each movend event\n this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;\n // Define throttling and debounce render function\n this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });\n this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true, maxWait: 5000, trailing: true });\n this.renderState = {\n center: [0, 0],\n rotation: 0,\n zoom: undefined,\n };\n this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);\n this.onDeleteTrajectoryMessage = this.onDeleteTrajectoryMessage.bind(this);\n this.onDocumentVisibilityChange =\n this.onDocumentVisibilityChange.bind(this);\n }\n /**\n * Add a trajectory.\n * @param {RealtimeTrajectory} trajectory The trajectory to add.\n * @private\n */\n addTrajectory(trajectory) {\n if (!this.trajectories) {\n this.trajectories = {};\n }\n const id = trajectory.properties.train_id;\n if (id !== undefined) {\n this.trajectories[id] = trajectory;\n }\n this.renderTrajectories();\n }\n attachToMap() {\n // To avoid browser hanging when the tab is not visible for a certain amount of time,\n // We stop the rendering and the websocket when hide and start again when show.\n document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);\n }\n detachFromMap() {\n document.removeEventListener('visibilitychange', this.onDocumentVisibilityChange);\n this.stop();\n if (this.canvas) {\n const context = this.canvas.getContext('2d');\n if (context) {\n context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n }\n /**\n * Get the duration before the next update depending on zoom level.\n *\n * @private\n */\n getRefreshTimeInMs() {\n var _a, _b;\n const viewState = this.getViewState();\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;\n const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;\n const nextTick = Math.max(25, timeStep / (this.speed || 1));\n const nextThrottleTick = Math.min(nextTick, 500);\n // TODO: see if this should go elsewhere.\n if (this.useThrottle) {\n this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });\n }\n else if (this.useDebounce) {\n this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, maxWait: 5000, trailing: true });\n }\n if ((_b = this.api) === null || _b === void 0 ? void 0 : _b.buffer) {\n const [, size] = this.api.buffer;\n this.api.buffer = [nextThrottleTick, size];\n }\n return nextTick;\n }\n /**\n * Get vehicle.\n * @param {function} filterFc A function use to filter results.\n * @return {Array} Array of vehicle.\n */\n getVehicles(filterFc) {\n return ((this.trajectories &&\n // @ts-expect-error good type must be defined\n Object.values(this.trajectories).filter(filterFc)) ||\n []);\n }\n /**\n * Request feature information for a given coordinate.\n *\n * @param {ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {Object} options Options See child classes to see which options are supported.\n * @param {number} [options.resolution=1] The resolution of the map.\n * @param {number} [options.nb=Infinity] The max number of vehicles to return.\n * @return {Promise} Promise with features, layer and coordinate.\n */\n getVehiclesAtCoordinate(coordinate, options) {\n const { resolution } = this.getViewState();\n const { hitTolerance, nb } = options || {};\n const extent = buffer([...coordinate, ...coordinate], (hitTolerance !== null && hitTolerance !== void 0 ? hitTolerance : 5) * (resolution !== null && resolution !== void 0 ? resolution : 1));\n let trajectories = Object.values(this.trajectories || {});\n if (this.sort) {\n // @ts-expect-error good type must be defined\n trajectories = trajectories.sort(this.sort);\n }\n const vehicles = [];\n // Theoretically 'for' is faster then 'for-of and it is important here\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < trajectories.length; i += 1) {\n const trajectory = trajectories[i];\n const { coordinate: trajcoord } = trajectory.properties;\n if (trajcoord && containsCoordinate(extent, trajcoord)) {\n vehicles.push(trajectory);\n }\n if (vehicles.length === nb) {\n break;\n }\n }\n return { features: vehicles, type: 'FeatureCollection' };\n }\n /**\n * Callback on websocket's deleted_vehicles channel events.\n * It removes the trajectory from the list.\n *\n * @private\n * @override\n */\n onDeleteTrajectoryMessage(data) {\n if (!data.content) {\n return;\n }\n this.removeTrajectory(data.content);\n }\n onDocumentVisibilityChange() {\n if (document.hidden) {\n this.stop();\n // Since we don't receive deleted_vehicles event when docuement\n // is hidden. We have to clean all the trajectories for a fresh\n // start when the document is visible again.\n this.trajectories = {};\n }\n else {\n const viewState = this.getViewState();\n if (!viewState.visible) {\n return;\n }\n this.start();\n }\n }\n /**\n * Callback on websocket's trajectory channel events.\n * It adds a trajectory to the list.\n *\n * @private\n */\n onTrajectoryMessage(data) {\n this.updateIdleState();\n if (!data.content) {\n return;\n }\n const trajectory = data.content;\n const { geometry, properties: { raw_coordinates: rawCoordinates, time_since_update: timeSinceUpdate, }, } = trajectory;\n // ignore old events [SBAHNM-97]\n // @ts-expect-error can be undefined\n if (timeSinceUpdate < 0) {\n return;\n }\n // console.time(`onTrajectoryMessage${data.content.properties.train_id}`);\n if (this.purgeTrajectory(trajectory)) {\n return;\n }\n if (this.debug &&\n this.mode === RealtimeModes.TOPOGRAPHIC &&\n rawCoordinates) {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry({\n coordinates: fromLonLat(rawCoordinates),\n type: 'Point',\n });\n }\n else {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry(geometry);\n }\n // TODO Make sure the timeOffset is useful. May be we can remove it.\n // @ts-expect-error missing type definition\n trajectory.properties.timeOffset = Date.now() - data.timestamp;\n this.addTrajectory(trajectory);\n }\n /**\n * On zoomend we adjust the time interval of the update of vehicles positions.\n *\n * @private\n */\n onZoomEnd() {\n this.startUpdateTime();\n }\n /**\n * Remove all trajectories that are in the past.\n */\n purgeOutOfDateTrajectories() {\n Object.entries(this.trajectories || {}).forEach(([key, trajectory]) => {\n var _a;\n const timeIntervals = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.time_intervals;\n if (this.time && (timeIntervals === null || timeIntervals === void 0 ? void 0 : timeIntervals.length)) {\n const lastTimeInterval = timeIntervals[timeIntervals.length - 1][0];\n if (lastTimeInterval < this.time.getTime()) {\n this.removeTrajectory(key);\n }\n }\n });\n }\n /**\n * Determine if the trajectory is useless and should be removed from the list or not.\n * By default, this function exclude vehicles:\n * - that have their trajectory outside the current extent and\n * - that aren't in the MOT list.\n *\n * @param {RealtimeTrajectory} trajectory\n * @return {boolean} if the trajectory must be displayed or not.\n * @private\n */\n purgeTrajectory(trajectory) {\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const { bounds, type } = trajectory.properties;\n if ((this.isUpdateBboxOnMoveEnd && extent && !intersects(extent, bounds)) ||\n (this.mots && !this.mots.includes(type))) {\n this.removeTrajectory(trajectory);\n return true;\n }\n return false;\n }\n removeTrajectory(trajectoryOrId) {\n var _a;\n let id;\n if (typeof trajectoryOrId !== 'string') {\n id = (_a = trajectoryOrId === null || trajectoryOrId === void 0 ? void 0 : trajectoryOrId.properties) === null || _a === void 0 ? void 0 : _a.train_id;\n }\n else {\n id = trajectoryOrId;\n }\n if (id !== undefined && this.trajectories) {\n delete this.trajectories[id];\n }\n }\n /**\n * Render the trajectories requesting an animation frame and cancelling the previous one.\n * This function must be overrided by children to provide the correct parameters.\n *\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectories(noInterpolate) {\n const viewState = this.getViewState();\n if (this.requestId) {\n cancelAnimationFrame(this.requestId);\n this.requestId = undefined;\n }\n if (!(viewState === null || viewState === void 0 ? void 0 : viewState.center) || !(viewState === null || viewState === void 0 ? void 0 : viewState.extent) || !(viewState === null || viewState === void 0 ? void 0 : viewState.size)) {\n return;\n }\n if (!noInterpolate && this.useRequestAnimationFrame) {\n this.requestId = requestAnimationFrame(() => {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n });\n }\n else if (!noInterpolate && this.useDebounce) {\n this.debounceRenderTrajectories(viewState, noInterpolate);\n }\n else if (!noInterpolate && this.useThrottle) {\n this.throttleRenderTrajectories(viewState, noInterpolate);\n }\n else {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n }\n }\n /**\n * Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.\n *\n * @param {object} viewState The view state of the map.\n * @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.\n * @param {number[4]} viewState.extent Extent of the map in mercator coordinates.\n * @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.\n * @param {number} [viewState.rotation = 0] Rotation of the map to render.\n * @param {number} viewState.resolution Resolution of the map to render.\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectoriesInternal(viewState, noInterpolate = false) {\n var _a;\n if (!this.trajectories || !this.shouldRender()) {\n return false;\n }\n let time = new Date();\n if (this.live) {\n // Save the time internally, to keep trace of the time rendered for purge.\n this._time = time;\n }\n else if (this.time) {\n time = this.time;\n }\n const trajectories = Object.values(this.trajectories);\n // console.time('sort');\n if (this.sort) {\n // @ts-expect-error type problem\n trajectories.sort(this.sort);\n }\n // console.timeEnd('sort');\n if (!this.canvas || !this.style) {\n return true;\n }\n this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time: time.getTime() }), Object.assign(Object.assign({}, this.styleOptions), { filter: this.filter, hoverVehicleId: this.hoverVehicleId, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation\n ? true\n : noInterpolate, selectedVehicleId: this.selectedVehicleId }));\n (_a = this.onRender) === null || _a === void 0 ? void 0 : _a.call(this, this.renderState, viewState);\n // console.timeEnd('render');\n return true;\n }\n setBbox() {\n var _a;\n this.updateIdleState();\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n if (!extent || Number.isNaN(zoom)) {\n return;\n }\n // Clean trajectories before sending the new bbox\n // Purge trajectories:\n // - which are outside the extent\n // - when it's bus and zoom level is too low for them\n if (this.trajectories && extent && zoom) {\n const keys = Object.keys(this.trajectories);\n for (let i = keys.length - 1; i >= 0; i -= 1) {\n this.purgeTrajectory(this.trajectories[keys[i]]);\n }\n }\n // The backend only supports non float value\n const zoomFloor = Math.floor(zoom);\n if (!extent || Number.isNaN(zoomFloor)) {\n return;\n }\n // The extent does not need to be precise under meter, so we round floor/ceil the values.\n const [minX, minY, maxX, maxY] = extent;\n const bbox = [\n Math.floor(minX),\n Math.floor(minY),\n Math.ceil(maxX),\n Math.ceil(maxY),\n zoomFloor,\n ];\n /* @private */\n this.generalizationLevel = this.getGeneralizationLevelByZoom(zoomFloor);\n if (this.generalizationLevel) {\n bbox.push(`gen=${this.generalizationLevel}`);\n }\n /* @private */\n this.mots = this.getMotsByZoom(zoomFloor);\n if (this.mots) {\n bbox.push(`mots=${this.mots.toString()}`);\n }\n if (this.tenant) {\n bbox.push(`tenant=${this.tenant}`);\n }\n if (this.mode !== 'topographic') {\n bbox.push(`channel_prefix=${this.mode}`);\n }\n const graph = this.getGraphByZoom(zoomFloor);\n if (graph) {\n bbox.push(`graph=${graph}`);\n }\n if (this.bboxParameters) {\n Object.entries(this.bboxParameters).forEach(([key, value]) => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n bbox.push(`${key}=${value}`);\n });\n }\n // Extent and zoom level are mandatory.\n this.api.bbox = bbox;\n }\n start() {\n this.stop();\n // Before starting to update trajectories, we remove trajectories that have\n // a time_intervals in the past, it will\n // avoid phantom train that are at the end of their route because we never\n // received the deleted_vehicle event because we have changed the browser tab.\n this.purgeOutOfDateTrajectories();\n this.renderTrajectories();\n this.startUpdateTime();\n this.api.open();\n this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n // Update the bbox on each move end\n if (this.isUpdateBboxOnMoveEnd) {\n this.setBbox();\n }\n if (this.onStart) {\n this.onStart(this);\n }\n }\n /**\n * Start the clock.\n * @private\n */\n startUpdateTime() {\n this.stopUpdateTime();\n this.updateTimeDelay = this.getRefreshTimeInMs() || 0;\n this.updateTimeInterval = window.setInterval(() => {\n // When live=true, we update the time with new Date();\n if (this.live) {\n this.time = new Date();\n }\n else if (this.time && this.updateTimeDelay && this.speed) {\n this.time = new Date(this.time.getTime() + this.updateTimeDelay * this.speed);\n }\n }, this.updateTimeDelay);\n }\n stop() {\n this.api.unsubscribeTrajectory(this.onTrajectoryMessage);\n this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);\n this.api.close();\n if (this.onStop) {\n this.onStop(this);\n }\n }\n /**\n * Stop the clock.\n * @private\n */\n stopUpdateTime() {\n if (this.updateTimeInterval) {\n clearInterval(this.updateTimeInterval);\n this.updateTimeInterval = undefined;\n }\n }\n updateIdleState() {\n this.isIdle = false;\n clearTimeout(this._idleTimeout);\n this._idleTimeout = window.setTimeout(() => {\n var _a;\n this.isIdle = true;\n (_a = this.onIdle) === null || _a === void 0 ? void 0 : _a.call(this, this);\n }, 1000);\n }\n}\nexport default RealtimeEngine;\n", @@ -6156,7 +6371,7 @@ "lineNumber": 1 }, { - "__docId__": 265, + "__docId__": 273, "kind": "variable", "name": "defaultStyleOptions", "memberof": "build/common/utils/RealtimeEngine.js", @@ -6175,7 +6390,7 @@ } }, { - "__docId__": 266, + "__docId__": 274, "kind": "class", "name": "RealtimeEngine", "memberof": "build/common/utils/RealtimeEngine.js", @@ -6190,7 +6405,7 @@ "interface": false }, { - "__docId__": 267, + "__docId__": 275, "kind": "get", "name": "mode", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6209,7 +6424,7 @@ } }, { - "__docId__": 268, + "__docId__": 276, "kind": "set", "name": "mode", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6223,7 +6438,7 @@ "undocument": true }, { - "__docId__": 269, + "__docId__": 277, "kind": "member", "name": "_mode", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6240,7 +6455,7 @@ } }, { - "__docId__": 270, + "__docId__": 278, "kind": "get", "name": "speed", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6259,7 +6474,7 @@ } }, { - "__docId__": 271, + "__docId__": 279, "kind": "set", "name": "speed", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6273,7 +6488,7 @@ "undocument": true }, { - "__docId__": 272, + "__docId__": 280, "kind": "member", "name": "_speed", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6290,7 +6505,7 @@ } }, { - "__docId__": 273, + "__docId__": 281, "kind": "get", "name": "style", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6309,7 +6524,7 @@ } }, { - "__docId__": 274, + "__docId__": 282, "kind": "set", "name": "style", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6323,7 +6538,7 @@ "undocument": true }, { - "__docId__": 275, + "__docId__": 283, "kind": "member", "name": "_style", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6340,7 +6555,7 @@ } }, { - "__docId__": 276, + "__docId__": 284, "kind": "get", "name": "time", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6359,7 +6574,7 @@ } }, { - "__docId__": 277, + "__docId__": 285, "kind": "set", "name": "time", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6373,7 +6588,7 @@ "undocument": true }, { - "__docId__": 278, + "__docId__": 286, "kind": "member", "name": "_time", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6390,7 +6605,7 @@ } }, { - "__docId__": 279, + "__docId__": 287, "kind": "constructor", "name": "constructor", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6404,7 +6619,7 @@ "undocument": true }, { - "__docId__": 280, + "__docId__": 288, "kind": "member", "name": "isIdle", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6421,7 +6636,7 @@ } }, { - "__docId__": 281, + "__docId__": 289, "kind": "member", "name": "getViewState", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6438,7 +6653,7 @@ } }, { - "__docId__": 282, + "__docId__": 290, "kind": "member", "name": "shouldRender", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6455,7 +6670,7 @@ } }, { - "__docId__": 287, + "__docId__": 295, "kind": "member", "name": "api", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6472,7 +6687,7 @@ } }, { - "__docId__": 288, + "__docId__": 296, "kind": "member", "name": "bboxParameters", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6489,7 +6704,7 @@ } }, { - "__docId__": 289, + "__docId__": 297, "kind": "member", "name": "canvas", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6506,7 +6721,7 @@ } }, { - "__docId__": 290, + "__docId__": 298, "kind": "member", "name": "debug", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6523,7 +6738,7 @@ } }, { - "__docId__": 291, + "__docId__": 299, "kind": "member", "name": "filter", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6540,7 +6755,7 @@ } }, { - "__docId__": 292, + "__docId__": 300, "kind": "member", "name": "hoverVehicleId", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6557,7 +6772,7 @@ } }, { - "__docId__": 293, + "__docId__": 301, "kind": "member", "name": "live", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6573,7 +6788,7 @@ } }, { - "__docId__": 294, + "__docId__": 302, "kind": "member", "name": "minZoomInterpolation", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6590,7 +6805,7 @@ } }, { - "__docId__": 295, + "__docId__": 303, "kind": "member", "name": "pixelRatio", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6607,7 +6822,7 @@ } }, { - "__docId__": 296, + "__docId__": 304, "kind": "member", "name": "selectedVehicleId", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6624,7 +6839,7 @@ } }, { - "__docId__": 297, + "__docId__": 305, "kind": "member", "name": "sort", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6641,7 +6856,7 @@ } }, { - "__docId__": 298, + "__docId__": 306, "kind": "member", "name": "styleOptions", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6657,7 +6872,7 @@ } }, { - "__docId__": 299, + "__docId__": 307, "kind": "member", "name": "tenant", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6674,7 +6889,7 @@ } }, { - "__docId__": 300, + "__docId__": 308, "kind": "member", "name": "trajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6691,7 +6906,7 @@ } }, { - "__docId__": 301, + "__docId__": 309, "kind": "member", "name": "useDebounce", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6708,7 +6923,7 @@ } }, { - "__docId__": 302, + "__docId__": 310, "kind": "member", "name": "useRequestAnimationFrame", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6725,7 +6940,7 @@ } }, { - "__docId__": 303, + "__docId__": 311, "kind": "member", "name": "useThrottle", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6742,7 +6957,7 @@ } }, { - "__docId__": 307, + "__docId__": 315, "kind": "member", "name": "onRender", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6759,7 +6974,7 @@ } }, { - "__docId__": 308, + "__docId__": 316, "kind": "member", "name": "onIdle", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6776,7 +6991,7 @@ } }, { - "__docId__": 309, + "__docId__": 317, "kind": "member", "name": "onStart", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6793,7 +7008,7 @@ } }, { - "__docId__": 310, + "__docId__": 318, "kind": "member", "name": "onStop", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6810,7 +7025,7 @@ } }, { - "__docId__": 311, + "__docId__": 319, "kind": "member", "name": "format", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6827,7 +7042,7 @@ } }, { - "__docId__": 312, + "__docId__": 320, "kind": "member", "name": "motsByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6844,7 +7059,7 @@ } }, { - "__docId__": 313, + "__docId__": 321, "kind": "member", "name": "getMotsByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6861,7 +7076,7 @@ } }, { - "__docId__": 314, + "__docId__": 322, "kind": "member", "name": "generalizationLevelByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6878,7 +7093,7 @@ } }, { - "__docId__": 315, + "__docId__": 323, "kind": "member", "name": "getGeneralizationLevelByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6895,7 +7110,7 @@ } }, { - "__docId__": 316, + "__docId__": 324, "kind": "member", "name": "graphByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6912,7 +7127,7 @@ } }, { - "__docId__": 317, + "__docId__": 325, "kind": "member", "name": "getGraphByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6929,7 +7144,7 @@ } }, { - "__docId__": 318, + "__docId__": 326, "kind": "member", "name": "renderTimeIntervalByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6946,7 +7161,7 @@ } }, { - "__docId__": 319, + "__docId__": 327, "kind": "member", "name": "getRenderTimeIntervalByZoom", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6963,7 +7178,7 @@ } }, { - "__docId__": 320, + "__docId__": 328, "kind": "member", "name": "isUpdateBboxOnMoveEnd", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6980,7 +7195,7 @@ } }, { - "__docId__": 321, + "__docId__": 329, "kind": "member", "name": "throttleRenderTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -6997,7 +7212,7 @@ } }, { - "__docId__": 322, + "__docId__": 330, "kind": "member", "name": "debounceRenderTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7014,7 +7229,7 @@ } }, { - "__docId__": 323, + "__docId__": 331, "kind": "member", "name": "renderState", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7031,7 +7246,7 @@ } }, { - "__docId__": 327, + "__docId__": 335, "kind": "method", "name": "addTrajectory", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7057,7 +7272,7 @@ "return": null }, { - "__docId__": 329, + "__docId__": 337, "kind": "method", "name": "attachToMap", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7073,7 +7288,7 @@ "return": null }, { - "__docId__": 330, + "__docId__": 338, "kind": "method", "name": "detachFromMap", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7089,7 +7304,7 @@ "return": null }, { - "__docId__": 331, + "__docId__": 339, "kind": "method", "name": "getRefreshTimeInMs", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7108,7 +7323,7 @@ } }, { - "__docId__": 334, + "__docId__": 342, "kind": "method", "name": "getVehicles", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7141,7 +7356,7 @@ } }, { - "__docId__": 335, + "__docId__": 343, "kind": "method", "name": "getVehiclesAtCoordinate", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7208,7 +7423,7 @@ } }, { - "__docId__": 336, + "__docId__": 344, "kind": "method", "name": "onDeleteTrajectoryMessage", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7231,7 +7446,7 @@ "return": null }, { - "__docId__": 337, + "__docId__": 345, "kind": "method", "name": "onDocumentVisibilityChange", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7247,7 +7462,7 @@ "return": null }, { - "__docId__": 339, + "__docId__": 347, "kind": "method", "name": "onTrajectoryMessage", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7269,7 +7484,7 @@ "return": null }, { - "__docId__": 340, + "__docId__": 348, "kind": "method", "name": "onZoomEnd", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7284,7 +7499,7 @@ "return": null }, { - "__docId__": 341, + "__docId__": 349, "kind": "method", "name": "purgeOutOfDateTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7299,7 +7514,7 @@ "return": null }, { - "__docId__": 342, + "__docId__": 350, "kind": "method", "name": "purgeTrajectory", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7332,7 +7547,7 @@ } }, { - "__docId__": 343, + "__docId__": 351, "kind": "method", "name": "removeTrajectory", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7355,7 +7570,7 @@ "return": null }, { - "__docId__": 344, + "__docId__": 352, "kind": "method", "name": "renderTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7381,7 +7596,7 @@ "return": null }, { - "__docId__": 345, + "__docId__": 353, "kind": "member", "name": "requestId", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7398,7 +7613,7 @@ } }, { - "__docId__": 347, + "__docId__": 355, "kind": "method", "name": "renderTrajectoriesInternal", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7490,7 +7705,7 @@ } }, { - "__docId__": 350, + "__docId__": 358, "kind": "method", "name": "setBbox", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7506,7 +7721,7 @@ "return": null }, { - "__docId__": 351, + "__docId__": 359, "kind": "member", "name": "generalizationLevel", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7523,7 +7738,7 @@ } }, { - "__docId__": 352, + "__docId__": 360, "kind": "member", "name": "mots", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7540,7 +7755,7 @@ } }, { - "__docId__": 353, + "__docId__": 361, "kind": "method", "name": "start", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7556,7 +7771,7 @@ "return": null }, { - "__docId__": 354, + "__docId__": 362, "kind": "method", "name": "startUpdateTime", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7571,7 +7786,7 @@ "return": null }, { - "__docId__": 355, + "__docId__": 363, "kind": "member", "name": "updateTimeDelay", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7588,7 +7803,7 @@ } }, { - "__docId__": 356, + "__docId__": 364, "kind": "member", "name": "updateTimeInterval", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7605,7 +7820,7 @@ } }, { - "__docId__": 359, + "__docId__": 367, "kind": "method", "name": "stop", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7621,7 +7836,7 @@ "return": null }, { - "__docId__": 360, + "__docId__": 368, "kind": "method", "name": "stopUpdateTime", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7636,7 +7851,7 @@ "return": null }, { - "__docId__": 362, + "__docId__": 370, "kind": "method", "name": "updateIdleState", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7652,7 +7867,7 @@ "return": null }, { - "__docId__": 364, + "__docId__": 372, "kind": "member", "name": "_idleTimeout", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7669,7 +7884,7 @@ } }, { - "__docId__": 366, + "__docId__": 374, "kind": "file", "name": "build/common/utils/compareDepartures.js", "content": "/**\n * Compare two given departures for sort alogithm,\n * @param {RealtimeDeparture} a First departure.\n * @param {RealtimeDeparture} b Second departure.\n * @param {boolean} [sortByMinArrivalTime=false] Sort departures by arrival time.\n * @private\n */\nconst compareDepartures = (a, b, sortByMinArrivalTime = false) => {\n // First LEAVING and HIDDEN, then BOARDING and then sorted by time.\n const topStates = ['HIDDEN', 'LEAVING', 'BOARDING'];\n const aTop = a.has_fzo && topStates.includes(a.state);\n const bTop = b.has_fzo && topStates.includes(b.state);\n if (aTop || bTop) {\n if (aTop !== bTop) {\n return aTop ? -1 : 1;\n }\n if (a.state !== b.state) {\n // one is leaving\n return topStates.indexOf(a.state) - topStates.indexOf(b.state);\n }\n }\n let aDuration = null;\n let bDuration = null;\n const now = Date.now();\n if (sortByMinArrivalTime) {\n const aTime = a.min_arrival_time || a.time;\n const bTime = b.min_arrival_time || b.time;\n if (!aTime && !bTime) {\n return 0;\n }\n if (!aTime) {\n return 1;\n }\n if (!bTime) {\n return -1;\n }\n if (aTime && bTime) {\n aDuration = new Date(aTime).getTime() - now;\n bDuration = new Date(bTime).getTime() - now;\n }\n }\n else {\n if (!a.time && !b.time) {\n return 0;\n }\n if (!a.time) {\n return 1;\n }\n if (!b.time) {\n return -1;\n }\n if (a.time && b.time) {\n aDuration = new Date(a.time).getTime() - now;\n bDuration = new Date(b.time).getTime() - now;\n }\n }\n if (!aDuration && !bDuration) {\n return 0;\n }\n if (!aDuration) {\n return 1;\n }\n if (!bDuration) {\n return -1;\n }\n return aDuration - bDuration;\n};\nexport default compareDepartures;\n", @@ -7680,7 +7895,7 @@ "lineNumber": 1 }, { - "__docId__": 367, + "__docId__": 375, "kind": "function", "name": "compareDepartures", "memberof": "build/common/utils/compareDepartures.js", @@ -7735,7 +7950,7 @@ } }, { - "__docId__": 368, + "__docId__": 376, "kind": "file", "name": "build/common/utils/constants.js", "content": "export const VECTOR_TILE_FEATURE_PROPERTY = 'vectorTileFeature';\nexport default {\n VECTOR_TILE_FEATURE_PROPERTY,\n};\n", @@ -7746,7 +7961,7 @@ "lineNumber": 1 }, { - "__docId__": 369, + "__docId__": 377, "kind": "variable", "name": "VECTOR_TILE_FEATURE_PROPERTY", "memberof": "build/common/utils/constants.js", @@ -7766,7 +7981,7 @@ } }, { - "__docId__": 370, + "__docId__": 378, "kind": "file", "name": "build/common/utils/createCanvas.js", "content": "/**\n * This function try to create a canvas element and return it.\n * it uses document.createElement('canvas') if document is available\n * or new OffscreenCanvas(width, height) if OffscreenCanvas is avalaible (for web worker)\n * or it returns null if neither is available.\n * @private\n */\nconst createCanvas = (width, height) => {\n let canvas = null;\n // Prevent SSR errors\n if (typeof window === 'undefined') {\n return null;\n }\n if (typeof document !== 'undefined' && (document === null || document === void 0 ? void 0 : document.createElement)) {\n canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n }\n else if (OffscreenCanvas) {\n canvas = new OffscreenCanvas(width, height);\n }\n else {\n // eslint-disable-next-line no-console\n console.error(\"We didn't find a way to create a canvas element, document.createElement('canvas') and new OffscrenCanvas() are not supported\");\n }\n return canvas;\n};\nexport default createCanvas;\n", @@ -7777,7 +7992,7 @@ "lineNumber": 1 }, { - "__docId__": 371, + "__docId__": 379, "kind": "function", "name": "createCanvas", "memberof": "build/common/utils/createCanvas.js", @@ -7812,7 +8027,7 @@ } }, { - "__docId__": 372, + "__docId__": 380, "kind": "file", "name": "build/common/utils/createDefaultCopyrightElt.js", "content": "/**\n * @private\n */\nconst createDefaultCopyrightElement = () => {\n const element = document.createElement('div');\n Object.assign(element.style, {\n bottom: 0,\n fontSize: '.8rem',\n padding: '0 10px',\n position: 'absolute',\n right: 0,\n });\n return element;\n};\nexport default createDefaultCopyrightElement;\n", @@ -7823,7 +8038,7 @@ "lineNumber": 1 }, { - "__docId__": 373, + "__docId__": 381, "kind": "function", "name": "createDefaultCopyrightElement", "memberof": "build/common/utils/createDefaultCopyrightElt.js", @@ -7845,7 +8060,7 @@ } }, { - "__docId__": 374, + "__docId__": 382, "kind": "file", "name": "build/common/utils/createDefaultStopFinderElt.js", "content": "/**\n * @private\n */\nconst createDefaultStopFinderElement = () => {\n const element = document.createElement('div');\n Object.assign(element.style, {\n display: 'flex',\n flexDirection: 'column',\n left: '50px',\n margin: '10px',\n maxHeight: '90%',\n position: 'absolute',\n top: 0,\n width: '320px',\n });\n return element;\n};\nexport default createDefaultStopFinderElement;\n", @@ -7856,7 +8071,7 @@ "lineNumber": 1 }, { - "__docId__": 375, + "__docId__": 383, "kind": "function", "name": "createDefaultStopFinderElement", "memberof": "build/common/utils/createDefaultStopFinderElt.js", @@ -7878,10 +8093,10 @@ } }, { - "__docId__": 376, + "__docId__": 384, "kind": "file", "name": "build/common/utils/createRealtimeFilters.js", - "content": "/**\n * Return a filter functions based on some parameters of a vehicle.\n *\n * @param {string|Array} line - A list of vehicle's name to filter. Names can be separated by a comma. Ex: 'S1,S2,S3'\n * @param {string|Array {\n const filterList = [];\n if (!line && !route && !operator && !regexLine) {\n return null;\n }\n if (regexLine) {\n const regexLineList = typeof regexLine === 'string' ? [regexLine] : regexLine;\n const lineFilter = (item) => {\n var _a;\n const name = item.properties.name || ((_a = item.properties.line) === null || _a === void 0 ? void 0 : _a.name) || '';\n if (!name) {\n return false;\n }\n return regexLineList.some((regexStr) => {\n return new RegExp(regexStr, 'i').test(name);\n });\n };\n filterList.push(lineFilter);\n }\n if (line) {\n const lineFiltersList = typeof line === 'string' ? line.split(',') : line;\n const lineList = lineFiltersList.map((l) => {\n return l.replace(/\\s+/g, '').toUpperCase();\n });\n const lineFilter = (item) => {\n const { line: linee, name } = item.properties;\n const lineName = (name || (linee === null || linee === void 0 ? void 0 : linee.name) || '').toUpperCase();\n if (!lineName) {\n return false;\n }\n return lineList.includes(lineName);\n };\n filterList.push(lineFilter);\n }\n if (route) {\n const routes = typeof route === 'string' ? route.split(',') : route;\n const routeList = routes.map((item) => {\n return parseInt(item, 10);\n });\n const routeFilter = (item) => {\n const routeIdentifier = item.properties.route_identifier ||\n item.properties.routeIdentifier ||\n '';\n const routeId = parseInt(routeIdentifier.split('.')[0], 10);\n return routeList.includes(routeId);\n };\n filterList.push(routeFilter);\n }\n if (operator) {\n const operatorList = typeof operator === 'string' ? [operator] : operator;\n const operatorFilter = (item) => {\n return operatorList.some((op) => {\n // operaotr is the old property tenant is the new one\n const tenant = item.properties.operator || item.properties.tenant || '';\n return new RegExp(op, 'i').test(tenant);\n });\n };\n filterList.push(operatorFilter);\n }\n if (!filterList.length) {\n return null;\n }\n return (item) => {\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < filterList.length; i += 1) {\n if (!filterList[i](item)) {\n return false;\n }\n }\n return true;\n };\n};\nexport default createRealtimeFilters;\n", + "content": "/**\n * Return a filter functions based on some parameters of a vehicle.\n *\n * @param {string|Array} line - A list of vehicle's name to filter. Names can be separated by a comma. Ex: 'S1,S2,S3'\n * @param {string|Array {\n const filterList = [];\n if (!line && !route && !operator && !regexLine) {\n return null;\n }\n if (regexLine) {\n const regexLineList = typeof regexLine === 'string' ? [regexLine] : regexLine;\n const lineFilter = (item) => {\n var _a;\n const name = item.properties.name || ((_a = item.properties.line) === null || _a === void 0 ? void 0 : _a.name) || '';\n if (!name) {\n return false;\n }\n return regexLineList.some((regexStr) => {\n return new RegExp(regexStr, 'i').test(name);\n });\n };\n filterList.push(lineFilter);\n }\n if (line) {\n const lineFiltersList = typeof line === 'string' ? line.split(',') : line;\n const lineList = lineFiltersList.map((l) => {\n return l.replace(/\\s+/g, '').toUpperCase();\n });\n const lineFilter = (item) => {\n const { line: linee, name } = item.properties;\n const lineName = (name || (linee === null || linee === void 0 ? void 0 : linee.name) || '').toUpperCase();\n if (!lineName) {\n return false;\n }\n return lineList.includes(lineName);\n };\n filterList.push(lineFilter);\n }\n if (route) {\n const routes = typeof route === 'string' ? route.split(',') : route;\n const routeList = routes.map((item) => {\n return parseInt(item, 10);\n });\n const routeFilter = (item) => {\n const routeIdentifier = item.properties.route_identifier || '';\n const routeId = parseInt(routeIdentifier.split('.')[0], 10);\n return routeList.includes(routeId);\n };\n filterList.push(routeFilter);\n }\n if (operator) {\n const operatorList = typeof operator === 'string' ? [operator] : operator;\n const operatorFilter = (item) => {\n return operatorList.some((op) => {\n // operaotr is the old property tenant is the new one\n const tenant = item.properties.operator || item.properties.tenant || '';\n return new RegExp(op, 'i').test(tenant);\n });\n };\n filterList.push(operatorFilter);\n }\n if (!filterList.length) {\n return null;\n }\n return (item) => {\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < filterList.length; i += 1) {\n if (!filterList[i](item)) {\n return false;\n }\n }\n return true;\n };\n};\nexport default createRealtimeFilters;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/createRealtimeFilters.js", "access": "private", @@ -7889,7 +8104,7 @@ "lineNumber": 1 }, { - "__docId__": 377, + "__docId__": 385, "kind": "function", "name": "createRealtimeFilters", "memberof": "build/common/utils/createRealtimeFilters.js", @@ -7955,7 +8170,7 @@ } }, { - "__docId__": 378, + "__docId__": 386, "kind": "file", "name": "build/common/utils/debounceDeparturesMessages.js", "content": "import sortAndFilterDepartures from './sortAndFilterDepartures';\n/**\n * This function returns a WebSocket api callback, and call the onDeparturesUpdate function with the list of current departures to display.\n * @param {function(departures: RealtimeDeparture[])} onDeparturesUpdate callback when list of departures changes, called after 100 ms\n * @param {boolean} [sortByMinArrivalTime = true] Sort departures by arrival time\n * @param {number} [maxDepartureAge = 30] max departure age of departures in minutes\n * @param {number} [timeout = 100] debounce timeout in ms\n * @private\n */\nconst debounceDeparturesMessages = (onDeparturesUpdate, sortByMinArrivalTime = false, maxDepartureAge = 30, timeout = 100) => {\n const departureUpdateTimeout = {};\n const departureObject = {};\n return (data) => {\n const { content: departure, source } = data;\n if (departureUpdateTimeout[source]) {\n window.clearTimeout(departureUpdateTimeout[source]);\n }\n if (!departure) {\n return;\n }\n departureObject[departure.call_id] = departure;\n departureUpdateTimeout[source] = window.setTimeout(() => {\n const departures = sortAndFilterDepartures(departureObject, sortByMinArrivalTime || false, maxDepartureAge);\n onDeparturesUpdate(departures);\n }, timeout);\n };\n};\nexport default debounceDeparturesMessages;\n", @@ -7966,7 +8181,7 @@ "lineNumber": 1 }, { - "__docId__": 379, + "__docId__": 387, "kind": "function", "name": "debounceDeparturesMessages", "memberof": "build/common/utils/debounceDeparturesMessages.js", @@ -8035,7 +8250,7 @@ } }, { - "__docId__": 380, + "__docId__": 388, "kind": "file", "name": "build/common/utils/debounceWebsocketMessages.js", "content": "/**\n * This function returns a WebSocket api callback, and call the onUpdate function with the list of of subscribed objects changes.\n *\n * @param {function(objects: any[])} onUpdate callback when list of subscribed objects changes, called after 100 ms\n * @param {function(object: any)} [getObjectId = true] function returning the id of an object\n * @param {number} [timeout = 100] debounce timeout in ms\n * @private\n */\nconst debounceWebsocketMessages = (onUpdate, getObjectId, timeout = 100) => {\n const updateTimeout = {};\n const objectsById = {};\n const objects = [];\n return (data) => {\n const { content, source } = data;\n if (updateTimeout[source]) {\n window.clearTimeout(updateTimeout[source]);\n }\n if (getObjectId) {\n objectsById[getObjectId(content)] = content;\n }\n else {\n objects.push(content);\n }\n updateTimeout[source] = window.setTimeout(() => {\n const objectToReturn = getObjectId ? Object.values(objectsById) : objects;\n onUpdate(objectToReturn);\n }, timeout);\n };\n};\nexport default debounceWebsocketMessages;\n", @@ -8046,7 +8261,7 @@ "lineNumber": 1 }, { - "__docId__": 381, + "__docId__": 389, "kind": "function", "name": "debounceWebsocketMessages", "memberof": "build/common/utils/debounceWebsocketMessages.js", @@ -8103,7 +8318,7 @@ } }, { - "__docId__": 382, + "__docId__": 390, "kind": "file", "name": "build/common/utils/getLayersAsFlatArray.js", "content": "const getLayersAsFlatArray = (layersOrLayer) => {\n let layers = layersOrLayer;\n if (!Array.isArray(layers)) {\n layers = [layersOrLayer];\n }\n let flatLayers = [];\n layers.forEach((layer) => {\n var _a, _b, _c;\n flatLayers.push(layer);\n // Handle children property and ol.layer.Group\n const children = \n // @ts-expect-error children is deprecated\n layer.children ||\n layer.get('children') ||\n ((_c = (_b = (_a = layer).getLayers) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.getArray());\n flatLayers = flatLayers.concat(getLayersAsFlatArray(children || []));\n });\n return flatLayers;\n};\nexport default getLayersAsFlatArray;\n", @@ -8114,7 +8329,7 @@ "lineNumber": 1 }, { - "__docId__": 383, + "__docId__": 391, "kind": "function", "name": "getLayersAsFlatArray", "memberof": "build/common/utils/getLayersAsFlatArray.js", @@ -8144,10 +8359,10 @@ } }, { - "__docId__": 384, + "__docId__": 392, "kind": "file", "name": "build/common/utils/getMapGlCopyrights.js", - "content": "import removeDuplicate from './removeDuplicate';\n/**\n * Return the copyright a Maplibre map.\n * @param {maplibregl.Map} map A Maplibre map\n * @private\n */\nconst getMapGlCopyrights = (map) => {\n if (!map) {\n return [];\n }\n const { style } = map;\n if (!style) {\n return [];\n }\n const { sourceCaches } = style;\n let copyrights = [];\n Object.values(sourceCaches).forEach((value) => {\n var _a;\n if (value.used) {\n const source = value.getSource();\n const attribution = (source === null || source === void 0 ? void 0 : source.attribution) ||\n ((_a = source.options) === null || _a === void 0 ? void 0 : _a.attribution);\n if (attribution) {\n copyrights = copyrights.concat(attribution.replace(/©/g, '©').split(/()/));\n }\n }\n });\n return removeDuplicate(copyrights);\n};\nexport default getMapGlCopyrights;\n", + "content": "import removeDuplicate from './removeDuplicate';\n/**\n * Return the copyright a Maplibre map.\n * @param {maplibregl.Map} map A Maplibre map\n * @private\n */\nconst getMapGlCopyrights = (map) => {\n if (!map) {\n return [];\n }\n const { style } = map;\n if (!style) {\n return [];\n }\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n const { sourceCaches, tileManagers } = style;\n let copyrights = [];\n const sourceCacheObj = tileManagers || sourceCaches || {};\n Object.values(sourceCacheObj).forEach((value) => {\n var _a;\n if (value.used) {\n const source = value.getSource();\n const attribution = (source === null || source === void 0 ? void 0 : source.attribution) ||\n ((_a = source.options) === null || _a === void 0 ? void 0 : _a.attribution);\n if (attribution) {\n copyrights = copyrights.concat(attribution.replace(/©/g, '©').split(/()/));\n }\n }\n });\n return removeDuplicate(copyrights);\n};\nexport default getMapGlCopyrights;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/getMapGlCopyrights.js", "access": "private", @@ -8155,7 +8370,7 @@ "lineNumber": 1 }, { - "__docId__": 385, + "__docId__": 393, "kind": "function", "name": "getMapGlCopyrights", "memberof": "build/common/utils/getMapGlCopyrights.js", @@ -8188,7 +8403,7 @@ } }, { - "__docId__": 386, + "__docId__": 394, "kind": "file", "name": "build/common/utils/getRealtimeModeSuffix.js", "content": "/**\n * Get the websocket channel suffix, depending on the current mode.\n * @param {String} mode Mode 'topographic' ou 'schematic'.\n * @param {String[]} modes List of modes\n * @private\n */\nconst getModeSuffix = (mode, modes) => {\n return mode === modes.SCHEMATIC ? '_schematic' : '';\n};\nexport default getModeSuffix;\n", @@ -8199,7 +8414,7 @@ "lineNumber": 1 }, { - "__docId__": 387, + "__docId__": 395, "kind": "function", "name": "getModeSuffix", "memberof": "build/common/utils/getRealtimeModeSuffix.js", @@ -8242,7 +8457,7 @@ } }, { - "__docId__": 388, + "__docId__": 396, "kind": "file", "name": "build/common/utils/getUrlWithParams.js", "content": "/**\n * Return the styleUrl with apiKey parameters set.\n * @param {string} url a url.\n * @param {Object} params a list of key/value pair to add to the url.\n * @private\n */\nconst getUrlWithParams = (url, params) => {\n // Clean requets parameters, removing undefined and null values.\n const newUrl = new URL(url);\n const searchParams = params || {};\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n newUrl.searchParams.set(key, value);\n }\n });\n return newUrl;\n};\nexport default getUrlWithParams;\n", @@ -8253,7 +8468,7 @@ "lineNumber": 1 }, { - "__docId__": 389, + "__docId__": 397, "kind": "function", "name": "getUrlWithParams", "memberof": "build/common/utils/getUrlWithParams.js", @@ -8296,7 +8511,71 @@ } }, { - "__docId__": 390, + "__docId__": 398, + "kind": "file", + "name": "build/common/utils/getUrlWithPath.js", + "content": "/**\n * Concatenate an url with a path to avoid double slash.\n * @param {string} url a url.\n * @param {string} path a path.\n * @param {Object} params a list of key/value pair to add to the url.\n * @private\n */\nconst getUrlWithPath = (url, path) => {\n const urlObj = new URL(url);\n let newUrl = url;\n let newPath = path;\n if (urlObj.searchParams.size > 0) {\n newUrl = url.split('?')[0];\n }\n if (!newUrl.endsWith('/')) {\n newUrl = `${newUrl}/`;\n }\n if (newPath === null || newPath === void 0 ? void 0 : newPath.startsWith('/')) {\n newPath = newPath.substring(1);\n }\n return newUrl + (newPath !== null && newPath !== void 0 ? newPath : '');\n};\nexport default getUrlWithPath;\n", + "static": true, + "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/getUrlWithPath.js", + "access": "private", + "description": null, + "lineNumber": 1 + }, + { + "__docId__": 399, + "kind": "function", + "name": "getUrlWithPath", + "memberof": "build/common/utils/getUrlWithPath.js", + "generator": false, + "async": false, + "static": true, + "longname": "build/common/utils/getUrlWithPath.js~getUrlWithPath", + "access": "private", + "export": true, + "importPath": "mobility-toolbox-js/build/common/utils/getUrlWithPath.js", + "importStyle": "getUrlWithPath", + "description": "Concatenate an url with a path to avoid double slash.", + "lineNumber": 8, + "params": [ + { + "nullable": null, + "types": [ + "string" + ], + "spread": false, + "optional": false, + "name": "url", + "description": "a url." + }, + { + "nullable": null, + "types": [ + "string" + ], + "spread": false, + "optional": false, + "name": "path", + "description": "a path." + }, + { + "nullable": null, + "types": [ + "Object" + ], + "spread": false, + "optional": false, + "name": "params", + "description": "a list of key/value pair to add to the url." + } + ], + "return": { + "types": [ + "*" + ] + } + }, + { + "__docId__": 400, "kind": "file", "name": "build/common/utils/getVehiclePosition.js", "content": "import { LineString } from 'ol/geom';\n/**\n * Interpolate or not the vehicle position from a trajectory at a specific date.\n *\n * @param {number} now Current date to interpolate a position with. In ms.\n * @param {RealtimeTrajectory} trajectory The trajectory to interpolate.\n * @param {boolean} noInterpolate If true, the vehicle position is not interpolated on each render but only once.\n * @returns {VehiclePosition}\n * @private\n */\nconst getVehiclePosition = (now, trajectory, noInterpolate) => {\n var _a;\n const { coordinate, olGeometry, rotation: oldRotation, time_intervals: timeIntervals, } = trajectory.properties;\n let { coordinates, type } = trajectory.geometry;\n let geometry = olGeometry;\n let coord;\n let rotation = oldRotation;\n // If an olGeometry exists we use it. It avoids to create one each time.\n if (geometry) {\n // @ts-expect-error improve types\n type = geometry.getType();\n coordinates = (_a = geometry.getCoordinates()) !== null && _a !== void 0 ? _a : [];\n }\n if (noInterpolate && coordinate) {\n coord = coordinate;\n }\n else if (type === 'Point') {\n coord = coordinates;\n }\n else if (type === 'LineString') {\n geometry !== null && geometry !== void 0 ? geometry : (geometry = new LineString(coordinates));\n const intervals = timeIntervals || [[]];\n const firstInterval = intervals[0];\n const lastInterval = intervals[intervals.length - 1];\n // Between the last time interval of a trajectory event and the beginning\n // of the new trajectory event, there is few seconds, can be 6 to 30\n // seconds (that's why the vehicle jumps sometimes).\n // So we make the choice here to display the last (or the first) position\n // of an trajectory event instead of removing them, if the current date is\n // outside the time intervals we display the vehicle at the last (or first) position known.\n if (now < firstInterval[0]) {\n // Display first position known.\n [, , rotation] = firstInterval;\n coord = geometry.getFirstCoordinate();\n }\n else if (now > lastInterval[0]) {\n // Display last position known.\n [, , rotation] = lastInterval;\n coord = geometry.getLastCoordinate();\n }\n else {\n // Interpolate position using time intervals.\n for (let j = 0; j < intervals.length - 1; j += 1) {\n // Rotation only available in realtime layer.\n const [start, startFrac] = intervals[j];\n const [end, endFrac] = intervals[j + 1];\n if (start <= now && now <= end) {\n // interpolate position inside the time interval.\n const timeFrac = Math.min((now - start) / (end - start), 1);\n const geomFrac = timeFrac * (endFrac - startFrac) + startFrac;\n coord = geometry === null || geometry === void 0 ? void 0 : geometry.getCoordinateAt(geomFrac);\n [, , rotation] = intervals[j];\n break;\n }\n }\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.error('This geometry type is not supported. Only Point or LineString are. Current geometry: ', geometry);\n }\n return { coord, rotation };\n};\nexport default getVehiclePosition;\n", @@ -8307,7 +8586,7 @@ "lineNumber": 1 }, { - "__docId__": 391, + "__docId__": 401, "kind": "function", "name": "getVehiclePosition", "memberof": "build/common/utils/getVehiclePosition.js", @@ -8369,7 +8648,7 @@ } }, { - "__docId__": 392, + "__docId__": 402, "kind": "file", "name": "build/common/utils/index.js", "content": "export { default as compareDepartures } from './compareDepartures';\nexport * from './constants';\nexport { default as createCanvas } from './createCanvas';\nexport { default as createRealtimeFilters } from './createRealtimeFilters';\nexport { default as debounceDeparturesMessages } from './debounceDeparturesMessages';\nexport { default as debounceWebsocketMessages } from './debounceWebsocketMessages';\nexport { default as getLayersAsFlatArray } from './getLayersAsFlatArray';\nexport { default as getMapGlCopyrights } from './getMapGlCopyrights';\nexport { default as getUrlWithParams } from './getUrlWithParams';\nexport { default as getVehiclePosition } from './getVehiclePosition';\nexport * from './mocoUtils';\nimport * as realtimeConfig_1 from './realtimeStyleUtils';\nexport { realtimeConfig_1 as realtimeConfig };\nimport * as realtimeStyleUtils_1 from './realtimeStyleUtils';\nexport { realtimeStyleUtils_1 as realtimeStyleUtils };\nexport { default as removeDuplicate } from './removeDuplicate';\nexport { default as renderTrajectories } from './renderTrajectories';\nexport { default as sortAndFilterDepartures } from './sortAndFilterDepartures';\nexport { default as sortByDelay } from './sortByDelay';\nexport * from './timeUtils';\n", @@ -8380,10 +8659,10 @@ "lineNumber": 1 }, { - "__docId__": 393, + "__docId__": 403, "kind": "file", "name": "build/common/utils/mocoUtils.js", - "content": "import { getCenter } from 'ol/extent';\nimport GeoJSONFormat from 'ol/format/GeoJSON';\nimport { v4 as uuid } from 'uuid';\nexport const getTime = (str) => {\n return parseInt(str === null || str === void 0 ? void 0 : str.substr(0, 8).replace(/:/g, ''), 10);\n};\nconst geojson = new GeoJSONFormat();\n/**\n * Determines if the current date is within an affected time intervals of a situation.\n */\nexport const isMocoSituationAffected = (situation, now = new Date()) => {\n var _a;\n return !!((_a = situation.affectedTimeIntervals) === null || _a === void 0 ? void 0 : _a.some((affectedTimeInterval) => {\n const { dailyEndTime = '', dailyStartTime = '', endTime, startTime, } = affectedTimeInterval;\n const nowTime = getTime(now.toTimeString());\n const dailyStart = getTime(dailyStartTime);\n const dailyEnd = getTime(dailyEndTime);\n const inRange = new Date(startTime) <= now && now <= new Date(endTime);\n return dailyStart && dailyEnd\n ? inRange && dailyStart <= nowTime && nowTime <= dailyEnd\n : inRange;\n }));\n};\n/**\n * Determines if the current date is within a publication windows of a situation.\n */\nexport const isMocoSituationPublished = (situation, now = new Date()) => {\n var _a, _b, _c;\n const publicationWindows = (_c = (_a = situation.publicationWindows) !== null && _a !== void 0 ? _a : (_b = situation.publications) === null || _b === void 0 ? void 0 : _b.flatMap((publication) => {\n var _a;\n return (_a = publication.publicationWindows) !== null && _a !== void 0 ? _a : [];\n })) !== null && _c !== void 0 ? _c : [];\n if (!publicationWindows.length) {\n // If there are no publication windows, use the time intervals\n return !!isMocoSituationAffected(situation, now);\n }\n return !!publicationWindows.some(({ endTime, startTime }) => {\n return new Date(startTime) <= now && now <= new Date(endTime);\n });\n};\n// export const getMocoStartsString = (\n// notificationProperties: MocoNotificationProperties,\n// now: Date,\n// ) => {\n// const next = notificationProperties.affected_time_intervals.reduce(\n// (\n// a: MocoDefinitions['AffectedTimeIntervals'],\n// b: MocoDefinitions['AffectedTimeIntervals'],\n// ) => {\n// const aEnd = new Date(a.end);\n// const aStart = new Date(a.start);\n// const bStart = new Date(b.start);\n// return now < aEnd && aStart < bStart ? a : b;\n// },\n// {} as MocoDefinitions['AffectedTimeIntervals'],\n// );\n// const nextStartDate = new Date(next.start);\n// let starts;\n// if (\n// now.toDateString() === nextStartDate.toDateString() ||\n// now.getTime() - nextStartDate.getTime() > 0\n// ) {\n// if (next.time_of_day_start) {\n// starts = `ab ${next.time_of_day_start.substr(0, 5)}`;\n// } else {\n// starts = `ab ${nextStartDate.toLocaleTimeString(['de'], {\n// hour: '2-digit',\n// hour12: false,\n// minute: '2-digit',\n// })}`;\n// }\n// } else {\n// starts = `ab ${nextStartDate.toLocaleDateString(['de-DE'], {\n// day: 'numeric',\n// month: 'short',\n// })}`;\n// }\n// return starts;\n// };\nexport const getMocoIconRefFeature = (publicationLineFeature) => {\n const geometry = geojson.readGeometry(publicationLineFeature.geometry);\n const center = getCenter(geometry.getExtent());\n const icon = {\n geometry: {\n coordinates: geometry.getClosestPoint(center),\n type: 'Point',\n },\n id: uuid(),\n properties: Object.assign(Object.assign({}, publicationLineFeature.properties), { geometry: undefined }),\n type: 'Feature',\n };\n return icon;\n};\nconst to4326 = (geometry3857) => {\n return geojson.writeGeometryObject(geojson.readGeometry(geometry3857, {\n dataProjection: 'EPSG:3857',\n featureProjection: 'EPSG:4326',\n }));\n};\nexport const getMocoReasonCategoryImageName = (categoryName = 'undefiniert') => {\n return categoryName\n .toLowerCase()\n .replace(/\\s/g, '_')\n .replace(/ü/g, 'ue')\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ß/g, 'ss');\n};\n/**\n * This function return a FeatureCollection representing a Situation,\n * This feature collection contains a feature for each affectd lines and stops.\n * This also creates an icon for each affected line if hasIcon property is true.\n */\nexport const getFeatureCollectionToRenderFromSituation = (situation, date = new Date()) => {\n var _a, _b, _c;\n const features = [];\n const reasonCategoryImageName = getMocoReasonCategoryImageName((_b = (_a = situation.reasons) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.categoryName);\n const situationRenderProps = {\n reasonCategoryImageName,\n reasons: situation.reasons,\n // for backward compatibility\n reasons_category: reasonCategoryImageName,\n };\n (_c = situation === null || situation === void 0 ? void 0 : situation.publications) === null || _c === void 0 ? void 0 : _c.forEach((publication) => {\n var _a, _b, _c;\n const isAffected = isMocoSituationAffected(situation, date);\n const isPublished = isMocoSituationPublished(situation, date);\n const publicationRenderProps = {\n // for backward compatibility with v1\n condition_group: publication.serviceConditionGroup.toLowerCase(),\n // for backward compatibility with v1\n isActive: isAffected,\n isAffected,\n isPublished,\n serviceConditionGroup: publication.serviceConditionGroup,\n // for backward compatibility with v1\n severity_group: (_a = publication.severityGroup) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase(),\n severityGroup: publication.severityGroup,\n };\n (_b = publication.publicationLines) === null || _b === void 0 ? void 0 : _b.forEach((publicationLine) => {\n publicationLine.lines.forEach((line) => {\n line.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, hasIcon: publicationLine.hasIcon, line, mot: publicationLine.mot, \n // We pass the ids to be able to identify the publication and the situation related to\n publicationId: publication.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n // console.log(feature.properties);\n features.push(feature);\n if (publicationLine.hasIcon) {\n const iconFeature = getMocoIconRefFeature(feature);\n iconFeature.properties.situationId = situation.id; // make the sure the situation is passed\n features.push(iconFeature);\n }\n });\n });\n });\n (_c = publication.publicationStops) === null || _c === void 0 ? void 0 : _c.forEach((publicationStop) => {\n publicationStop.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, name: publicationStop.name, publicationId: publication.id, publicationStopId: publicationStop.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n features.push(feature);\n });\n });\n });\n return {\n features,\n type: 'FeatureCollection',\n };\n};\n// export const getMocoSituationsAsFeatureCollection = (\n// situations: MocoSituationToRender[],\n// ): MocoNotificationAsFeatureCollection => {\n// situations.forEach((situation) => {});\n// // Merge all features into a single GeoJSON feature collection\n// // and add the notification properties to each feature.\n// const features = notifications.flatMap((notification) => {\n// return (notification.features || []).map((feature) => {\n// const feat: MocoNotificationFeature = {\n// ...feature,\n// properties: {\n// ...notification.properties,\n// ...feature.properties,\n// },\n// };\n// const reasonCategoryName =\n// notification.properties.reasons?.[0]?.category_name;\n// // reasons_category is used to choose the proper icon in the style\n// // @ts-expect-error the value is a string in the style\n// feat.properties.reasons_category =\n// MOCO_IMAGE_BY_CATEGORY[\n// reasonCategoryName || MOCO_REASONS_CATEGORY.UNDEFINIERT\n// ] || MOCO_IMAGE_BY_CATEGORY[MOCO_REASONS_CATEGORY.UNDEFINIERT];\n// return feat;\n// });\n// });\n// return {\n// // @ts-expect-error conflict between geometry types\n// features,\n// type: 'FeatureCollection',\n// };\n// };\n", + "content": "import { getCenter } from 'ol/extent';\nimport GeoJSONFormat from 'ol/format/GeoJSON';\nimport { v4 as uuid } from 'uuid';\nexport const getTime = (str) => {\n return parseInt(str === null || str === void 0 ? void 0 : str.substr(0, 8).replace(/:/g, ''), 10);\n};\nconst geojson = new GeoJSONFormat();\n/**\n * Determines if the current date is within an affected time intervals of a situation.\n */\nexport const isMocoSituationAffected = (situation, now = new Date()) => {\n var _a;\n return !!((_a = situation.affectedTimeIntervals) === null || _a === void 0 ? void 0 : _a.some((affectedTimeInterval) => {\n const { dailyEndTime = '', dailyStartTime = '', endTime, startTime, } = affectedTimeInterval;\n const nowTime = getTime(now.toTimeString());\n const dailyStart = getTime(dailyStartTime);\n const dailyEnd = getTime(dailyEndTime);\n const inRange = new Date(startTime) <= now && now <= new Date(endTime);\n return dailyStart && dailyEnd\n ? inRange && dailyStart <= nowTime && nowTime <= dailyEnd\n : inRange;\n }));\n};\n/**\n * Determines if the current date is within a publication windows of a situation.\n */\nexport const isMocoSituationPublished = (situation, now = new Date()) => {\n var _a, _b, _c;\n const publicationWindows = (_c = (_a = situation.publicationWindows) !== null && _a !== void 0 ? _a : (_b = situation.publications) === null || _b === void 0 ? void 0 : _b.flatMap((publication) => {\n var _a;\n return (_a = publication.publicationWindows) !== null && _a !== void 0 ? _a : [];\n })) !== null && _c !== void 0 ? _c : [];\n if (!publicationWindows.length) {\n // If there are no publication windows, use the time intervals\n return !!isMocoSituationAffected(situation, now);\n }\n return !!publicationWindows.some(({ endTime, startTime }) => {\n return new Date(startTime) <= now && now <= new Date(endTime);\n });\n};\n// export const getMocoStartsString = (\n// notificationProperties: MocoNotificationProperties,\n// now: Date,\n// ) => {\n// const next = notificationProperties.affected_time_intervals.reduce(\n// (\n// a: MocoDefinitions['AffectedTimeIntervals'],\n// b: MocoDefinitions['AffectedTimeIntervals'],\n// ) => {\n// const aEnd = new Date(a.end);\n// const aStart = new Date(a.start);\n// const bStart = new Date(b.start);\n// return now < aEnd && aStart < bStart ? a : b;\n// },\n// {} as MocoDefinitions['AffectedTimeIntervals'],\n// );\n// const nextStartDate = new Date(next.start);\n// let starts;\n// if (\n// now.toDateString() === nextStartDate.toDateString() ||\n// now.getTime() - nextStartDate.getTime() > 0\n// ) {\n// if (next.time_of_day_start) {\n// starts = `ab ${next.time_of_day_start.substr(0, 5)}`;\n// } else {\n// starts = `ab ${nextStartDate.toLocaleTimeString(['de'], {\n// hour: '2-digit',\n// hour12: false,\n// minute: '2-digit',\n// })}`;\n// }\n// } else {\n// starts = `ab ${nextStartDate.toLocaleDateString(['de-DE'], {\n// day: 'numeric',\n// month: 'short',\n// })}`;\n// }\n// return starts;\n// };\nexport const getMocoIconRefFeature = (publicationLineFeature) => {\n const geometry = geojson.readGeometry(publicationLineFeature.geometry);\n const center = getCenter(geometry.getExtent());\n const icon = {\n geometry: {\n coordinates: geometry.getClosestPoint(center),\n type: 'Point',\n },\n id: uuid(),\n properties: Object.assign(Object.assign({}, publicationLineFeature.properties), { geometry: undefined }),\n type: 'Feature',\n };\n return icon;\n};\nconst to4326 = (geometry3857) => {\n return geojson.writeGeometryObject(geojson.readGeometry(geometry3857, {\n dataProjection: 'EPSG:3857',\n featureProjection: 'EPSG:4326',\n }));\n};\nexport const getMocoReasonCategoryImageName = (categoryName = 'undefiniert') => {\n return categoryName\n .toLowerCase()\n .replace(/\\s/g, '_')\n .replace(/ü/g, 'ue')\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ß/g, 'ss');\n};\n/**\n * This function return a FeatureCollection representing a Situation,\n * This feature collection contains a feature for each affectd lines and stops.\n * This also creates an icon for each affected line if hasIcon property is true.\n */\nexport const getFeatureCollectionToRenderFromSituation = (situation, date = new Date()) => {\n var _a, _b, _c;\n const features = [];\n const reasonCategoryImageName = getMocoReasonCategoryImageName((_b = (_a = situation.reasons) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.categoryName);\n const situationRenderProps = {\n reasonCategoryImageName,\n reasons: situation.reasons,\n // for backward compatibility\n reasons_category: reasonCategoryImageName,\n };\n (_c = situation === null || situation === void 0 ? void 0 : situation.publications) === null || _c === void 0 ? void 0 : _c.forEach((publication) => {\n var _a, _b, _c;\n const isAffected = isMocoSituationAffected(situation, date);\n const isPublished = isMocoSituationPublished(situation, date);\n const publicationRenderProps = {\n // for backward compatibility with v1\n condition_group: publication.serviceConditionGroup.toLowerCase(),\n // for backward compatibility with v1\n isActive: isAffected,\n isAffected,\n isPublished,\n serviceCondition: publication.serviceCondition,\n serviceConditionGroup: publication.serviceConditionGroup,\n severity: publication.severity,\n // for backward compatibility with v1\n severity_group: (_a = publication.severityGroup) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase(),\n severityGroup: publication.severityGroup,\n };\n (_b = publication.publicationLines) === null || _b === void 0 ? void 0 : _b.forEach((publicationLine) => {\n publicationLine.lines.forEach((line) => {\n line.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, hasIcon: publicationLine.hasIcon, line, mot: publicationLine.mot, \n // We pass the ids to be able to identify the publication and the situation related to\n publicationId: publication.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n features.push(feature);\n if (publicationLine.hasIcon) {\n const iconFeature = getMocoIconRefFeature(feature);\n iconFeature.properties.situationId = situation.id; // make the sure the situation is passed\n features.push(iconFeature);\n }\n });\n });\n });\n (_c = publication.publicationStops) === null || _c === void 0 ? void 0 : _c.forEach((publicationStop) => {\n publicationStop.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, name: publicationStop.name, publicationId: publication.id, publicationStopId: publicationStop.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n features.push(feature);\n });\n });\n });\n return {\n features,\n type: 'FeatureCollection',\n };\n};\n// export const getMocoSituationsAsFeatureCollection = (\n// situations: MocoSituationToRender[],\n// ): MocoNotificationAsFeatureCollection => {\n// situations.forEach((situation) => {});\n// // Merge all features into a single GeoJSON feature collection\n// // and add the notification properties to each feature.\n// const features = notifications.flatMap((notification) => {\n// return (notification.features || []).map((feature) => {\n// const feat: MocoNotificationFeature = {\n// ...feature,\n// properties: {\n// ...notification.properties,\n// ...feature.properties,\n// },\n// };\n// const reasonCategoryName =\n// notification.properties.reasons?.[0]?.category_name;\n// // reasons_category is used to choose the proper icon in the style\n// // @ts-expect-error the value is a string in the style\n// feat.properties.reasons_category =\n// MOCO_IMAGE_BY_CATEGORY[\n// reasonCategoryName || MOCO_REASONS_CATEGORY.UNDEFINIERT\n// ] || MOCO_IMAGE_BY_CATEGORY[MOCO_REASONS_CATEGORY.UNDEFINIERT];\n// return feat;\n// });\n// });\n// return {\n// // @ts-expect-error conflict between geometry types\n// features,\n// type: 'FeatureCollection',\n// };\n// };\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/mocoUtils.js", "access": "private", @@ -8391,7 +8670,7 @@ "lineNumber": 1 }, { - "__docId__": 394, + "__docId__": 404, "kind": "function", "name": "getTime", "memberof": "build/common/utils/mocoUtils.js", @@ -8421,7 +8700,7 @@ } }, { - "__docId__": 395, + "__docId__": 405, "kind": "variable", "name": "geojson", "memberof": "build/common/utils/mocoUtils.js", @@ -8442,7 +8721,7 @@ "ignore": true }, { - "__docId__": 396, + "__docId__": 406, "kind": "function", "name": "isMocoSituationAffected", "memberof": "build/common/utils/mocoUtils.js", @@ -8478,7 +8757,7 @@ } }, { - "__docId__": 397, + "__docId__": 407, "kind": "function", "name": "isMocoSituationPublished", "memberof": "build/common/utils/mocoUtils.js", @@ -8514,7 +8793,7 @@ } }, { - "__docId__": 398, + "__docId__": 408, "kind": "function", "name": "getMocoIconRefFeature", "memberof": "build/common/utils/mocoUtils.js", @@ -8544,7 +8823,7 @@ } }, { - "__docId__": 399, + "__docId__": 409, "kind": "function", "name": "to4326", "memberof": "build/common/utils/mocoUtils.js", @@ -8575,7 +8854,7 @@ "ignore": true }, { - "__docId__": 400, + "__docId__": 410, "kind": "function", "name": "getMocoReasonCategoryImageName", "memberof": "build/common/utils/mocoUtils.js", @@ -8608,7 +8887,7 @@ } }, { - "__docId__": 401, + "__docId__": 411, "kind": "function", "name": "getFeatureCollectionToRenderFromSituation", "memberof": "build/common/utils/mocoUtils.js", @@ -8644,10 +8923,10 @@ } }, { - "__docId__": 402, + "__docId__": 412, "kind": "file", "name": "build/common/utils/realtimeStyleUtils.js", - "content": "const radiusMapping = [\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n];\nexport const MOTS_ONLY_RAIL = ['rail'];\nexport const MOTS_WITH_CABLE = [\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\nexport const MOTS_WITHOUT_CABLE = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n];\nexport const MOTS_ALL = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n 'ferry',\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\n/**\n * Trajserv value: 'Tram', 'Subway / Metro / S-Bahn', 'Train', 'Bus', 'Ferry', 'Cable Car', 'Gondola', 'Funicular', 'Long distance bus', 'Rail',\n * New endpoint use Rail instead of Train.\n * New tracker values: null, \"tram\", \"subway\", \"rail\", \"bus\", \"ferry\", \"cablecar\", \"gondola\", \"funicular\", \"coach\".\n */\nexport const types = [\n /^Tram/i,\n /^Subway( \\/ Metro \\/ S-Bahn)?/i,\n /^Train/i,\n /^Bus/i,\n /^Ferry/i,\n /^Cable ?Car/i,\n /^Gondola/i,\n /^Funicular/i,\n /^(Long distance bus|coach)/i,\n /^Rail/i, // New endpoint use Rail instead of Train.\n /^unknown/i, // in case the type is not defined\n];\nexport const bgColors = [\n '#ffb400',\n '#ff5400',\n '#ff8080',\n '#ea0000',\n '#3000ff',\n '#ffb400',\n '#41a27b',\n '#00d237',\n '#b5b5b5',\n '#ff8080',\n '#ffb400',\n];\nexport const textColors = [\n '#000000',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#000000',\n '#000000',\n '#000000',\n];\nexport const DEFAULT_TYPE = 'unknown';\nexport const findDefaultIndexType = () => {\n return types.findIndex((r) => {\n return r.test(DEFAULT_TYPE);\n });\n};\nexport const getTypeIndex = (type) => {\n const t = type;\n if (t === undefined || t === null) {\n return findDefaultIndexType();\n }\n if (typeof t === 'string') {\n const index = types.findIndex((r) => {\n return r.test(t);\n });\n if (index === -1) {\n return findDefaultIndexType();\n }\n return index;\n }\n return t;\n};\nexport const getRadiusForTypeAndZoom = (type, zoom) => {\n const z = Math.min(Math.floor(zoom !== null && zoom !== void 0 ? zoom : 1), 16);\n try {\n const typeIdx = getTypeIndex(type);\n return radiusMapping[typeIdx][z];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (e) {\n return 1;\n }\n};\n/**\n * @deprecated use getRadiusForTypeAndZoom\n */\nexport const getRadius = getRadiusForTypeAndZoom;\nexport const getColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return bgColors[typeIdx];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (error) {\n return '#000';\n }\n};\n/**\n * @deprecated use getColorForType\n */\nexport const getBgColor = getColorForType;\nexport const getTextColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return textColors[typeIdx];\n }\n catch (e) {\n return '#ffffff';\n }\n};\nexport const getTextColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.text_color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * @deprecated use getTextColorForType\n */\nexport const getTextColor = getTextColorForType;\nexport const getTextSize = (ctx, markerSize, text, fontSize, font) => {\n if (!ctx || !font || !markerSize || !text || !fontSize) {\n return 0;\n }\n ctx.font = font;\n let newText = ctx.measureText(text);\n const maxiter = 25;\n let i = 0;\n while (newText.width > markerSize - 6 && i < maxiter) {\n const previousFontSize = fontSize;\n // eslint-disable-next-line no-param-reassign\n fontSize -= 0.5;\n ctx.font = ctx.font.replace(`${previousFontSize}px`, `${fontSize}px`);\n newText = ctx.measureText(text);\n i += 1;\n }\n return fontSize;\n};\nexport const getDelayColor = (delayInMs, cancelled, isDelayText) => {\n if (cancelled) {\n return isDelayText ? '#ff0000' : '#a0a0a0'; // red or gray\n }\n if (!delayInMs) {\n return '';\n }\n if (delayInMs === null) {\n return '#a0a0a0'; // grey { r: 160, g: 160, b: 160, s: '160,160,160' };\n }\n if (delayInMs >= 3600000) {\n return '#ed004c'; // pink { r: 237, g: 0, b: 76, s: '237,0,76' };\n }\n if (delayInMs >= 500000) {\n return '#e80000'; // red { r: 232, g: 0, b: 0, s: '232,0,0' };\n }\n if (delayInMs >= 300000) {\n return '#ff4a00'; // orange { r: 255, g: 74, b: 0, s: '255,74,0' };\n }\n if (delayInMs >= 180000) {\n return '#f7bf00'; // yellow { r: 247, g: 191, b: 0, s: '247,191,0' };\n }\n return '#00a00c'; // green { r: 0, g: 160, b: 12, s: '0,160,12' };\n};\nexport const getDelayText = (delay, cancelled) => {\n if (cancelled) {\n return String.fromCodePoint(0x00d7);\n }\n if (!delay) {\n return '';\n }\n if (delay >= 3600000) {\n const rounded = Math.round(delay / 3600000);\n return `+${rounded}h`;\n }\n if (delay >= 60000) {\n const rounded = Math.round(delay / 60000);\n return `+${rounded}m`;\n }\n if (delay >= 1000) {\n const rounded = Math.round(delay / 1000);\n return `+${rounded}s`;\n }\n if (delay > 0) {\n return `+${delay}ms`;\n }\n return '';\n};\nexport const getColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * This object is the default style options for the realtime layer.\n * The colors are defined depending of the trajectory`s line, and if it does\n * not exist, depending of the mot type of the trajectory.\n */\nexport const styleOptionsForMot = {\n getColor: (trajectory) => {\n var _a, _b;\n return (getColorForLine((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.line) ||\n getColorForType((_b = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _b === void 0 ? void 0 : _b.type) ||\n '#000');\n },\n getDelayColor: (trajectory, viewState, delayInMs, cancelled, isDelayText) => {\n return getDelayColor(delayInMs, cancelled, isDelayText) || 'transparent';\n },\n getDelayText: (trajectory, viewState, delay, cancelled) => {\n return getDelayText(delay, cancelled) || '';\n },\n getRadius: (trajectory, viewState) => {\n var _a;\n return (getRadiusForTypeAndZoom((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.type, viewState === null || viewState === void 0 ? void 0 : viewState.zoom) ||\n 1);\n },\n getTextColor: (trajectory) => {\n return (getTextColorForLine(trajectory.properties.line) ||\n getTextColorForType(trajectory.properties.type));\n },\n getTextSize: (trajectory, viewState, ctx, markerSize, text, fontSize, font) => {\n return getTextSize(ctx, markerSize, text, fontSize, font) || 12;\n },\n};\n", + "content": "const radiusMapping = [\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n];\nexport const MOTS_ONLY_RAIL = ['rail'];\nexport const MOTS_WITH_CABLE = [\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\nexport const MOTS_WITHOUT_CABLE = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n];\nexport const MOTS_ALL = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n 'ferry',\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\n/**\n * Trajserv value: 'Tram', 'Subway / Metro / S-Bahn', 'Train', 'Bus', 'Ferry', 'Cable Car', 'Gondola', 'Funicular', 'Long distance bus', 'Rail',\n * New endpoint use Rail instead of Train.\n * New tracker values: null, \"tram\", \"subway\", \"rail\", \"bus\", \"ferry\", \"cablecar\", \"gondola\", \"funicular\", \"coach\".\n */\nexport const types = [\n /^Tram/i,\n /^Subway( \\/ Metro \\/ S-Bahn)?/i,\n /^Train/i,\n /^Bus/i,\n /^Ferry/i,\n /^Cable ?Car/i,\n /^Gondola/i,\n /^Funicular/i,\n /^(Long distance bus|coach)/i,\n /^Rail/i, // New endpoint use Rail instead of Train.\n /^unknown/i, // in case the type is not defined\n];\nexport const bgColors = [\n '#ffb400',\n '#ff5400',\n '#ff8080',\n '#ea0000',\n '#3000ff',\n '#ffb400',\n '#41a27b',\n '#00d237',\n '#b5b5b5',\n '#ff8080',\n '#ffb400',\n];\nexport const textColors = [\n '#000000',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#000000',\n '#000000',\n '#000000',\n];\nexport const DEFAULT_TYPE = 'unknown';\nexport const findDefaultIndexType = () => {\n return types.findIndex((r) => {\n return r.test(DEFAULT_TYPE);\n });\n};\nexport const getTypeIndex = (type) => {\n const t = type;\n if (t === undefined || t === null) {\n return findDefaultIndexType();\n }\n if (typeof t === 'string') {\n const index = types.findIndex((r) => {\n return r.test(t);\n });\n if (index === -1) {\n return findDefaultIndexType();\n }\n return index;\n }\n return t;\n};\nexport const getRadiusForTypeAndZoom = (type, zoom) => {\n const z = Math.min(Math.floor(zoom !== null && zoom !== void 0 ? zoom : 1), 16);\n try {\n const typeIdx = getTypeIndex(type);\n return radiusMapping[typeIdx][z];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (e) {\n return 1;\n }\n};\n/**\n * @deprecated use getRadiusForTypeAndZoom\n */\nexport const getRadius = getRadiusForTypeAndZoom;\nexport const getColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return bgColors[typeIdx];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (error) {\n return '#000';\n }\n};\n/**\n * @deprecated use getColorForType\n */\nexport const getBgColor = getColorForType;\nexport const getTextColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return textColors[typeIdx];\n }\n catch (e) {\n return '#ffffff';\n }\n};\nexport const getTextColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.text_color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * @deprecated use getTextColorForType\n */\nexport const getTextColor = getTextColorForType;\nexport const getTextSize = (ctx, markerSize, text, fontSize, font) => {\n if (!ctx || !font || !markerSize || !text || !fontSize) {\n return 0;\n }\n ctx.font = font;\n let newText = ctx.measureText(text);\n const maxiter = 25;\n let i = 0;\n while (newText.width > markerSize && i < maxiter) {\n const previousFontSize = fontSize;\n // eslint-disable-next-line no-param-reassign\n fontSize -= 0.5;\n ctx.font = ctx.font.replace(`${previousFontSize}px`, `${fontSize}px`);\n newText = ctx.measureText(text);\n i += 1;\n }\n return fontSize;\n};\nexport const getDelayColor = (delayInMs, cancelled, isDelayText) => {\n if (cancelled) {\n return isDelayText ? '#ff0000' : '#a0a0a0'; // red or gray\n }\n if (delayInMs === null || delayInMs === undefined) {\n return ''; // grey { r: 160, g: 160, b: 160, s: '160,160,160' };\n }\n if (delayInMs >= 3600000) {\n return '#ed004c'; // pink { r: 237, g: 0, b: 76, s: '237,0,76' };\n }\n if (delayInMs >= 500000) {\n return '#e80000'; // red { r: 232, g: 0, b: 0, s: '232,0,0' };\n }\n if (delayInMs >= 300000) {\n return '#ff4a00'; // orange { r: 255, g: 74, b: 0, s: '255,74,0' };\n }\n if (delayInMs >= 180000) {\n return '#f7bf00'; // yellow { r: 247, g: 191, b: 0, s: '247,191,0' };\n }\n return '#00a00c'; // green { r: 0, g: 160, b: 12, s: '0,160,12' };\n};\nexport const getDelayText = (delay, cancelled) => {\n if (cancelled) {\n return String.fromCodePoint(0x00d7);\n }\n if (!delay) {\n return '';\n }\n if (delay >= 3600000) {\n const rounded = Math.round(delay / 3600000);\n return `+${rounded}h`;\n }\n if (delay >= 60000) {\n const rounded = Math.round(delay / 60000);\n return `+${rounded}m`;\n }\n if (delay >= 1000) {\n const rounded = Math.round(delay / 1000);\n return `+${rounded}s`;\n }\n if (delay > 0) {\n return `+${delay}ms`;\n }\n return '';\n};\nexport const getColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * This object is the default style options for the realtime layer.\n * The colors are defined depending of the trajectory`s line, and if it does\n * not exist, depending of the mot type of the trajectory.\n */\nexport const styleOptionsForMot = {\n getColor: (trajectory) => {\n var _a, _b;\n return (getColorForLine((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.line) ||\n getColorForType((_b = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _b === void 0 ? void 0 : _b.type) ||\n '#000');\n },\n getDelayColor: (trajectory, viewState, delayInMs, cancelled, isDelayText) => {\n return getDelayColor(delayInMs, cancelled, isDelayText) || 'transparent';\n },\n getDelayText: (trajectory, viewState, delay, cancelled) => {\n return getDelayText(delay, cancelled) || '';\n },\n getRadius: (trajectory, viewState) => {\n var _a;\n return (getRadiusForTypeAndZoom((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.type, viewState === null || viewState === void 0 ? void 0 : viewState.zoom) ||\n 1);\n },\n getTextColor: (trajectory) => {\n return (getTextColorForLine(trajectory.properties.line) ||\n getTextColorForType(trajectory.properties.type));\n },\n getTextSize: (trajectory, viewState, ctx, markerSize, text, fontSize, font) => {\n return getTextSize(ctx, markerSize, text, fontSize, font) || 12;\n },\n};\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/realtimeStyleUtils.js", "access": "private", @@ -8655,7 +8934,7 @@ "lineNumber": 1 }, { - "__docId__": 403, + "__docId__": 413, "kind": "variable", "name": "radiusMapping", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8676,7 +8955,7 @@ "ignore": true }, { - "__docId__": 404, + "__docId__": 414, "kind": "variable", "name": "MOTS_ONLY_RAIL", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8696,7 +8975,7 @@ } }, { - "__docId__": 405, + "__docId__": 415, "kind": "variable", "name": "MOTS_WITH_CABLE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8716,7 +8995,7 @@ } }, { - "__docId__": 406, + "__docId__": 416, "kind": "variable", "name": "MOTS_WITHOUT_CABLE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8736,7 +9015,7 @@ } }, { - "__docId__": 407, + "__docId__": 417, "kind": "variable", "name": "MOTS_ALL", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8756,7 +9035,7 @@ } }, { - "__docId__": 408, + "__docId__": 418, "kind": "variable", "name": "types", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8775,7 +9054,7 @@ } }, { - "__docId__": 409, + "__docId__": 419, "kind": "variable", "name": "bgColors", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8795,7 +9074,7 @@ } }, { - "__docId__": 410, + "__docId__": 420, "kind": "variable", "name": "textColors", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8815,7 +9094,7 @@ } }, { - "__docId__": 411, + "__docId__": 421, "kind": "variable", "name": "DEFAULT_TYPE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8835,7 +9114,7 @@ } }, { - "__docId__": 412, + "__docId__": 422, "kind": "function", "name": "findDefaultIndexType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8858,7 +9137,7 @@ } }, { - "__docId__": 413, + "__docId__": 423, "kind": "function", "name": "getTypeIndex", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8888,7 +9167,7 @@ } }, { - "__docId__": 414, + "__docId__": 424, "kind": "function", "name": "getRadiusForTypeAndZoom", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8924,7 +9203,7 @@ } }, { - "__docId__": 415, + "__docId__": 425, "kind": "variable", "name": "getRadius", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8944,7 +9223,7 @@ } }, { - "__docId__": 416, + "__docId__": 426, "kind": "function", "name": "getColorForType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8974,7 +9253,7 @@ } }, { - "__docId__": 417, + "__docId__": 427, "kind": "variable", "name": "getBgColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8994,7 +9273,7 @@ } }, { - "__docId__": 418, + "__docId__": 428, "kind": "function", "name": "getTextColorForType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9024,7 +9303,7 @@ } }, { - "__docId__": 419, + "__docId__": 429, "kind": "function", "name": "getTextColorForLine", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9054,7 +9333,7 @@ } }, { - "__docId__": 420, + "__docId__": 430, "kind": "variable", "name": "getTextColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9074,7 +9353,7 @@ } }, { - "__docId__": 421, + "__docId__": 431, "kind": "function", "name": "getTextSize", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9128,7 +9407,7 @@ } }, { - "__docId__": 422, + "__docId__": 432, "kind": "function", "name": "getDelayColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9170,7 +9449,7 @@ } }, { - "__docId__": 423, + "__docId__": 433, "kind": "function", "name": "getDelayText", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9183,7 +9462,7 @@ "importPath": "mobility-toolbox-js/build/common/utils/realtimeStyleUtils.js", "importStyle": "{getDelayText}", "description": null, - "lineNumber": 193, + "lineNumber": 190, "undocument": true, "params": [ { @@ -9206,7 +9485,7 @@ } }, { - "__docId__": 424, + "__docId__": 434, "kind": "function", "name": "getColorForLine", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9219,7 +9498,7 @@ "importPath": "mobility-toolbox-js/build/common/utils/realtimeStyleUtils.js", "importStyle": "{getColorForLine}", "description": null, - "lineNumber": 217, + "lineNumber": 214, "undocument": true, "params": [ { @@ -9236,7 +9515,7 @@ } }, { - "__docId__": 425, + "__docId__": 435, "kind": "variable", "name": "styleOptionsForMot", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9247,7 +9526,7 @@ "importPath": "mobility-toolbox-js/build/common/utils/realtimeStyleUtils.js", "importStyle": "{styleOptionsForMot}", "description": "This object is the default style options for the realtime layer.\nThe colors are defined depending of the trajectory`s line, and if it does\nnot exist, depending of the mot type of the trajectory.", - "lineNumber": 229, + "lineNumber": 226, "type": { "types": [ "{\"getColor\": *, \"getDelayColor\": *, \"getDelayText\": *, \"getRadius\": *, \"getTextColor\": *, \"getTextSize\": *}" @@ -9255,7 +9534,7 @@ } }, { - "__docId__": 426, + "__docId__": 436, "kind": "file", "name": "build/common/utils/removeDuplicate.js", "content": "/**\n * This function remove duplicates lower case string value of an array.\n * It removes also null, undefined or non string values.\n *\n * @param {array} array Array of values.\n * @private\n */\nfunction removeDuplicate(array) {\n const arrWithoutEmptyValues = array.filter((val) => {\n var _a;\n return (_a = val === null || val === void 0 ? void 0 : val.trim) === null || _a === void 0 ? void 0 : _a.call(val);\n });\n const lowerCasesValues = arrWithoutEmptyValues.map((str) => {\n return str.toLowerCase();\n });\n const uniqueLowerCaseValues = [...new Set(lowerCasesValues)];\n const uniqueValues = uniqueLowerCaseValues.map((uniqueStr) => {\n return arrWithoutEmptyValues.find((str) => {\n return str.toLowerCase() === uniqueStr;\n });\n });\n return uniqueValues;\n}\nexport default removeDuplicate;\n", @@ -9266,7 +9545,7 @@ "lineNumber": 1 }, { - "__docId__": 427, + "__docId__": 437, "kind": "function", "name": "removeDuplicate", "memberof": "build/common/utils/removeDuplicate.js", @@ -9299,10 +9578,10 @@ } }, { - "__docId__": 428, + "__docId__": 438, "kind": "file", "name": "build/common/utils/renderTrajectories.js", - "content": "import { apply, compose, create } from 'ol/transform';\nimport getVehiclePosition from './getVehiclePosition';\n/**\n * Draw all the trajectories available in a canvas.\n * @param {HTMLCanvas|HTMLOffscreenCanvas} canvas The canvas where to draw the trajectories.\n * @param {ViewState} trajectories An array of trajectories.\n * @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.\n * @param {ViewState} viewState The view state of the map.\n * @param {Object} options The options.\n * @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.\n * @param {boolean} options.selectedVehicleId The id of the vehicle to select.\n * @param {boolean} options.noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\nconst renderTrajectories = (canvas, trajectories, style, viewState, options) => {\n if (!canvas) {\n return { renderedTrajectories: [] };\n }\n const { center, pixelRatio = 1, resolution, rotation = 0, size = [], time = Date.now(), } = viewState;\n if (!resolution || !center) {\n return { renderedTrajectories: [] };\n }\n const { filter, getScreenPixel = (pixel, viewStat) => {\n return (viewStat.zoom || 0) < 12\n ? pixel.map((coord) => {\n return Math.floor(coord);\n })\n : pixel;\n }, hoverVehicleId, noInterpolate = false, selectedVehicleId, } = options;\n const context = canvas.getContext('2d');\n context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);\n const [width, height] = size;\n if (width &&\n height &&\n (canvas.width !== width * pixelRatio ||\n canvas.height !== height * pixelRatio)) {\n [canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];\n }\n const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);\n // Offscreen canvas has not style attribute\n if (canvas.style) {\n canvas.style.width = `${canvas.width / pixelRatio}px`;\n canvas.style.height = `${canvas.height / pixelRatio}px`;\n }\n let hoverVehicleImg;\n let hoverVehiclePx;\n let selectedVehicleImg;\n let selectedVehiclePx;\n const renderedTrajectories = [];\n for (let i = trajectories.length - 1; i >= 0; i -= 1) {\n const trajectory = trajectories[i];\n // Filter out trajectories\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n if (filter && !filter(trajectory)) {\n continue;\n }\n // We simplify the trajectory object\n // @ts-expect-error improve types\n const { timeOffset, train_id: id } = trajectory.properties;\n // We set the rotation and the timeFraction of the trajectory (used by tralis).\n // if rotation === null that seems there is no rotation available.\n const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);\n // We store the current vehicle position to the trajectory.\n trajectories[i].properties.coordinate = coord;\n trajectories[i].properties.rotation = rotationIcon;\n if (!coord) {\n continue;\n }\n let px = apply(coordinateToPixelTransform, [...coord]);\n if (!px) {\n continue;\n }\n px = px.map((p) => {\n return p * pixelRatio;\n });\n if (px[0] < 0 ||\n px[0] > canvas.width ||\n px[1] < 0 ||\n px[1] > canvas.height) {\n continue;\n }\n const vehicleImg = style(trajectory, viewState, options);\n if (!vehicleImg) {\n continue;\n }\n if (hoverVehicleId !== id && selectedVehicleId !== id) {\n // To optimize the performance we use integer as pixel coordinate\n // to avoid an additional work by the browser on zoom level < 12.\n // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead\n const [x, y] = getScreenPixel([px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState);\n context === null || context === void 0 ? void 0 : context.drawImage(vehicleImg, x, y);\n }\n if (hoverVehicleId && hoverVehicleId === id) {\n // Store the canvas to draw it at the end\n hoverVehicleImg = vehicleImg;\n hoverVehiclePx = px;\n }\n if (selectedVehicleId && selectedVehicleId === id) {\n // Store the canvas to draw it at the end\n selectedVehicleImg = vehicleImg;\n selectedVehiclePx = px;\n }\n renderedTrajectories.push(trajectory);\n }\n if (selectedVehicleImg && selectedVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(selectedVehicleImg, Math.floor(selectedVehiclePx[0] - selectedVehicleImg.width / 2), Math.floor(selectedVehiclePx[1] - selectedVehicleImg.height / 2));\n }\n if (hoverVehicleImg && hoverVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(hoverVehicleImg, Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2));\n }\n return {\n // isReady: true,\n renderedTrajectories,\n };\n};\nexport default renderTrajectories;\n", + "content": "import { apply, compose, create } from 'ol/transform';\nimport getVehiclePosition from './getVehiclePosition';\n/**\n * Draw all the trajectories available in a canvas.\n * @param {HTMLCanvas|HTMLOffscreenCanvas} canvas The canvas where to draw the trajectories.\n * @param {ViewState} trajectories An array of trajectories.\n * @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.\n * @param {ViewState} viewState The view state of the map.\n * @param {Object} options The options.\n * @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.\n * @param {boolean} options.selectedVehicleId The id of the vehicle to select.\n * @param {boolean} options.noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\nconst renderTrajectories = (canvas, trajectories, style, viewState, options) => {\n if (!canvas) {\n return { renderedTrajectories: [] };\n }\n const { center, pixelRatio = 1, resolution, rotation = 0, size = [], time = Date.now(), } = viewState;\n if (!resolution || !center) {\n return { renderedTrajectories: [] };\n }\n const { filter, getScreenPixel = (pixel, viewStat) => {\n return (viewStat.zoom || 0) < 12\n ? pixel.map((coord) => {\n return Math.floor(coord);\n })\n : pixel;\n }, hoverVehicleId, noInterpolate = false, selectedVehicleId, } = options;\n const context = canvas.getContext('2d');\n context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);\n const [width, height] = size;\n if (width &&\n height &&\n (canvas.width !== width * pixelRatio ||\n canvas.height !== height * pixelRatio)) {\n [canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];\n }\n const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);\n // Offscreen canvas has not style attribute\n if (canvas.style) {\n canvas.style.width = `${canvas.width / pixelRatio}px`;\n canvas.style.height = `${canvas.height / pixelRatio}px`;\n }\n let hoverVehicleImg;\n let hoverVehiclePx;\n let selectedVehicleImg;\n let selectedVehiclePx;\n const renderedTrajectories = [];\n const cachePixel = {};\n const cacheNbTrainAtPixel = {};\n const cacheDistanceOffset = {};\n for (let i = trajectories.length - 1; i >= 0; i -= 1) {\n const trajectory = trajectories[i];\n // Filter out trajectories\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n if (filter && !filter(trajectory)) {\n continue;\n }\n // We simplify the trajectory object\n // @ts-expect-error improve types\n const { timeOffset, train_id: id } = trajectory.properties;\n // We set the rotation and the timeFraction of the trajectory (used by tralis).\n // if rotation === null that seems there is no rotation available.\n const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);\n // We store the current vehicle position to the trajectory.\n trajectories[i].properties.coordinate = coord;\n trajectories[i].properties.rotation = rotationIcon;\n if (!coord) {\n continue;\n }\n let px = apply(coordinateToPixelTransform, [...coord]);\n if (!px) {\n continue;\n }\n px = px.map((p) => {\n return p * pixelRatio;\n });\n if (px[0] < 0 ||\n px[0] > canvas.width ||\n px[1] < 0 ||\n px[1] > canvas.height) {\n continue;\n }\n const vehicleImg = style(trajectory, viewState, options);\n if (!vehicleImg) {\n continue;\n }\n if (resolution < 1) {\n const roundedPX = px.map((p) => {\n return Math.round(p);\n });\n const key = `${roundedPX.toString()}`;\n if (!cachePixel[key]) {\n cachePixel[key] = px;\n cacheNbTrainAtPixel[key] = 1;\n cacheDistanceOffset[key] = 40 * resolution;\n }\n else {\n // if (!hoverVehicleId) {\n px[0] += 40 * cacheNbTrainAtPixel[key];\n // // }\n trajectories[i].properties.coordinate = [\n coord[0] + cacheDistanceOffset[key],\n coord[1],\n ];\n cacheNbTrainAtPixel[key]++;\n cacheDistanceOffset[key] += 40 * resolution;\n }\n }\n if (hoverVehicleId !== id && selectedVehicleId !== id) {\n // To optimize the performance we use integer as pixel coordinate\n // to avoid an additional work by the browser on zoom level < 12.\n // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead\n const [x, y] = getScreenPixel([px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState);\n context === null || context === void 0 ? void 0 : context.drawImage(vehicleImg, x, y);\n }\n if (hoverVehicleId && hoverVehicleId === id) {\n // Store the canvas to draw it at the end\n hoverVehicleImg = vehicleImg;\n hoverVehiclePx = px;\n // console.log(resolution);\n }\n if (selectedVehicleId && selectedVehicleId === id) {\n // Store the canvas to draw it at the end\n selectedVehicleImg = vehicleImg;\n selectedVehiclePx = px;\n }\n renderedTrajectories.push(trajectory);\n }\n if (selectedVehicleImg && selectedVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(selectedVehicleImg, Math.floor(selectedVehiclePx[0] - selectedVehicleImg.width / 2), Math.floor(selectedVehiclePx[1] - selectedVehicleImg.height / 2));\n }\n if (hoverVehicleImg && hoverVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(hoverVehicleImg, Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2));\n }\n return {\n // isReady: true,\n renderedTrajectories,\n };\n};\nexport default renderTrajectories;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/renderTrajectories.js", "access": "private", @@ -9310,7 +9589,7 @@ "lineNumber": 1 }, { - "__docId__": 429, + "__docId__": 439, "kind": "function", "name": "renderTrajectories", "memberof": "build/common/utils/renderTrajectories.js", @@ -9414,7 +9693,7 @@ } }, { - "__docId__": 430, + "__docId__": 440, "kind": "file", "name": "build/common/utils/sortAndFilterDepartures.js", "content": "import compareDepartures from './compareDepartures';\n/**\n * This function sort Departures by arrival time and filter out unwanted departures:\n * - when dparture time is in the past\n * - when departure are duplicated\n * - when departure is not in the next 30 min\n *\n * @param {Object} depObject The object containing departures by id.\n * @param {boolean} [sortByMinArrivalTime=false] If true sort departures by arrival time.\n * @param {number} [maxDepartureAge=30] The maximum departure age in minutes.\n * @return {RealtimeDeparture[]} Return departures array.\n * @private\n */\nconst sortAndfilterDepartures = (depObject, sortByMinArrivalTime = false, maxDepartureAge = 30) => {\n const departures = Object.keys(depObject).map((k) => {\n return depObject[k];\n });\n departures.sort((a, b) => {\n return compareDepartures(a, b, sortByMinArrivalTime);\n });\n const futureDate = new Date();\n futureDate.setMinutes(futureDate.getMinutes() + maxDepartureAge);\n const future = futureDate.getTime();\n const pastDate = new Date();\n pastDate.setMinutes(pastDate.getMinutes() - maxDepartureAge);\n const past = pastDate.getTime();\n const departureArray = [];\n const platformsBoarding = [];\n let previousDeparture = null;\n for (let i = departures.length - 1; i >= 0; i -= 1) {\n const departure = Object.assign({}, departures[i]);\n if (!departure.time) {\n // eslint-disable-next-line no-console\n console.warn('Departure without time found, skipping it.', departure);\n continue;\n }\n const time = new Date(departure.time).getTime();\n // Only show departures within the next 30 minutes\n if (time > past && time < future) {\n // If 2 trains are boarding at the same platform,\n // remove the older one.\n if (departure.state === 'BOARDING') {\n if (departure.platform &&\n !platformsBoarding.includes(departure.platform)) {\n platformsBoarding.push(departure.platform);\n }\n else {\n departure.state = 'HIDDEN';\n }\n }\n // If two trains with the same line number and destinatin\n // and a departure difference < 1 minute, hide the second one.\n if (previousDeparture &&\n departure.to[0] === previousDeparture.to[0] &&\n Math.abs(time - (previousDeparture.time || 0)) < 1000 &&\n departure.line.name === previousDeparture.line.name) {\n departure.state = 'HIDDEN';\n }\n if (/(STOP_CANCELLED|JOURNEY_CANCELLED)/.test(departure.state)) {\n departure.cancelled = true;\n }\n previousDeparture = departure;\n previousDeparture.time = time;\n departureArray.unshift(departure);\n }\n }\n return departureArray;\n};\nexport default sortAndfilterDepartures;\n", @@ -9425,7 +9704,7 @@ "lineNumber": 1 }, { - "__docId__": 431, + "__docId__": 441, "kind": "function", "name": "sortAndfilterDepartures", "memberof": "build/common/utils/sortAndFilterDepartures.js", @@ -9485,10 +9764,10 @@ } }, { - "__docId__": 432, + "__docId__": 442, "kind": "file", "name": "build/common/utils/sortByDelay.js", - "content": "const sortByDelay = (traj1, traj2) => {\n const props1 = traj1.properties;\n const props2 = traj2.properties;\n if (props1.delay === null && props2.delay !== null) {\n return 1;\n }\n if (props2.delay === null && props1.delay !== null) {\n return -1;\n }\n // We put cancelled train inbetween green and yellow trains\n // >=180000ms corresponds to yellow train\n // @ts-expect-error\n if (props1.cancelled && !props2.cancelled) {\n // @ts-expect-error\n return props2.delay < 180000 ? -1 : 1;\n }\n // @ts-expect-error\n if (props2.cancelled && !props1.cancelled) {\n // @ts-expect-error\n return props1.delay < 180000 ? 1 : -1;\n }\n // @ts-expect-error\n return props2.delay - props1.delay;\n};\nexport default sortByDelay;\n", + "content": "const sortByDelay = (traj1, traj2) => {\n const props1 = traj1.properties;\n const props2 = traj2.properties;\n if (props1.delay === null && props2.delay !== null) {\n return 1;\n }\n if (props2.delay === null && props1.delay !== null) {\n return -1;\n }\n // We put cancelled train inbetween green and yellow trains\n // >=180000ms corresponds to yellow train\n // @ts-expect-error Verify that this property exists\n if (props1.cancelled && !props2.cancelled) {\n return props2.delay < 180000 ? -1 : 1;\n }\n // @ts-expect-error Verify that this property exists\n if (props2.cancelled && !props1.cancelled) {\n return props1.delay < 180000 ? 1 : -1;\n }\n return props2.delay - props1.delay;\n};\nexport default sortByDelay;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/sortByDelay.js", "access": "private", @@ -9496,7 +9775,7 @@ "lineNumber": 1 }, { - "__docId__": 433, + "__docId__": 443, "kind": "function", "name": "sortByDelay", "memberof": "build/common/utils/sortByDelay.js", @@ -9532,7 +9811,7 @@ } }, { - "__docId__": 434, + "__docId__": 444, "kind": "file", "name": "build/common/utils/timeUtils.js", "content": "/**\n * Get a Date object as UTC date string .\n * ex: 2019 09 01\n * @private\n */\nexport const getUTCDateString = (now = new Date()) => {\n let month = (now.getUTCMonth() + 1).toString();\n month = month.length === 1 ? `0${month}` : month;\n let day = now.getUTCDate().toString();\n day = day.length === 1 ? `0${day}` : day;\n return [now.getUTCFullYear(), month, day].join('');\n};\n/**\n * Get the UTC time string of Date object.\n * ex: 09:05:01.123\n * @private\n */\nexport const getUTCTimeString = (date) => {\n return [\n date.getUTCHours(),\n date.getUTCMinutes(),\n `${date.getUTCSeconds()}.${date.getUTCMilliseconds()}`,\n ].join(':');\n};\n/**\n * Returns a string representation of a number, with a zero if the number is lower than 10.\n * @private\n */\nexport const pad = (integer) => {\n return integer < 10 ? `0${integer}` : `${integer}`;\n};\n/**\n * Returns a 'hh:mm' string from a time in ms.\n * @param {Number} timeInMs Time in milliseconds.\n * @private\n */\nexport const getHoursAndMinutes = (timeInMs) => {\n if (!timeInMs || timeInMs <= 0) {\n return '';\n }\n const date = new Date(timeInMs);\n return `${pad(date.getHours())}:${pad(date.getMinutes())}`;\n};\n", @@ -9543,7 +9822,7 @@ "lineNumber": 1 }, { - "__docId__": 435, + "__docId__": 445, "kind": "function", "name": "getUTCDateString", "memberof": "build/common/utils/timeUtils.js", @@ -9573,7 +9852,7 @@ } }, { - "__docId__": 436, + "__docId__": 446, "kind": "function", "name": "getUTCTimeString", "memberof": "build/common/utils/timeUtils.js", @@ -9602,7 +9881,7 @@ } }, { - "__docId__": 437, + "__docId__": 447, "kind": "function", "name": "pad", "memberof": "build/common/utils/timeUtils.js", @@ -9631,7 +9910,7 @@ } }, { - "__docId__": 438, + "__docId__": 448, "kind": "function", "name": "getHoursAndMinutes", "memberof": "build/common/utils/timeUtils.js", @@ -9664,7 +9943,7 @@ } }, { - "__docId__": 439, + "__docId__": 449, "kind": "file", "name": "build/common/utils/toMercatorExtent.js", "content": "import { transformExtent } from 'ol/proj';\n/**\n * @private\n */\nconst toMercatorExtent = (bounds) => {\n return transformExtent(bounds.toArray().flat(), 'EPSG:4326', 'EPSG:3857');\n};\nexport default toMercatorExtent;\n", @@ -9675,7 +9954,7 @@ "lineNumber": 1 }, { - "__docId__": 440, + "__docId__": 450, "kind": "function", "name": "toMercatorExtent", "memberof": "build/common/utils/toMercatorExtent.js", @@ -9704,7 +9983,7 @@ } }, { - "__docId__": 441, + "__docId__": 451, "kind": "file", "name": "build/index.js", "content": "import * as maplibre from './maplibre';\nimport * as ol from './ol';\nimport * as maplibre_1 from './maplibre';\nexport { maplibre_1 as maplibre };\nimport * as ol_1 from './ol';\nexport { ol_1 as ol };\nexport default {\n maplibre,\n ol,\n};\n", @@ -9715,7 +9994,7 @@ "lineNumber": 1 }, { - "__docId__": 442, + "__docId__": 452, "kind": "file", "name": "build/maplibre/controls/CopyrightControl.js", "content": "import { getMapGlCopyrights } from '../../common/utils';\n/**\n * @private\n */\nconst DEFAULT_SEPARATOR = ' | ';\n/**\n * Display layer's attributions trying to remove duplicated ones.\n *\n * @example\n * import { Map } from 'maplibre-gl';\n * import { CopyrightControl } from 'mobility-toolbox-js/maplibre';\n *\n * const map = new Map({\n * container: 'map',\n * style: `https://maps.geops.io/styles/travic_v2/style.json?key=${window.apiKey}`,\n * });\n *\n * const control = new CopyrightControl();\n * map.addControl(control);\n *\n *\n * @see MapLibre Realtime layer example\n *\n * @implements {maplibregl.IControl}\n *\n * @public\n */\nclass CopyrightControl {\n constructor(options = {}) {\n this.options = options;\n }\n getDefaultPosition() {\n return 'bottom-right';\n }\n onAdd(map) {\n this.map = map;\n if (!this.container) {\n this.container = document.createElement('div');\n }\n this.render = this.render.bind(this);\n this.map.on('idle', this.render);\n this.map.on('sourcedata', this.render);\n this.map.on('styledata', this.render);\n this.render();\n return this.container;\n }\n onRemove() {\n var _a, _b;\n if ((_a = this.container) === null || _a === void 0 ? void 0 : _a.parentElement) {\n (_b = this.container.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(this.container);\n }\n if (this.map) {\n this.map.off('sourcedata', this.render);\n this.map.off('styledata', this.render);\n this.map.off('idle', this.render);\n }\n this.map = undefined;\n return this.container;\n }\n render() {\n var _a, _b;\n if (this.map && this.container) {\n const separator = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.separator) || DEFAULT_SEPARATOR;\n const attribs = ((_b = this.options) === null || _b === void 0 ? void 0 : _b.customAttribution) || getMapGlCopyrights(this.map);\n const content = (Array.isArray(attribs) ? attribs : [attribs]).join(separator);\n if (this.container.innerHTML !== content) {\n this.content = content;\n this.container.innerHTML = this.content;\n }\n }\n }\n}\nexport default CopyrightControl;\n", @@ -9726,7 +10005,7 @@ "lineNumber": 1 }, { - "__docId__": 443, + "__docId__": 453, "kind": "variable", "name": "DEFAULT_SEPARATOR", "memberof": "build/maplibre/controls/CopyrightControl.js", @@ -9746,7 +10025,7 @@ "ignore": true }, { - "__docId__": 444, + "__docId__": 454, "kind": "class", "name": "CopyrightControl", "memberof": "build/maplibre/controls/CopyrightControl.js", @@ -9770,7 +10049,7 @@ ] }, { - "__docId__": 445, + "__docId__": 455, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9784,7 +10063,7 @@ "undocument": true }, { - "__docId__": 446, + "__docId__": 456, "kind": "member", "name": "options", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9801,7 +10080,7 @@ } }, { - "__docId__": 447, + "__docId__": 457, "kind": "method", "name": "getDefaultPosition", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9821,7 +10100,7 @@ } }, { - "__docId__": 448, + "__docId__": 458, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9848,7 +10127,7 @@ } }, { - "__docId__": 449, + "__docId__": 459, "kind": "member", "name": "map", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9865,7 +10144,7 @@ } }, { - "__docId__": 450, + "__docId__": 460, "kind": "member", "name": "container", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9882,7 +10161,7 @@ } }, { - "__docId__": 452, + "__docId__": 462, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9902,7 +10181,7 @@ } }, { - "__docId__": 454, + "__docId__": 464, "kind": "method", "name": "render", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9918,7 +10197,7 @@ "return": null }, { - "__docId__": 455, + "__docId__": 465, "kind": "member", "name": "content", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -9935,7 +10214,7 @@ } }, { - "__docId__": 456, + "__docId__": 466, "kind": "file", "name": "build/maplibre/controls/index.js", "content": "// eslint-disable-next-line import/prefer-default-export\nexport { default as CopyrightControl } from './CopyrightControl';\n", @@ -9946,7 +10225,7 @@ "lineNumber": 1 }, { - "__docId__": 457, + "__docId__": 467, "kind": "file", "name": "build/maplibre/index.js", "content": "export * from '../api';\nexport * from '../common';\nexport * from './controls';\nexport * from './layers';\nexport * from './utils';\n", @@ -9957,7 +10236,7 @@ "lineNumber": 1 }, { - "__docId__": 458, + "__docId__": 468, "kind": "file", "name": "build/maplibre/layers/Layer.js", "content": "import { Evented } from 'maplibre-gl';\nimport { v4 as uuid } from 'uuid';\n/**\n * A class representing a layer to display on an Maplibre map.\n *\n * @example\n * import { Layer } from 'mobility-toolbox-js/Maplibre';\n *\n * const layer = new Layer({ id:'MyLayer' });\n *\n * @implements {maplibregl.CustomLayerInterface}\n * @extends {maplibregl.Evented}\n * @private\n */\nclass Layer extends Evented {\n constructor(options = {}) {\n super();\n this.options = {};\n this.type = 'custom';\n this.options = options;\n this.id = options.id || uuid();\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onAdd(map, gl) {\n this.map = map;\n }\n onRemove(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n map, \n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n gl) {\n this.map = undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n render(gl) { }\n}\nexport default Layer;\n", @@ -9968,7 +10247,7 @@ "lineNumber": 1 }, { - "__docId__": 459, + "__docId__": 469, "kind": "class", "name": "Layer", "memberof": "build/maplibre/layers/Layer.js", @@ -9992,7 +10271,7 @@ ] }, { - "__docId__": 460, + "__docId__": 470, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10006,7 +10285,7 @@ "undocument": true }, { - "__docId__": 461, + "__docId__": 471, "kind": "member", "name": "options", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10023,7 +10302,7 @@ } }, { - "__docId__": 462, + "__docId__": 472, "kind": "member", "name": "type", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10040,7 +10319,7 @@ } }, { - "__docId__": 464, + "__docId__": 474, "kind": "member", "name": "id", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10057,7 +10336,7 @@ } }, { - "__docId__": 465, + "__docId__": 475, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10086,7 +10365,7 @@ "return": null }, { - "__docId__": 466, + "__docId__": 476, "kind": "member", "name": "map", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10103,7 +10382,7 @@ } }, { - "__docId__": 467, + "__docId__": 477, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10132,7 +10411,7 @@ "return": null }, { - "__docId__": 469, + "__docId__": 479, "kind": "method", "name": "render", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10155,7 +10434,7 @@ "return": null }, { - "__docId__": 470, + "__docId__": 480, "kind": "file", "name": "build/maplibre/layers/RealtimeLayer.js", "content": "var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _RealtimeLayer_internalId;\nimport { point } from '@turf/helpers';\nimport transformRotate from '@turf/transform-rotate';\nimport { getHeight, getWidth } from 'ol/extent';\nimport { fromLonLat } from 'ol/proj';\nimport RealtimeEngine from '../../common/utils/RealtimeEngine';\nimport { getSourceCoordinates } from '../utils';\nimport Layer from './Layer';\n/**\n * A Maplibre layer able to display data from the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { Map } from 'maplibre-gl';\n * import { RealtimeLayer } from 'mobility-toolbox-js/maplibre';\n *\n * // Define the map\n * const map = new Map({ ... });\n *\n * // Define your layer map\n * const layer = new RealtimeLayer({\n * apiKey: \"yourApiKey\"\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n * // Add the layer to your map *\n * map.on('load', () => {\n * map.addLayer(layer);\n * });\n *\n *\n * @see RealtimeAPI\n * @see MapLibre Realtime layer example\n *\n * @implements {maplibregl.CustomLayerInterface}\n * @extends {maplibregl.Evented}\n * @classproperty {function} filter - Filter out a train. This function must be fast, it is executed for every trajectory on every render frame.\n * @classproperty {RealtimeMode} mode - The realtime mode to use.\n * @classproperty {RealtimeMot[]} mots - Filter trains by its mode of transportation. It filters trains on backend side.\n * @classproperty {RealtimeTenant} tenant - Filter trains by its tenant. It filters trains on backend side.\n * @classproperty {function} sort - Sort trains. This function must be fast, it is executed on every render frame.\n * @classproperty {function} style - Function to style the vehicles.\n s\n * @public\n */\nclass RealtimeLayer extends Layer {\n get canvas() {\n return this.engine.canvas;\n }\n get pixelRatio() {\n return this.engine.pixelRatio || 1;\n }\n set pixelRatio(pixelRatio) {\n this.engine.pixelRatio = pixelRatio || 1;\n }\n /**\n * Constructor.\n *\n * @param {RealtimeLayerOptions} options\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {FilterFunction} options.filter Filter out a train. This function must be fast, it is executed for every trajectory on every render frame.\n * @param {getMotsByZoomFunction} options.getMotsByZoom Returns for each zoom level the list of MOTs to display. It filters trains on backend side.\n * @param {number} [options.minZoomInterpolation=8] Minimal zoom level where to start to interpolate train positions.\n * @param {RealtimeMode} [options.mode='topographic'] The realtime mode to use.\n * @param {SortFunction} options.sort Sort trains. This function must be fast, it is executed on every render frame.\n * @param {RealtimeStyleFunction} options.style Function to style the vehicles.\n * @param {RealtimeTenant} options.tenant Filter trains by its tenant. It filters trains on backend side.\n * @param {string} [options.url=\"wss://api.geops.io/tracker-ws/v1/\"] The geOps Realtime API url.\n */\n constructor(options = {}) {\n var _a;\n const id = (options === null || options === void 0 ? void 0 : options.id) || 'realtime';\n super(Object.assign(Object.assign({}, options), { id: `realtime-custom-${id}` }));\n _RealtimeLayer_internalId.set(this, void 0);\n __classPrivateFieldSet(this, _RealtimeLayer_internalId, id, \"f\");\n this.engine = new RealtimeEngine(Object.assign({ getViewState: this.getViewState.bind(this), onRender: this.onRealtimeEngineRender.bind(this) }, options));\n this.sourceId = __classPrivateFieldGet(this, _RealtimeLayer_internalId, \"f\");\n this.source = {\n // Set to true if the canvas source is animated. If the canvas is static, animate should be set to false to improve performance.\n animate: true,\n // @ts-expect-error bad type definition\n attribution: (_a = options.attribution) === null || _a === void 0 ? void 0 : _a.join(', '),\n canvas: this.canvas,\n // Set a default coordinates, it will be overrides on next data update\n coordinates: [\n [0, 0],\n [1, 1],\n [2, 2],\n [0, 0],\n ],\n loaded: true,\n type: 'canvas',\n };\n this.layer = {\n id: __classPrivateFieldGet(this, _RealtimeLayer_internalId, \"f\"),\n layout: {\n visibility: 'visible',\n },\n paint: {\n 'raster-fade-duration': 0,\n 'raster-opacity': 1,\n 'raster-resampling': 'nearest', // important otherwise it looks blurry\n },\n source: this.sourceId,\n type: 'raster',\n };\n this.onLoad = this.onLoad.bind(this);\n this.onMove = this.onMove.bind(this);\n this.onMoveEnd = this.onMoveEnd.bind(this);\n this.onZoomEnd = this.onZoomEnd.bind(this);\n }\n /**\n * Return the current view state. Used by the RealtimeEngine.\n * @private\n */\n getViewState() {\n if (!this.map) {\n return {};\n }\n if (!this.pixelRatio) {\n this.pixelRatio = 1;\n }\n const { height, width } = this.map.getCanvas();\n const center = this.map.getCenter();\n // We use turf here to have good transform.\n // @ts-expect-error bad type definition\n const leftBottom = this.map.unproject({\n x: 0,\n y: height / this.pixelRatio,\n }); // southWest\n // @ts-expect-error bad type definition\n const rightTop = this.map.unproject({\n x: width / this.pixelRatio,\n y: 0,\n }); // north east\n const coord0 = transformRotate(point([leftBottom.lng, leftBottom.lat]), -this.map.getBearing(), {\n pivot: [center.lng, center.lat],\n }).geometry.coordinates;\n const coord1 = transformRotate(point([rightTop.lng, rightTop.lat]), -this.map.getBearing(), {\n pivot: [center.lng, center.lat],\n }).geometry.coordinates;\n const bounds = [...fromLonLat(coord0), ...fromLonLat(coord1)];\n const xResolution = getWidth(bounds) / (width / this.pixelRatio);\n const yResolution = getHeight(bounds) / (height / this.pixelRatio);\n const res = Math.max(xResolution, yResolution);\n // Coordinate of trajectories are in mercator so we have to pass the proper resolution and center in mercator.\n return {\n center: fromLonLat([center.lng, center.lat]),\n extent: bounds,\n pixelRatio: this.pixelRatio,\n resolution: res,\n rotation: -(this.map.getBearing() * Math.PI) / 180,\n size: [width / this.pixelRatio, height / this.pixelRatio],\n visible: true,\n zoom: this.map.getZoom() - 1,\n };\n }\n /**\n * Add sources, layers and listeners to the map.\n */\n onAdd(map, gl) {\n super.onAdd(map, gl);\n this.engine.attachToMap();\n if (map.isStyleLoaded()) {\n this.onLoad();\n }\n map.on('load', this.onLoad);\n }\n onLoad() {\n var _a, _b, _c, _d;\n if (!((_a = this.map) === null || _a === void 0 ? void 0 : _a.getSource(this.sourceId))) {\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.addSource(this.sourceId, this.source);\n }\n if (!((_c = this.map) === null || _c === void 0 ? void 0 : _c.getLayer(this.layer.id))) {\n (_d = this.map) === null || _d === void 0 ? void 0 : _d.addLayer(this.layer, this.id);\n }\n this.start();\n }\n /**\n * Callback on 'move' event.\n */\n onMove() {\n this.engine.renderTrajectories();\n }\n /**\n * Callback on 'moveend' event.\n */\n onMoveEnd() {\n this.engine.renderTrajectories();\n if (this.engine.isUpdateBboxOnMoveEnd) {\n this.engine.setBbox();\n }\n }\n /**\n * Callback when the RealtimeEngine has rendered successfully.\n */\n onRealtimeEngineRender() {\n var _a;\n if ((_a = this.map) === null || _a === void 0 ? void 0 : _a.style) {\n const extent = getSourceCoordinates(this.map, this.pixelRatio);\n const source = this.map.getSource(this.sourceId);\n if (source) {\n // @ts-expect-error bad type definition\n source.setCoordinates(extent);\n }\n }\n }\n /**\n * Remove source, layers and listeners from the map.\n */\n onRemove(map, gl) {\n this.engine.detachFromMap();\n this.stop();\n map.off('load', this.onLoad);\n if (map.getLayer(this.layer.id)) {\n map.removeLayer(this.layer.id);\n }\n if (map.getSource(this.sourceId)) {\n map.removeSource(this.sourceId);\n }\n super.onRemove(map, gl);\n }\n onZoomEnd() {\n this.engine.onZoomEnd();\n }\n /**\n * Start updating vehicles position.\n *\n * @public\n */\n start() {\n var _a, _b, _c;\n this.engine.start();\n (_a = this.map) === null || _a === void 0 ? void 0 : _a.on('move', this.onMove);\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.on('moveend', this.onMoveEnd);\n (_c = this.map) === null || _c === void 0 ? void 0 : _c.on('zoomend', this.onZoomEnd);\n }\n /**\n * Stop updating vehicles position.\n *\n * @public\n */\n stop() {\n var _a, _b, _c;\n this.engine.stop();\n (_a = this.map) === null || _a === void 0 ? void 0 : _a.off('move', this.onMove);\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.off('moveend', this.onMoveEnd);\n (_c = this.map) === null || _c === void 0 ? void 0 : _c.off('zoomend', this.onZoomEnd);\n }\n}\n_RealtimeLayer_internalId = new WeakMap();\nexport default RealtimeLayer;\n", @@ -10166,7 +10445,7 @@ "lineNumber": 1 }, { - "__docId__": 471, + "__docId__": 481, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10187,7 +10466,7 @@ "ignore": true }, { - "__docId__": 472, + "__docId__": 482, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10208,7 +10487,7 @@ "ignore": true }, { - "__docId__": 473, + "__docId__": 483, "kind": "class", "name": "RealtimeLayer", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10262,7 +10541,7 @@ ] }, { - "__docId__": 474, + "__docId__": 484, "kind": "get", "name": "canvas", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10281,7 +10560,7 @@ } }, { - "__docId__": 475, + "__docId__": 485, "kind": "get", "name": "pixelRatio", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10300,7 +10579,7 @@ } }, { - "__docId__": 476, + "__docId__": 486, "kind": "set", "name": "pixelRatio", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10314,7 +10593,7 @@ "undocument": true }, { - "__docId__": 477, + "__docId__": 487, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10435,7 +10714,7 @@ ] }, { - "__docId__": 478, + "__docId__": 488, "kind": "member", "name": "engine", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10452,7 +10731,7 @@ } }, { - "__docId__": 479, + "__docId__": 489, "kind": "member", "name": "sourceId", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10469,7 +10748,7 @@ } }, { - "__docId__": 480, + "__docId__": 490, "kind": "member", "name": "source", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10486,7 +10765,7 @@ } }, { - "__docId__": 481, + "__docId__": 491, "kind": "member", "name": "layer", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10503,7 +10782,7 @@ } }, { - "__docId__": 486, + "__docId__": 496, "kind": "method", "name": "getViewState", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10522,7 +10801,7 @@ } }, { - "__docId__": 488, + "__docId__": 498, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10550,7 +10829,7 @@ "return": null }, { - "__docId__": 489, + "__docId__": 499, "kind": "method", "name": "onLoad", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10566,7 +10845,7 @@ "return": null }, { - "__docId__": 490, + "__docId__": 500, "kind": "method", "name": "onMove", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10581,7 +10860,7 @@ "return": null }, { - "__docId__": 491, + "__docId__": 501, "kind": "method", "name": "onMoveEnd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10596,7 +10875,7 @@ "return": null }, { - "__docId__": 492, + "__docId__": 502, "kind": "method", "name": "onRealtimeEngineRender", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10611,7 +10890,7 @@ "return": null }, { - "__docId__": 493, + "__docId__": 503, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10639,7 +10918,7 @@ "return": null }, { - "__docId__": 494, + "__docId__": 504, "kind": "method", "name": "onZoomEnd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10655,7 +10934,7 @@ "return": null }, { - "__docId__": 495, + "__docId__": 505, "kind": "method", "name": "start", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10670,7 +10949,7 @@ "return": null }, { - "__docId__": 496, + "__docId__": 506, "kind": "method", "name": "stop", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10685,7 +10964,7 @@ "return": null }, { - "__docId__": 497, + "__docId__": 507, "kind": "file", "name": "build/maplibre/layers/index.js", "content": "export { default as Layer } from './Layer';\nexport { default as RealtimeLayer } from './RealtimeLayer';\n", @@ -10696,7 +10975,7 @@ "lineNumber": 1 }, { - "__docId__": 498, + "__docId__": 508, "kind": "file", "name": "build/maplibre/utils/getMercatorResolution.js", "content": "import { getHeight, getWidth } from 'ol/extent';\nimport { fromLonLat } from 'ol/proj';\n/**\n * Get the current resolution of a Maplibre map.\n * @param {maplibregl.Map} map A map object.\n */\nconst getMercatorResolution = (map) => {\n const bounds = map.getBounds().toArray();\n const a = fromLonLat(bounds[0]);\n const b = fromLonLat(bounds[1]);\n const extent = [...a, ...b];\n const { height, width } = map.getCanvas();\n const xResolution = getWidth(extent) / width;\n const yResolution = getHeight(extent) / height;\n return Math.max(xResolution, yResolution);\n};\nexport default getMercatorResolution;\n", @@ -10707,7 +10986,7 @@ "lineNumber": 1 }, { - "__docId__": 499, + "__docId__": 509, "kind": "function", "name": "getMercatorResolution", "memberof": "build/maplibre/utils/getMercatorResolution.js", @@ -10740,7 +11019,7 @@ } }, { - "__docId__": 500, + "__docId__": 510, "kind": "file", "name": "build/maplibre/utils/getSourceCoordinates.js", "content": "/**\n * Get the canvas source coordinates of the current map's extent.\n * @param {maplibregl.Map} map A map object.\n * @param {number} [pixelRatio=1] The pixel ratio.\n */\nexport const getSourceCoordinates = (map, pixelRatio = 1) => {\n // Requesting getBounds is not enough when we rotate the map, so we request manually each corner.\n const { height, width } = map.getCanvas();\n // @ts-expect-error - to fix\n const leftTop = map.unproject({ x: 0, y: 0 });\n // @ts-expect-error - to fix\n const leftBottom = map.unproject({ x: 0, y: height / pixelRatio }); // southWest\n // @ts-expect-error - to fix\n const rightBottom = map.unproject({\n x: width / pixelRatio,\n y: height / pixelRatio,\n });\n // @ts-expect-error - to fix\n const rightTop = map.unproject({ x: width / pixelRatio, y: 0 }); // north east\n return [\n [leftTop.lng, leftTop.lat],\n [rightTop.lng, rightTop.lat],\n [rightBottom.lng, rightBottom.lat],\n [leftBottom.lng, leftBottom.lat],\n ];\n};\nexport default getSourceCoordinates;\n", @@ -10751,7 +11030,7 @@ "lineNumber": 1 }, { - "__docId__": 501, + "__docId__": 511, "kind": "function", "name": "getSourceCoordinates", "memberof": "build/maplibre/utils/getSourceCoordinates.js", @@ -10796,7 +11075,7 @@ } }, { - "__docId__": 502, + "__docId__": 512, "kind": "file", "name": "build/maplibre/utils/index.js", "content": "export { default as getMercatorResolution } from './getMercatorResolution';\nexport { default as getSourceCoordinates } from './getSourceCoordinates';\n", @@ -10807,7 +11086,7 @@ "lineNumber": 1 }, { - "__docId__": 503, + "__docId__": 513, "kind": "file", "name": "build/ol/controls/CopyrightControl.js", "content": "import Control from 'ol/control/Control';\nimport { inView } from 'ol/layer/Layer';\nimport createDefaultCopyrightElement from '../../common/utils/createDefaultCopyrightElt';\nimport removeDuplicate from '../../common/utils/removeDuplicate';\n/**\n * Display layer's copyrights. Adding the possibility to format them as you wish.\n *\n * @example\n * import { Map } from 'ol';\n * import { CopyrightControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map',\n * });\n *\n * const control = new CopyrightControl();\n * map.addControl(control);\n *\n *\n * @see OpenLayers Realtime layer example\n *\n * @extends {ol/control/Control~Control}\n *\n */\nclass CopyrightControl extends Control {\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {Function} format Function used to format the list of copyrights available to a single string. By default join all the copyrights with a |.\n * @public\n */\n constructor(options = {}) {\n const element = createDefaultCopyrightElement();\n element.className = options.className || 'mbt-copyright';\n super(Object.assign({ element }, options));\n this.format =\n options.format ||\n ((copyrights) => {\n return copyrights === null || copyrights === void 0 ? void 0 : copyrights.join(' | ');\n });\n }\n render({ frameState }) {\n if (!frameState) {\n this.element.innerHTML = '';\n return;\n }\n let copyrights = [];\n // This code loop comes mainly from ol.\n frameState === null || frameState === void 0 ? void 0 : frameState.layerStatesArray.forEach((layerState) => {\n var _a;\n const { layer } = layerState;\n if (frameState && inView(layerState, frameState.viewState)) {\n const attribFunc = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getAttributions();\n if (attribFunc) {\n copyrights = copyrights.concat(attribFunc(frameState));\n }\n if (layer === null || layer === void 0 ? void 0 : layer.get('copyrights')) {\n let copyProp = layer.get('copyrights');\n copyProp = !Array.isArray(copyProp) ? [copyProp] : copyProp;\n if (copyProp === null || copyProp === void 0 ? void 0 : copyProp.length) {\n copyrights.push(...copyProp);\n }\n }\n }\n });\n const unique = removeDuplicate(copyrights) || [];\n this.element.innerHTML = this.format(unique);\n }\n}\nexport default CopyrightControl;\n", @@ -10818,7 +11097,7 @@ "lineNumber": 1 }, { - "__docId__": 504, + "__docId__": 514, "kind": "class", "name": "CopyrightControl", "memberof": "build/ol/controls/CopyrightControl.js", @@ -10842,7 +11121,7 @@ ] }, { - "__docId__": 505, + "__docId__": 515, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -10877,7 +11156,7 @@ ] }, { - "__docId__": 506, + "__docId__": 516, "kind": "member", "name": "format", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -10894,7 +11173,7 @@ } }, { - "__docId__": 507, + "__docId__": 517, "kind": "method", "name": "render", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -10921,7 +11200,7 @@ "return": null }, { - "__docId__": 508, + "__docId__": 518, "kind": "file", "name": "build/ol/controls/RoutingControl.js", "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport { Feature } from 'ol';\nimport Control from 'ol/control/Control';\nimport { click } from 'ol/events/condition';\nimport BaseEvent from 'ol/events/Event';\nimport { buffer } from 'ol/extent';\nimport { GeoJSON } from 'ol/format';\nimport { LineString, Point } from 'ol/geom';\nimport { Modify } from 'ol/interaction';\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { fromLonLat, toLonLat } from 'ol/proj';\nimport VectorSource from 'ol/source/Vector';\nimport { RoutingAPI } from '../../api';\n// Examples for a single hop:\n// basel sbb a station named \"basel sbb\"\n// ZUE, station \"Zürich HB\" by its common abbreviation\n// Zürich Hauptbahnhof or HBF Zürich are all valid synonyms für \"Zürich HB\"\n// @47.37811,8.53935 a station at position 47.37811, 8.53935\n// @47.37811,8.53935$4 track 4 in a station at position 47.37811, 8.53935\n// zürich hb@47.37811,8.53935$8 track 8 in station \"Zürich HB\" at position 47.37811, 8.53935\nconst REGEX_VIA_POINT = /^([^@$!\\n]*)(@?([\\d.]+),([\\d.]+))?(\\$?([a-zA-Z0-9]{0,2}))$/;\n// Examples for a single hop:\n//\n// 47.37811,8.53935 a position 47.37811, 8.53935\nconst REGEX_VIA_POINT_COORD = /^([\\d.]+),([\\d.]+)$/;\n// Examples for a single hop:\n//\n// !8596126 a station with id 8596126\n// !8596126$4 a station with id 8596126\nconst REGEX_VIA_POINT_STATION_ID = /^!([^$]*)(\\$?([a-zA-Z0-9]{0,2}))$/;\nconst STOP_FETCH_ABORT_CONTROLLER_KEY = 'stop-fetch';\nconst getFlatCoordinatesFromSegments = (segmentArray) => {\n const coords = [];\n segmentArray.forEach((seg) => {\n var _a;\n const coordArr = (_a = seg.getGeometry()) === null || _a === void 0 ? void 0 : _a.getCoordinates();\n if (coordArr === null || coordArr === void 0 ? void 0 : coordArr.length) {\n coords.push(...coordArr);\n }\n });\n return coords;\n};\n/**\n * This OpenLayers control allows the user to add and modifiy via points to\n * a map and request a route from the [geOps Routing API](https://developer.geops.io/apis/routing/).\n *\n * @example\n * import { Map } from 'ol';\n * import { RoutingControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map'\n * });\n *\n * const control = new RoutingControl();\n *\n * map.addControl(control);\n *\n * @classproperty {string} mot - Mean of transport to be used for routing.\n * @classproperty {VectorLayer} routingLayer - Layer for adding route features.\n * @classproperty {boolean} loading - True if the control is requesting the backend.\n *\n * @see Openlayers routing example\n *\n * @extends {ol/control/Control~Control}\n *\n * @public\n */\nclass RoutingControl extends Control {\n get active() {\n return this.get('active');\n }\n set active(newValue) {\n this.set('active', newValue);\n }\n get loading() {\n return this.get('loading');\n }\n set loading(newValue) {\n this.set('loading', newValue);\n }\n get modify() {\n return this.get('modify');\n }\n set modify(newValue) {\n this.set('modify', newValue);\n }\n get mot() {\n return this.get('mot');\n }\n set mot(newValue) {\n this.set('mot', newValue);\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {Object} options.apiParams Request parameters. See [geOps Routing API documentation](https://developer.geops.io/apis/routing/).\n * @param {Array.>} [options.graphs=[['osm', 0, 99]]] - Array of routing graphs and min/max zoom levels. If you use the control in combination with the [geOps Maps API](https://developer.geops.io/apis/maps/), you may want to use the optimal level of generalizations: \"[['gen4', 0, 8], ['gen3', 8, 9], ['gen2', 9, 11], ['gen1', 11, 13], ['osm', 13, 99]]\".\n * @param {string} [options.mot=\"bus\"] Mean of transport to be used for routing.\n * @param {function} options.onRouteError Callback on request errors.\n * @param {VectorLayer} [options.routingLayer=new VectorLayer()] Vector layer for adding route features.\n * @param {boolean} [options.snapToClosestStation=false] If true, the routing will snap the coordinate to the closest station. Default to false.\n * @param {StyleLike} options.style Style of the default vector layer.\n * @param {boolean} [options.useRawViaPoints=fale] Experimental property. If true, it allows the user to add via points using different kind of string. See \"via\" parameter defined by the [geOps Routing API](https://developer.geops.io/apis/routing/). Default to false, only array of coordinates and station's id are supported as via points.\n * @param {string} [options.url='https://api.geops.io/routing/v1/'] [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.\n * @public\n */\n constructor(options = {}) {\n var _a;\n super(options);\n this.abortControllers = {};\n this.cacheStationData = {};\n this.format = new GeoJSON({ featureProjection: 'EPSG:3857' });\n this.graphs = [];\n this.initialRouteDrag = {};\n this.segments = [];\n this.snapToClosestStation = false;\n this.useRawViaPoints = false;\n this.viaPoints = [];\n if (!this.element) {\n this.createDefaultElement();\n }\n /** True if the control is requesting the backend. */\n this.loading = false;\n this.active = options.active || true;\n this.graphs = (_a = options.graphs) !== null && _a !== void 0 ? _a : [['osm', 0, 99]];\n this.mot = options.mot || 'bus';\n this.modify = options.modify !== false;\n this.apiParams = options.apiParams;\n this.useRawViaPoints = options.useRawViaPoints || false;\n this.snapToClosestStation = options.snapToClosestStation || false;\n this.apiKey = options.apiKey;\n this.stopsApiKey = options.stopsApiKey || this.apiKey;\n this.stopsApiUrl = options.stopsApiUrl || 'https://api.geops.io/stops/v1/';\n this.api = new RoutingAPI(Object.assign({}, options));\n this.routingLayer =\n options.routingLayer ||\n new VectorLayer({\n source: new VectorSource(),\n style: options.style,\n });\n this.onRouteError =\n options.onRouteError ||\n ((error) => {\n this.dispatchEvent(new BaseEvent('change:route'));\n this.reset();\n console.error(error);\n });\n this.onMapClick = this.onMapClick.bind(this);\n this.onModifyEnd = this.onModifyEnd.bind(this);\n this.onModifyStart = this.onModifyStart.bind(this);\n this.createModifyInteraction();\n this.on('propertychange', (evt) => {\n if (evt.key === 'active') {\n this.onActiveChange();\n }\n if (evt.key === 'mot') {\n if (this.viaPoints) {\n void this.drawRoute();\n }\n }\n });\n }\n /**\n * Calculate at which resolutions corresponds each generalizations.\n *\n * @private\n */\n static getGraphsResolutions(graphs, map) {\n const view = map.getView();\n return graphs.map(([, minZoom, maxZoom]) => {\n return [\n view.getResolutionForZoom(minZoom),\n view.getResolutionForZoom(maxZoom || minZoom + 1),\n ];\n });\n }\n /**\n * Aborts viapoint and route requests\n * @private\n */\n abortRequests() {\n var _a;\n // Abort Routing API requests\n this.graphs.forEach((graph) => {\n const graphName = graph[0] || '';\n if (this.abortControllers[graphName]) {\n this.abortControllers[graphName].abort();\n }\n this.abortControllers[graphName] = new AbortController();\n });\n // Abort Stops API requests\n (_a = this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]) === null || _a === void 0 ? void 0 : _a.abort();\n this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY] =\n new AbortController();\n this.loading = false;\n }\n activate() {\n var _a;\n const map = this.getMap();\n if (map) {\n this.format = new GeoJSON({\n featureProjection: map.getView().getProjection(),\n });\n this.graphsResolutions = RoutingControl.getGraphsResolutions(this.graphs, map);\n // Clean the modifyInteraction if present\n if (this.modifyInteraction) {\n map.removeInteraction(this.modifyInteraction);\n }\n // Add modify interaction, RoutingLayer and listeners\n // this.routingLayer?.attachToMap(this.getMap());\n if (this.modifyInteraction) {\n map.addInteraction(this.modifyInteraction);\n }\n (_a = this.modifyInteraction) === null || _a === void 0 ? void 0 : _a.setActive(this.modify);\n this.addListeners();\n }\n }\n /**\n * Add click listener to map.\n * @private\n */\n addListeners() {\n var _a;\n if (!this.modify) {\n return;\n }\n this.removeListeners();\n // @ts-expect-error improve ts types\n this.onMapClickKey = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.on('singleclick', this.onMapClick);\n }\n /**\n * Adds/Replaces a viaPoint to the viaPoints array and redraws route:\n * Adds a viaPoint at end of array by default.\n * If an index is passed a viaPoint is added at the specified index.\n * If an index is passed and overwrite x is > 0, x viaPoints at the specified\n * index are replaced with a single new viaPoint.\n * @param {string | Coordinate} coordinatesOrString Array of coordinates or a string representing a station\n * @param {number} [index=-1] Integer representing the index of the added viaPoint. If not specified, the viaPoint is added at the end of the array.\n * @param {number} [overwrite=0] Marks the number of viaPoints that are removed at the specified index on add.\n * @public\n */\n addViaPoint(coordinatesOrString, index = -1, overwrite = 0) {\n /* Add/Insert/Overwrite viapoint and redraw route */\n this.viaPoints.splice(index === -1 ? this.viaPoints.length : index, overwrite, coordinatesOrString);\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n /**\n * Define a default element.\n *\n * @private\n */\n createDefaultElement() {\n this.element = document.createElement('button');\n this.element.id = 'ol-toggle-routing';\n this.element.innerHTML = 'Toggle Route Control';\n this.element.onclick = () => {\n return this.active ? this.deactivate() : this.activate();\n };\n Object.assign(this.element.style, {\n position: 'absolute',\n right: '10px',\n top: '10px',\n });\n }\n /**\n * Create the interaction used to modify vertexes of features.\n * @private\n */\n createModifyInteraction() {\n var _a;\n /**\n * @type {ol.interaction.Modify}\n * @private\n */\n // Define and add modify interaction\n this.modifyInteraction = new Modify({\n // hitDetection: this.routingLayer, // TODO: wait for ol, fixed in https://github.com/openlayers/openlayers/pull/16393\n deleteCondition: (e) => {\n var _a;\n const feats = \n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n ((_a = e.target) === null || _a === void 0 ? void 0 : _a.getFeaturesAtPixel(e.pixel, {\n hitTolerance: 5,\n })) || [];\n const viaPoint = feats.find((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' && feat.get('index');\n });\n if (click(e) && viaPoint) {\n // Remove node & viaPoint if an existing viaPoint was clicked\n this.removeViaPoint(viaPoint.get('index'));\n return true;\n }\n return false;\n },\n pixelTolerance: 6,\n source: ((_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) || undefined,\n });\n this.modifyInteraction.on('modifystart', this.onModifyStart);\n this.modifyInteraction.on('modifyend', this.onModifyEnd);\n this.modifyInteraction.setActive(false);\n }\n deactivate() {\n const map = this.getMap();\n if (map) {\n // Remove modify interaction, RoutingLayer, listeners and viaPoints\n // this.routingLayer?.detachFromMap();\n if (this.modifyInteraction) {\n map.removeInteraction(this.modifyInteraction);\n }\n this.removeListeners();\n this.reset();\n }\n }\n /**\n * Draws route on map using an array of coordinates:\n * If a single coordinate is passed a single point feature is added to map.\n * If two or more coordinates are passed a request to the RoutingAPI fetches\n * the route using the passed coordinates and the current mot.\n * @private\n */\n drawRoute() {\n var _a, _b;\n /* Calls RoutingAPI to draw a route using the viaPoints array */\n this.abortRequests();\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n if (!this.viaPoints.length) {\n return null;\n }\n if (this.viaPoints.length === 1) {\n // Add point for first node\n return this.drawViaPoint(this.viaPoints[0], 0, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]);\n }\n const formattedViaPoints = this.viaPoints.map((viaPoint) => {\n var _a;\n if (Array.isArray(viaPoint)) {\n const projection = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.getView().getProjection();\n // viaPoint is a coordinate\n // Coordinates need to be reversed as required by the backend RoutingAPI\n const [lon, lat] = toLonLat(viaPoint, projection);\n return this.snapToClosestStation ? [`@${lat}`, lon] : [lat, lon];\n }\n // viaPoint is a string to use as it is\n return this.useRawViaPoints ? viaPoint : `!${viaPoint}`;\n });\n this.loading = true;\n // Create point features for the viaPoints\n this.viaPoints.forEach((viaPoint, idx) => {\n void this.drawViaPoint(viaPoint, idx, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]);\n });\n return Promise.all(this.graphs.map(([graph], index) => {\n const { signal } = this.abortControllers[graph || ''];\n if (!this.api) {\n return Promise.resolve([]);\n }\n return this.api\n .route(Object.assign({ 'coord-punish': 1000.0, 'coord-radius': 100.0, elevation: false, \n // @ts-expect-error improve type graph must include osm in the enum\n graph, mot: this.mot, 'resolve-hops': false, via: `${formattedViaPoints.join('|')}` }, (this.apiParams || {})), { signal })\n .then((featureCollection) => {\n var _a, _b, _c;\n this.segments = this.format.readFeatures(featureCollection);\n if (this.mot === 'foot') {\n // Extract unique values from viaPoint target value\n const uniqueVias = this.segments.reduce((resultVias, currentFeat) => {\n const segTrg = currentFeat.get('trg');\n return resultVias.find((via) => {\n return via[0] === segTrg[0] && via[1] === segTrg[1];\n })\n ? resultVias\n : [...resultVias, segTrg];\n }, []);\n // Create LineString features from segments with same unique value\n this.segments = uniqueVias.map((via) => {\n const viaSegments = this.segments.filter((seg) => {\n const segTrg = seg.get('trg');\n return segTrg[0] === via[0] && segTrg[1] === via[1];\n });\n const coords = getFlatCoordinatesFromSegments(viaSegments);\n return new Feature({\n geometry: new LineString(coords),\n });\n });\n }\n // Create the new route. This route will be modifiable by the Modifiy interaction.\n const coords = getFlatCoordinatesFromSegments(this.segments);\n const routeFeature = new Feature({\n geometry: new LineString(coords),\n });\n routeFeature.set('graph', graph);\n routeFeature.set('mot', this.mot);\n if (this.graphsResolutions &&\n ((_a = this.graphsResolutions[index]) === null || _a === void 0 ? void 0 : _a.length) >= 2) {\n routeFeature.set('minResolution', this.graphsResolutions[index][0]);\n routeFeature.set('maxResolution', this.graphsResolutions[index][1]);\n }\n (_c = (_b = this.routingLayer) === null || _b === void 0 ? void 0 : _b.getSource()) === null || _c === void 0 ? void 0 : _c.addFeature(routeFeature);\n this.loading = false;\n })\n .catch((error) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access\n if (/AbortError/.test(error === null || error === void 0 ? void 0 : error.name)) {\n // Ignore abort error\n return;\n }\n this.segments = [];\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n this.loading = false;\n });\n }));\n }\n /**\n * Draw a via point. This function can parse all the possibilitiies\n *\n * @private\n */\n drawViaPoint(viaPoint, idx, abortController) {\n var _a, _b, _c, _d, _e, _f, _g, _h;\n const pointFeature = new Feature();\n pointFeature.set('viaPointIdx', idx);\n // The via point is a coordinate using the current map's projection\n if (Array.isArray(viaPoint)) {\n pointFeature.setGeometry(new Point(viaPoint));\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n // Possibility to parse:\n //\n // !8596126 a station with id 8596126\n // !8596126$4 a station with id 8596126\n if (!this.useRawViaPoints || REGEX_VIA_POINT_STATION_ID.test(viaPoint)) {\n let stationId;\n let track;\n if (this.useRawViaPoints) {\n [, stationId, , track] =\n REGEX_VIA_POINT_STATION_ID.exec(viaPoint) || [];\n }\n else {\n [stationId, track] = viaPoint.split('$');\n }\n return fetch(`${this.stopsApiUrl}lookup/${stationId}?key=${this.stopsApiKey}`, { signal: abortController.signal })\n .then((res) => {\n return res.json();\n })\n .then((stationData) => {\n var _a, _b, _c, _d;\n const { coordinates } = ((_b = (_a = stationData === null || stationData === void 0 ? void 0 : stationData.features) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.geometry) || {};\n if (!coordinates) {\n console.log(`No coordinates found for station ${stationId}`, stationData);\n }\n this.cacheStationData[viaPoint] = fromLonLat(coordinates);\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(fromLonLat(coordinates)));\n (_d = (_c = this.routingLayer) === null || _c === void 0 ? void 0 : _c.getSource()) === null || _d === void 0 ? void 0 : _d.addFeature(pointFeature);\n return pointFeature;\n })\n .catch((error) => {\n var _a, _b;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access\n if (/AbortError/.test(error.message)) {\n // Ignore abort error\n return;\n }\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n this.loading = false;\n });\n }\n // Only when this.useRawViaPoints is true.\n // Possibility to parse:\n //\n // 47.37811,8.53935 a position 47.37811, 8.53935\n if (this.useRawViaPoints && REGEX_VIA_POINT_COORD.test(viaPoint)) {\n const [lat, lon] = REGEX_VIA_POINT_COORD.exec(viaPoint) || [];\n if (lon && lat) {\n const floatLon = parseFloat(lon);\n const floatLat = parseFloat(lat);\n const coordinates = fromLonLat([floatLon, floatLat], (_c = this.getMap()) === null || _c === void 0 ? void 0 : _c.getView().getProjection());\n pointFeature.setGeometry(new Point(coordinates));\n (_e = (_d = this.routingLayer) === null || _d === void 0 ? void 0 : _d.getSource()) === null || _e === void 0 ? void 0 : _e.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n }\n // Only when this.useRawViaPoints is true.\n // It will parse the via point to find some name, id, track coordinates.\n //\n // Possibility to parse:\n //\n // @47.37811,8.53935 a station at position 47.37811, 8.53935\n // @47.37811,8.53935$4 track 4 in a station at position 47.37811, 8.53935\n // zürich hb@47.37811,8.53935$8 track 8 in station \"Zürich HB\" at position 47.37811, 8.53935\n const [, stationName, , lat, lon, , track] = REGEX_VIA_POINT.exec(viaPoint) || [];\n if (lon && lat) {\n const coordinates = fromLonLat([parseFloat(lon), parseFloat(lat)], (_f = this.getMap()) === null || _f === void 0 ? void 0 : _f.getView().getProjection());\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(coordinates));\n (_h = (_g = this.routingLayer) === null || _g === void 0 ? void 0 : _g.getSource()) === null || _h === void 0 ? void 0 : _h.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n if (stationName) {\n return fetch(`${this.stopsApiUrl}?key=${this.stopsApiKey}&q=${stationName}&limit=1`, { signal: abortController.signal })\n .then((res) => {\n return res.json();\n })\n .then((stationData) => {\n var _a, _b, _c;\n const { coordinates } = ((_a = stationData === null || stationData === void 0 ? void 0 : stationData.features) === null || _a === void 0 ? void 0 : _a[0].geometry) || {};\n if (!coordinates) {\n throw new Error(`No coordinates found for station ${stationName}`);\n }\n this.cacheStationData[viaPoint] = fromLonLat(coordinates);\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(fromLonLat(coordinates)));\n (_c = (_b = this.routingLayer) === null || _b === void 0 ? void 0 : _b.getSource()) === null || _c === void 0 ? void 0 : _c.addFeature(pointFeature);\n return pointFeature;\n })\n .catch((error) => {\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n this.loading = false;\n return null;\n });\n }\n return Promise.resolve(null);\n }\n /**\n * Activet7deactivate the control when activ eproperty changes\n * @private\n */\n onActiveChange() {\n if (this.get('active')) {\n this.activate();\n }\n else {\n this.deactivate();\n }\n this.render();\n }\n /**\n * Used on click on map while control is active:\n * By default adds a viaPoint to the end of array.\n * If an existing viaPoint is clicked removes the clicked viaPoint.\n * @private\n */\n onMapClick(evt) {\n const feats = evt.target.getFeaturesAtPixel(evt.pixel, {\n hitTolerance: 5,\n layerFilter: (layer) => {\n return layer === this.routingLayer;\n },\n });\n const viaPoint = feats.find((feat) => {\n var _a;\n return (((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' &&\n feat.get('viaPointIdx') !== undefined);\n });\n if (viaPoint) {\n // Remove existing viaPoint on click and abort viaPoint add\n this.removeViaPoint(viaPoint.get('viaPointIdx'));\n return;\n }\n this.addViaPoint(evt.coordinate);\n }\n /**\n * Used on end of the modify interaction. Resolves feature modification:\n * Line drag creates new viaPoint at the final coordinate of drag.\n * Point drag replaces old viaPoint.\n * @private\n */\n onModifyEnd(evt) {\n const coord = evt.mapBrowserEvent.coordinate;\n const { oldRoute, segmentIndex, viaPoint } = this.initialRouteDrag || {};\n // If viaPoint is being relocated overwrite the old viaPoint\n if (viaPoint) {\n return this.addViaPoint(coord, viaPoint.get('viaPointIdx'), 1);\n }\n // In case there is no route overwrite first coordinate\n if (!oldRoute) {\n return this.addViaPoint(coord, 0, 1);\n }\n // We can't add a via point because we haven't found which segment has been modified.\n if (segmentIndex === -1) {\n return Promise.reject(new Error('No segment found'));\n }\n // Insert new viaPoint at the modified segment index + 1\n return this.addViaPoint(coord, (segmentIndex || 0) + 1);\n }\n /**\n * Used on start of the modify interaction. Stores relevant data\n * in this.initialRouteDrag object\n * @private\n */\n onModifyStart(evt) {\n var _a;\n // When modify start, we search the index of the segment that is modifying.\n let segmentIndex = -1;\n const route = evt.features.getArray().find((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'LineString';\n });\n // Find the segment index that is being modified\n if ((route === null || route === void 0 ? void 0 : route.getGeometry()) && evt.mapBrowserEvent.coordinate) {\n // We use a buff extent to fix floating issues , see https://github.com/openlayers/openlayers/issues/7130#issuecomment-535856422\n const closestExtent = buffer(new Point(\n // @ts-expect-error bad def\n (_a = route.getGeometry()) === null || _a === void 0 ? void 0 : _a.getClosestPoint(evt.mapBrowserEvent.coordinate)).getExtent(), 0.001);\n segmentIndex = this.segments.findIndex((segment) => {\n var _a;\n return (_a = segment.getGeometry()) === null || _a === void 0 ? void 0 : _a.intersectsExtent(closestExtent);\n });\n }\n // Find the viaPoint that is being modified\n const viaPoint = (evt.features.getArray().filter((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point';\n }) || [])[0];\n // Write object with modify info\n this.initialRouteDrag = {\n oldRoute: route === null || route === void 0 ? void 0 : route.clone(),\n segmentIndex,\n viaPoint,\n };\n }\n /**\n * Remove click listener from map.\n * @private\n */\n removeListeners() {\n if (this.onMapClickKey) {\n unByKey(this.onMapClickKey);\n }\n }\n /**\n * Removes a viaPoint at the passed array index and redraws route\n * By default the last viaPoint is removed.\n * @param {number} index Integer representing the index of the viaPoint to delete.\n * @public\n */\n removeViaPoint(index = (this.viaPoints || []).length - 1) {\n /* Remove viapoint and redraw route */\n if (this.viaPoints.length && this.viaPoints[index]) {\n this.viaPoints.splice(index, 1);\n }\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n render() { }\n /**\n * Removes all viaPoints, clears the source and triggers a change event\n * @public\n */\n reset() {\n var _a, _b;\n // Clear viaPoints and source\n this.abortRequests();\n this.viaPoints = [];\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n setMap(map) {\n super.setMap(map);\n if (map && this.active) {\n this.activate();\n }\n else if (!map) {\n this.active = false;\n }\n }\n /**\n * Replaces the current viaPoints with a new coordinate array.\n * @param {Array>} coordinateArray Array of nested coordinates\n * @public\n */\n setViaPoints(coordinateArray) {\n this.viaPoints = [...coordinateArray];\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n}\nexport default RoutingControl;\n", @@ -10932,7 +11211,7 @@ "lineNumber": 1 }, { - "__docId__": 509, + "__docId__": 519, "kind": "variable", "name": "REGEX_VIA_POINT", "memberof": "build/ol/controls/RoutingControl.js", @@ -10953,7 +11232,7 @@ "ignore": true }, { - "__docId__": 510, + "__docId__": 520, "kind": "variable", "name": "REGEX_VIA_POINT_COORD", "memberof": "build/ol/controls/RoutingControl.js", @@ -10974,7 +11253,7 @@ "ignore": true }, { - "__docId__": 511, + "__docId__": 521, "kind": "variable", "name": "REGEX_VIA_POINT_STATION_ID", "memberof": "build/ol/controls/RoutingControl.js", @@ -10995,7 +11274,7 @@ "ignore": true }, { - "__docId__": 512, + "__docId__": 522, "kind": "variable", "name": "STOP_FETCH_ABORT_CONTROLLER_KEY", "memberof": "build/ol/controls/RoutingControl.js", @@ -11016,7 +11295,7 @@ "ignore": true }, { - "__docId__": 513, + "__docId__": 523, "kind": "function", "name": "getFlatCoordinatesFromSegments", "memberof": "build/ol/controls/RoutingControl.js", @@ -11047,7 +11326,7 @@ "ignore": true }, { - "__docId__": 514, + "__docId__": 524, "kind": "class", "name": "RoutingControl", "memberof": "build/ol/controls/RoutingControl.js", @@ -11085,7 +11364,7 @@ ] }, { - "__docId__": 515, + "__docId__": 525, "kind": "get", "name": "active", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11104,7 +11383,7 @@ } }, { - "__docId__": 516, + "__docId__": 526, "kind": "set", "name": "active", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11118,7 +11397,7 @@ "undocument": true }, { - "__docId__": 517, + "__docId__": 527, "kind": "get", "name": "loading", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11137,7 +11416,7 @@ } }, { - "__docId__": 518, + "__docId__": 528, "kind": "set", "name": "loading", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11151,7 +11430,7 @@ "undocument": true }, { - "__docId__": 519, + "__docId__": 529, "kind": "get", "name": "modify", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11170,7 +11449,7 @@ } }, { - "__docId__": 520, + "__docId__": 530, "kind": "set", "name": "modify", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11184,7 +11463,7 @@ "undocument": true }, { - "__docId__": 521, + "__docId__": 531, "kind": "get", "name": "mot", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11203,7 +11482,7 @@ } }, { - "__docId__": 522, + "__docId__": 532, "kind": "set", "name": "mot", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11217,7 +11496,7 @@ "undocument": true }, { - "__docId__": 523, + "__docId__": 533, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11354,7 +11633,7 @@ ] }, { - "__docId__": 524, + "__docId__": 534, "kind": "member", "name": "abortControllers", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11371,7 +11650,7 @@ } }, { - "__docId__": 525, + "__docId__": 535, "kind": "member", "name": "cacheStationData", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11388,7 +11667,7 @@ } }, { - "__docId__": 526, + "__docId__": 536, "kind": "member", "name": "format", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11405,7 +11684,7 @@ } }, { - "__docId__": 527, + "__docId__": 537, "kind": "member", "name": "graphs", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11422,7 +11701,7 @@ } }, { - "__docId__": 528, + "__docId__": 538, "kind": "member", "name": "initialRouteDrag", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11439,7 +11718,7 @@ } }, { - "__docId__": 529, + "__docId__": 539, "kind": "member", "name": "segments", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11456,7 +11735,7 @@ } }, { - "__docId__": 530, + "__docId__": 540, "kind": "member", "name": "snapToClosestStation", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11473,7 +11752,7 @@ } }, { - "__docId__": 531, + "__docId__": 541, "kind": "member", "name": "useRawViaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11490,7 +11769,7 @@ } }, { - "__docId__": 532, + "__docId__": 542, "kind": "member", "name": "viaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11507,7 +11786,7 @@ } }, { - "__docId__": 538, + "__docId__": 548, "kind": "member", "name": "apiParams", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11524,7 +11803,7 @@ } }, { - "__docId__": 541, + "__docId__": 551, "kind": "member", "name": "apiKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11541,7 +11820,7 @@ } }, { - "__docId__": 542, + "__docId__": 552, "kind": "member", "name": "stopsApiKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11558,7 +11837,7 @@ } }, { - "__docId__": 543, + "__docId__": 553, "kind": "member", "name": "stopsApiUrl", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11575,7 +11854,7 @@ } }, { - "__docId__": 544, + "__docId__": 554, "kind": "member", "name": "api", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11592,7 +11871,7 @@ } }, { - "__docId__": 545, + "__docId__": 555, "kind": "member", "name": "routingLayer", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11609,7 +11888,7 @@ } }, { - "__docId__": 546, + "__docId__": 556, "kind": "member", "name": "onRouteError", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11626,7 +11905,7 @@ } }, { - "__docId__": 550, + "__docId__": 560, "kind": "method", "name": "getGraphsResolutions", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11658,7 +11937,7 @@ } }, { - "__docId__": 551, + "__docId__": 561, "kind": "method", "name": "abortRequests", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11673,7 +11952,7 @@ "return": null }, { - "__docId__": 553, + "__docId__": 563, "kind": "method", "name": "activate", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11689,7 +11968,7 @@ "return": null }, { - "__docId__": 555, + "__docId__": 565, "kind": "member", "name": "graphsResolutions", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11706,7 +11985,7 @@ } }, { - "__docId__": 556, + "__docId__": 566, "kind": "method", "name": "addListeners", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11721,7 +12000,7 @@ "return": null }, { - "__docId__": 557, + "__docId__": 567, "kind": "member", "name": "onMapClickKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11738,7 +12017,7 @@ } }, { - "__docId__": 558, + "__docId__": 568, "kind": "method", "name": "addViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11789,7 +12068,7 @@ "return": null }, { - "__docId__": 559, + "__docId__": 569, "kind": "method", "name": "createDefaultElement", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11804,7 +12083,7 @@ "return": null }, { - "__docId__": 560, + "__docId__": 570, "kind": "member", "name": "element", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11821,7 +12100,7 @@ } }, { - "__docId__": 561, + "__docId__": 571, "kind": "method", "name": "createModifyInteraction", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11836,7 +12115,7 @@ "return": null }, { - "__docId__": 562, + "__docId__": 572, "kind": "member", "name": "modifyInteraction", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11855,7 +12134,7 @@ } }, { - "__docId__": 563, + "__docId__": 573, "kind": "method", "name": "deactivate", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11871,7 +12150,7 @@ "return": null }, { - "__docId__": 564, + "__docId__": 574, "kind": "method", "name": "drawRoute", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11890,7 +12169,7 @@ } }, { - "__docId__": 571, + "__docId__": 581, "kind": "method", "name": "drawViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11928,7 +12207,7 @@ } }, { - "__docId__": 574, + "__docId__": 584, "kind": "method", "name": "onActiveChange", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11943,7 +12222,7 @@ "return": null }, { - "__docId__": 575, + "__docId__": 585, "kind": "method", "name": "onMapClick", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11965,7 +12244,7 @@ "return": null }, { - "__docId__": 576, + "__docId__": 586, "kind": "method", "name": "onModifyEnd", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11991,7 +12270,7 @@ } }, { - "__docId__": 577, + "__docId__": 587, "kind": "method", "name": "onModifyStart", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12013,7 +12292,7 @@ "return": null }, { - "__docId__": 579, + "__docId__": 589, "kind": "method", "name": "removeListeners", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12028,7 +12307,7 @@ "return": null }, { - "__docId__": 580, + "__docId__": 590, "kind": "method", "name": "removeViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12054,7 +12333,7 @@ "return": null }, { - "__docId__": 581, + "__docId__": 591, "kind": "method", "name": "render", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12070,7 +12349,7 @@ "return": null }, { - "__docId__": 582, + "__docId__": 592, "kind": "method", "name": "reset", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12085,7 +12364,7 @@ "return": null }, { - "__docId__": 584, + "__docId__": 594, "kind": "method", "name": "setMap", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12108,7 +12387,7 @@ "return": null }, { - "__docId__": 586, + "__docId__": 596, "kind": "method", "name": "setViaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12134,7 +12413,7 @@ "return": null }, { - "__docId__": 588, + "__docId__": 598, "kind": "file", "name": "build/ol/controls/StopFinderControl.js", "content": "import Control from 'ol/control/Control';\nimport { fromLonLat } from 'ol/proj';\nimport StopFinderControlCommon from '../../common/controls/StopFinderControlCommon';\nimport createDefaultStopFinderElement from '../../common/utils/createDefaultStopFinderElt';\n/**\n * This OpenLayers control allows to search stations from the [geOps Stops API](https://developer.geops.io/apis/stops/).\n *\n * @example\n * import { Map } from 'ol';\n * import { StopFinderControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map',\n * });\n *\n * const control = new StopFinderControl({\n * apiKey: [yourApiKey]\n * });\n *\n * map.addControl(control);\n *\n *\n * @see Openlayers search example\n *\n * @extends {ol/control/Control~Control}\n *\n * @public\n */\nclass StopFinderControl extends Control {\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {HTMLElement} options.element HTML element where to attach input and suggestions.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {StopsSearchParams} [options.apiParams={ limit: 20 }] Request parameters. See [geOps Stops API documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).\n * @param {string} [options.placeholder='Search for a stop...'] Input field placeholder.\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] [geOps Stops API](https://developer.geops.io/apis/stops/) url.\n * @public\n */\n constructor(options) {\n const element = createDefaultStopFinderElement();\n element.className = (options === null || options === void 0 ? void 0 : options.className) || 'mbt-stop-finder';\n const opt = Object.assign({ element }, (options || {}));\n super(opt);\n this.controller = new StopFinderControlCommon(Object.assign({ onSuggestionClick: this.onSuggestionClick.bind(this) }, opt));\n }\n onSuggestionClick(suggestion) {\n var _a;\n const coord = fromLonLat(suggestion.geometry.coordinates);\n (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.getView().setCenter(coord);\n }\n /**\n * Search for stations using a query.\n *\n * @param {string} q Query used to search stops.\n * @param {AbortController} abortController Abort controller used to abort requests.\n * @returns {Promise>}\n * @public\n */\n search(q, abortController) {\n return this.controller.search(q, abortController);\n }\n}\nexport default StopFinderControl;\n", @@ -12145,7 +12424,7 @@ "lineNumber": 1 }, { - "__docId__": 589, + "__docId__": 599, "kind": "class", "name": "StopFinderControl", "memberof": "build/ol/controls/StopFinderControl.js", @@ -12169,7 +12448,7 @@ ] }, { - "__docId__": 590, + "__docId__": 600, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12250,7 +12529,7 @@ ] }, { - "__docId__": 591, + "__docId__": 601, "kind": "member", "name": "controller", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12267,7 +12546,7 @@ } }, { - "__docId__": 592, + "__docId__": 602, "kind": "method", "name": "onSuggestionClick", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12290,7 +12569,7 @@ "return": null }, { - "__docId__": 593, + "__docId__": 603, "kind": "method", "name": "search", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12339,7 +12618,7 @@ } }, { - "__docId__": 594, + "__docId__": 604, "kind": "file", "name": "build/ol/controls/index.js", "content": "export { default as CopyrightControl } from './CopyrightControl';\nexport { default as RoutingControl } from './RoutingControl';\nexport { default as StopFinderControl } from './StopFinderControl';\n", @@ -12350,7 +12629,7 @@ "lineNumber": 1 }, { - "__docId__": 595, + "__docId__": 605, "kind": "file", "name": "build/ol/index.js", "content": "export * from '../api';\nexport * from '../common';\nexport * from './controls';\nexport * from './layers';\nexport * from './styles';\nexport * from './utils';\n", @@ -12361,7 +12640,7 @@ "lineNumber": 1 }, { - "__docId__": 596, + "__docId__": 606, "kind": "file", "name": "build/ol/layers/Layer.js", "content": "import debounce from 'lodash.debounce';\nimport OLLayer from 'ol/layer/Layer';\nimport { unByKey } from 'ol/Observable';\nimport LayerRenderer from 'ol/renderer/Layer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n // eslint-disable-next-line no-console\n console.warn(message);\n }, 1000);\n}\nclass EmptyLayerRenderer extends LayerRenderer {\n prepareFrame() {\n return true;\n }\n renderFrame() {\n // Return an empty div as a placeholder HTMLElement\n return document.createElement('div');\n }\n}\n/**\n * An OpenLayers layer here only for backward compatibility v2.\n * @deprecated Use an OpenLayers Layer instead.\n */\nclass Layer extends OLLayer {\n constructor(options = {}) {\n super(options);\n this.olEventsKeys = [];\n defineDeprecatedProperties(this, options);\n deprecated('Layer is deprecated. Use an OpenLayers Layer instead.');\n // Backward compatibility\n this.olEventsKeys = [];\n }\n clone(newOptions) {\n return new Layer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n // ol does not like when it returns null.\n createRenderer() {\n return new EmptyLayerRenderer(this);\n }\n detachFromMap() {\n // Backward compatibility\n unByKey(this.olEventsKeys);\n }\n}\nexport default Layer;\n", @@ -12372,7 +12651,7 @@ "lineNumber": 1 }, { - "__docId__": 597, + "__docId__": 607, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/Layer.js", @@ -12392,7 +12671,7 @@ "ignore": true }, { - "__docId__": 598, + "__docId__": 608, "kind": "class", "name": "EmptyLayerRenderer", "memberof": "build/ol/layers/Layer.js", @@ -12412,7 +12691,7 @@ "ignore": true }, { - "__docId__": 599, + "__docId__": 609, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/layers/Layer.js~EmptyLayerRenderer", @@ -12432,7 +12711,7 @@ } }, { - "__docId__": 600, + "__docId__": 610, "kind": "method", "name": "renderFrame", "memberof": "build/ol/layers/Layer.js~EmptyLayerRenderer", @@ -12452,7 +12731,7 @@ } }, { - "__docId__": 601, + "__docId__": 611, "kind": "class", "name": "Layer", "memberof": "build/ol/layers/Layer.js", @@ -12471,7 +12750,7 @@ ] }, { - "__docId__": 602, + "__docId__": 612, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12485,7 +12764,7 @@ "undocument": true }, { - "__docId__": 603, + "__docId__": 613, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12502,7 +12781,7 @@ } }, { - "__docId__": 605, + "__docId__": 615, "kind": "method", "name": "clone", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12529,7 +12808,7 @@ } }, { - "__docId__": 606, + "__docId__": 616, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12549,7 +12828,7 @@ } }, { - "__docId__": 607, + "__docId__": 617, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12565,10 +12844,10 @@ "return": null }, { - "__docId__": 608, + "__docId__": 618, "kind": "file", "name": "build/ol/layers/MaplibreLayer.js", - "content": "import { MapLibreLayer } from '@geoblocks/ol-maplibre-layer/lib';\nimport debounce from 'lodash.debounce';\nimport { unByKey } from 'ol/Observable';\nimport { getUrlWithParams } from '../../common/utils';\nimport MaplibreLayerRenderer from '../renderers/MaplibreLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nconst buildStyleUrl = (url, style, apiKey, apiKeyName) => {\n return getUrlWithParams(`${url}/styles/${style}/style.json`, {\n [apiKeyName]: apiKey,\n }).toString();\n};\nexport let deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n console.warn(message);\n }, 1000);\n}\n/**\n * An OpenLayers layer able to display data from the [geOps Maps API](https://developer.geops.io/apis/maps).\n *\n * @example\n * import { MaplibreLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * // apiKeyName: 'key',\n * // mapLibreOptions: {\n * // interactive: false,\n * // trackResize: false,\n * // attributionControl: false,\n * // }\n * // queryRenderedFeaturesOptions: {\n * // layers: ['waters_lakes'], // map.getFeaturesAtPixel will only return lakes.\n * // },\n * // style: 'travic_v2',\n * // url: 'https://maps.geops.io',\n * });\n *\n * @classproperty {maplibregl.Map} mapLibreMap - The Maplibre map object. Readonly.\n * @classproperty {string} style - The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n *\n *\n * @see OpenLayers Maplibre layer example\n *\n * @extends {geoblocks/ol-maplibre-layer/MapLibreLayer}\n * @public\n */\nclass MaplibreLayer extends MapLibreLayer {\n set apiKey(newValue) {\n this.set('apiKey', newValue);\n }\n get apiKey() {\n return this.get('apiKey');\n }\n set apiKeyName(newValue) {\n this.set('apiKeyName', newValue);\n }\n get apiKeyName() {\n return this.get('apiKeyName');\n }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get maplibreMap() {\n deprecated('MaplibreLayer.maplibreMap is deprecated. Use layer.mapLibreMap.');\n return this.mapLibreMap;\n }\n // get queryRenderedFeaturesOptions(): maplibregl.QueryRenderedFeaturesOptions {\n // return this.get('queryRenderedFeaturesOptions');\n // }\n // set queryRenderedFeaturesOptions(\n // newValue: maplibregl.QueryRenderedFeaturesOptions,\n // ) {\n // this.set('queryRenderedFeaturesOptions', newValue);\n // }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get mbMap() {\n deprecated('MaplibreLayer.mbMap is deprecated. Use layer.maplibreMap.');\n return this.maplibreMap;\n }\n get style() {\n return this.get('style');\n }\n set style(newValue) {\n this.set('style', newValue);\n }\n get url() {\n return this.get('url');\n }\n set url(newValue) {\n this.set('url', newValue);\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Accesss key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiKeyName=\"key\"] The [geOps Maps API](https://developer.geops.io/apis/maps) key name.\n * @param {maplibregl.MapOptions} [options.mapLibreOptions={ interactive: false, trackResize: false, attributionControl: false }] MapLibre map options.\n * @param {string} [options.style=\"travic_v2\"] The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n * @param {string} [options.url=\"https://maps.geops.io\"] The [geOps Maps API](https://developer.geops.io/apis/maps) url.\n */\n constructor(options) {\n var _a;\n // Backward compatibility\n if (options.mapOptions && !options.mapLibreOptions) {\n deprecated('MaplibreLayer.mapOptions is deprecated. Use mapLibreOptions instead.');\n options.mapLibreOptions = options.mapOptions;\n }\n const newOptions = Object.assign(Object.assign({ apiKeyName: 'key', style: 'travic_v2', url: 'https://maps.geops.io' }, (options || {})), { mapLibreOptions: Object.assign({ fadeDuration: 10 }, (options.mapLibreOptions || {})) });\n if (!newOptions.mapLibreOptions.style &&\n ((_a = newOptions.url) === null || _a === void 0 ? void 0 : _a.includes('style.json'))) {\n newOptions.mapLibreOptions.style = newOptions.url;\n }\n else if (!newOptions.mapLibreOptions.style &&\n newOptions.apiKey &&\n newOptions.style &&\n typeof newOptions.style === 'string') {\n newOptions.mapLibreOptions.style = buildStyleUrl(newOptions.url, newOptions.style, newOptions.apiKey, newOptions.apiKeyName);\n }\n super(newOptions);\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // We save the options to be able to clone the layer.\n // and to see if the style is defined by the maplibreOptions given by the user.\n this.set('options', options);\n }\n /**\n * Initialize the layer and listen to feature clicks.\n */\n attachToMap() {\n const updateMaplibreMapDebounced = debounce(this.updateMaplibreMap.bind(this), 150);\n updateMaplibreMapDebounced();\n this.olEventsKeys.push(this.on('propertychange', (evt) => {\n if (/(url|style|apiKey|apiKeyName)/.test(evt.key)) {\n updateMaplibreMapDebounced();\n }\n }));\n }\n /**\n * Create a copy of the MaplibreLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MaplibreLayer} A MaplibreLayer layer\n * @public\n */\n clone(newOptions) {\n return new MaplibreLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreLayerRenderer(this);\n }\n detachFromMap() {\n unByKey(this.olEventsKeys);\n }\n disposeInternal() {\n const source = this.getSource();\n super.disposeInternal();\n // At this point mapLibreMap.style is undefined, so to avoid errors on layers removed after this one,\n // we set the mapLibreMap to null\n this.mapLibreMap = undefined;\n // We don't want the source removed\n this.setSource(source);\n }\n getStyle() {\n var _a;\n // If the style is a complete style object, use it directly.\n if (this.style &&\n typeof this.style === 'object' &&\n this.style.name &&\n this.style.version) {\n return this.style;\n }\n // If the url set is already a complete style url, use it directly.\n if (this.url.includes('style.json')) {\n return this.url;\n }\n // If the user has defined the style by the maplibreOptions, we use it directly.\n const opts = this.get('options');\n if ((_a = opts === null || opts === void 0 ? void 0 : opts.mapLibreOptions) === null || _a === void 0 ? void 0 : _a.style) {\n return opts.mapLibreOptions.style;\n }\n /// Otherwise build the complete style url.\n return buildStyleUrl(this.url, this.style, this.apiKey, this.apiKeyName);\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n updateMaplibreMap() {\n var _a;\n try {\n (_a = this.mapLibreMap) === null || _a === void 0 ? void 0 : _a.setStyle(this.getStyle(), { diff: false });\n }\n catch (e) {\n console.error('Error while updating MaplibreMap', e);\n }\n }\n}\nexport default MaplibreLayer;\n", + "content": "import { getMapLibreAttributions, MapLibreLayer, } from '@geoblocks/ol-maplibre-layer/lib';\nimport debounce from 'lodash.debounce';\nimport { unByKey } from 'ol/Observable';\nimport { Source } from 'ol/source';\nimport { getUrlWithParams } from '../../common/utils';\nimport getUrlWithPath from '../../common/utils/getUrlWithPath';\nimport MaplibreLayerRenderer from '../renderers/MaplibreLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nconst buildStyleUrl = (url, style, apiKey, apiKeyName) => {\n return getUrlWithParams(getUrlWithPath(url, `/styles/${style}/style.json`), {\n [apiKeyName]: apiKey,\n }).toString();\n};\nexport let deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n console.warn(message);\n }, 1000);\n}\n/**\n * An OpenLayers layer able to display data from the [geOps Maps API](https://developer.geops.io/apis/maps).\n *\n * @example\n * import { MaplibreLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * // apiKeyName: 'key',\n * // mapLibreOptions: {\n * // interactive: false,\n * // trackResize: false,\n * // attributionControl: false,\n * // }\n * // queryRenderedFeaturesOptions: {\n * // layers: ['waters_lakes'], // map.getFeaturesAtPixel will only return lakes.\n * // },\n * // style: 'travic_v2',\n * // url: 'https://maps.geops.io',\n * });\n *\n * @classproperty {maplibregl.Map} mapLibreMap - The Maplibre map object. Readonly.\n * @classproperty {string} style - The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n *\n *\n * @see OpenLayers Maplibre layer example\n *\n * @extends {geoblocks/ol-maplibre-layer/MapLibreLayer}\n * @public\n */\nclass MaplibreLayer extends MapLibreLayer {\n set apiKey(newValue) {\n this.set('apiKey', newValue);\n }\n get apiKey() {\n return this.get('apiKey');\n }\n set apiKeyName(newValue) {\n this.set('apiKeyName', newValue);\n }\n get apiKeyName() {\n return this.get('apiKeyName');\n }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get maplibreMap() {\n deprecated('MaplibreLayer.maplibreMap is deprecated. Use layer.mapLibreMap.');\n return this.mapLibreMap;\n }\n // get queryRenderedFeaturesOptions(): maplibregl.QueryRenderedFeaturesOptions {\n // return this.get('queryRenderedFeaturesOptions');\n // }\n // set queryRenderedFeaturesOptions(\n // newValue: maplibregl.QueryRenderedFeaturesOptions,\n // ) {\n // this.set('queryRenderedFeaturesOptions', newValue);\n // }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get mbMap() {\n deprecated('MaplibreLayer.mbMap is deprecated. Use layer.maplibreMap.');\n return this.maplibreMap;\n }\n get style() {\n return this.get('style');\n }\n set style(newValue) {\n this.set('style', newValue);\n }\n get url() {\n return this.get('url');\n }\n set url(newValue) {\n this.set('url', newValue);\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Accesss key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiKeyName=\"key\"] The [geOps Maps API](https://developer.geops.io/apis/maps) key name.\n * @param {maplibregl.MapOptions} [options.mapLibreOptions={ interactive: false, trackResize: false, attributionControl: false }] MapLibre map options.\n * @param {string} [options.style=\"travic_v2\"] The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n * @param {string} [options.url=\"https://maps.geops.io\"] The [geOps Maps API](https://developer.geops.io/apis/maps) url.\n */\n constructor(options) {\n var _a, _b;\n // Backward compatibility\n if (options.mapOptions && !options.mapLibreOptions) {\n deprecated('MaplibreLayer.mapOptions is deprecated. Use mapLibreOptions instead.');\n options.mapLibreOptions = options.mapOptions;\n }\n const newOptions = Object.assign(Object.assign({ apiKeyName: 'key', style: 'travic_v2', url: 'https://maps.geops.io' }, (options || {})), { mapLibreOptions: Object.assign({ fadeDuration: 10 }, (options.mapLibreOptions || {})), source: (_a = options.source) !== null && _a !== void 0 ? _a : new Source({\n // We define a default source until https://github.com/geoblocks/ol-maplibre-layer/pull/274/files\n // is merged and published\n attributions: () => {\n var _a, _b;\n const style = (_a = this.mapLibreMap) === null || _a === void 0 ? void 0 : _a.style;\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n if (!!this.mapLibreMap && !!style && !style.sourceCaches) {\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n this.mapLibreMap.style.sourceCaches =\n (_b = this.mapLibreMap.style.tileManagers) !== null && _b !== void 0 ? _b : {};\n }\n return getMapLibreAttributions(this.mapLibreMap);\n },\n }) });\n if (!newOptions.mapLibreOptions.style &&\n ((_b = newOptions.url) === null || _b === void 0 ? void 0 : _b.includes('style.json'))) {\n newOptions.mapLibreOptions.style = newOptions.url;\n }\n else if (!newOptions.mapLibreOptions.style &&\n newOptions.apiKey &&\n newOptions.style &&\n typeof newOptions.style === 'string') {\n newOptions.mapLibreOptions.style = buildStyleUrl(newOptions.url, newOptions.style, newOptions.apiKey, newOptions.apiKeyName);\n }\n super(newOptions);\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // We save the options to be able to clone the layer.\n // and to see if the style is defined by the maplibreOptions given by the user.\n this.set('options', options);\n }\n /**\n * Initialize the layer and listen to feature clicks.\n */\n attachToMap() {\n const updateMaplibreMapDebounced = debounce(this.updateMaplibreMap.bind(this), 150);\n this.olEventsKeys.push(this.on('propertychange', (evt) => {\n if (/(url|style|apiKey|apiKeyName)/.test(evt.key)) {\n updateMaplibreMapDebounced();\n }\n }));\n }\n /**\n * Create a copy of the MaplibreLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MaplibreLayer} A MaplibreLayer layer\n * @public\n */\n clone(newOptions) {\n return new MaplibreLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreLayerRenderer(this);\n }\n detachFromMap() {\n unByKey(this.olEventsKeys);\n }\n disposeInternal() {\n const source = this.getSource();\n super.disposeInternal();\n // At this point mapLibreMap.style is undefined, so to avoid errors on layers removed after this one,\n // we set the mapLibreMap to null\n this.mapLibreMap = undefined;\n // We don't want the source removed\n this.setSource(source);\n }\n getStyle() {\n var _a;\n // If the style is a complete style object, use it directly.\n if (this.style &&\n typeof this.style === 'object' &&\n this.style.name &&\n this.style.version) {\n return this.style;\n }\n // If the url set is already a complete style url, use it directly.\n if (this.url.includes('style.json')) {\n return this.url;\n }\n // If the user has defined the style by the maplibreOptions, we use it directly.\n const opts = this.get('options');\n if ((_a = opts === null || opts === void 0 ? void 0 : opts.mapLibreOptions) === null || _a === void 0 ? void 0 : _a.style) {\n return opts.mapLibreOptions.style;\n }\n /// Otherwise build the complete style url.\n return buildStyleUrl(this.url, this.style, this.apiKey, this.apiKeyName);\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n updateMaplibreMap() {\n var _a;\n try {\n (_a = this.mapLibreMap) === null || _a === void 0 ? void 0 : _a.setStyle(this.getStyle(), { diff: false });\n }\n catch (e) {\n console.error('Error while updating MaplibreMap', e);\n }\n }\n}\nexport default MaplibreLayer;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/layers/MaplibreLayer.js", "access": "private", @@ -12576,7 +12855,7 @@ "lineNumber": 1 }, { - "__docId__": 609, + "__docId__": 619, "kind": "function", "name": "buildStyleUrl", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12589,7 +12868,7 @@ "importPath": "mobility-toolbox-js/build/ol/layers/MaplibreLayer.js", "importStyle": null, "description": null, - "lineNumber": 7, + "lineNumber": 9, "undocument": true, "params": [ { @@ -12625,7 +12904,7 @@ "ignore": true }, { - "__docId__": 610, + "__docId__": 620, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12638,13 +12917,13 @@ "importPath": "mobility-toolbox-js/build/ol/layers/MaplibreLayer.js", "importStyle": "{deprecated}", "description": null, - "lineNumber": 12, + "lineNumber": 14, "undocument": true, "params": [], "return": null }, { - "__docId__": 611, + "__docId__": 621, "kind": "class", "name": "MaplibreLayer", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12661,7 +12940,7 @@ "see": [ "OpenLayers Maplibre layer example" ], - "lineNumber": 49, + "lineNumber": 51, "unknown": [ { "tagName": "@classproperty", @@ -12678,7 +12957,7 @@ ] }, { - "__docId__": 612, + "__docId__": 622, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12688,11 +12967,11 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#apiKey", "access": "private", "description": null, - "lineNumber": 50, + "lineNumber": 52, "undocument": true }, { - "__docId__": 613, + "__docId__": 623, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12702,7 +12981,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#apiKey", "access": "private", "description": null, - "lineNumber": 53, + "lineNumber": 55, "undocument": true, "type": { "types": [ @@ -12711,7 +12990,7 @@ } }, { - "__docId__": 614, + "__docId__": 624, "kind": "set", "name": "apiKeyName", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12721,11 +13000,11 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#apiKeyName", "access": "private", "description": null, - "lineNumber": 56, + "lineNumber": 58, "undocument": true }, { - "__docId__": 615, + "__docId__": 625, "kind": "get", "name": "apiKeyName", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12735,7 +13014,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#apiKeyName", "access": "private", "description": null, - "lineNumber": 59, + "lineNumber": 61, "undocument": true, "type": { "types": [ @@ -12744,7 +13023,7 @@ } }, { - "__docId__": 616, + "__docId__": 626, "kind": "get", "name": "maplibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12754,7 +13033,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#maplibreMap", "access": "private", "description": "", - "lineNumber": 65, + "lineNumber": 67, "deprecated": "Use layer.mapLibreMap.", "type": { "types": [ @@ -12763,7 +13042,7 @@ } }, { - "__docId__": 617, + "__docId__": 627, "kind": "get", "name": "mbMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12773,7 +13052,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#mbMap", "access": "private", "description": "", - "lineNumber": 80, + "lineNumber": 82, "deprecated": "Use layer.mapLibreMap.", "type": { "types": [ @@ -12782,7 +13061,7 @@ } }, { - "__docId__": 618, + "__docId__": 628, "kind": "get", "name": "style", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12792,7 +13071,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#style", "access": "private", "description": null, - "lineNumber": 84, + "lineNumber": 86, "undocument": true, "type": { "types": [ @@ -12801,7 +13080,7 @@ } }, { - "__docId__": 619, + "__docId__": 629, "kind": "set", "name": "style", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12811,11 +13090,11 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#style", "access": "private", "description": null, - "lineNumber": 87, + "lineNumber": 89, "undocument": true }, { - "__docId__": 620, + "__docId__": 630, "kind": "get", "name": "url", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12825,7 +13104,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#url", "access": "private", "description": null, - "lineNumber": 90, + "lineNumber": 92, "undocument": true, "type": { "types": [ @@ -12834,7 +13113,7 @@ } }, { - "__docId__": 621, + "__docId__": 631, "kind": "set", "name": "url", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12844,11 +13123,11 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#url", "access": "private", "description": null, - "lineNumber": 93, + "lineNumber": 95, "undocument": true }, { - "__docId__": 622, + "__docId__": 632, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12858,7 +13137,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#constructor", "access": "private", "description": "Constructor.", - "lineNumber": 106, + "lineNumber": 108, "params": [ { "nullable": null, @@ -12931,7 +13210,7 @@ ] }, { - "__docId__": 623, + "__docId__": 633, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12939,7 +13218,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#olEventsKeys", "access": "private", "description": null, - "lineNumber": 125, + "lineNumber": 141, "undocument": true, "type": { "types": [ @@ -12948,7 +13227,7 @@ } }, { - "__docId__": 624, + "__docId__": 634, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12958,12 +13237,12 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#attachToMap", "access": "private", "description": "Initialize the layer and listen to feature clicks.", - "lineNumber": 135, + "lineNumber": 151, "params": [], "return": null }, { - "__docId__": 625, + "__docId__": 635, "kind": "method", "name": "clone", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12973,7 +13252,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#clone", "access": "public", "description": "Create a copy of the MaplibreLayer.", - "lineNumber": 151, + "lineNumber": 166, "params": [ { "nullable": null, @@ -12996,7 +13275,7 @@ } }, { - "__docId__": 626, + "__docId__": 636, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13006,7 +13285,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#createRenderer", "access": "private", "description": null, - "lineNumber": 154, + "lineNumber": 169, "undocument": true, "params": [], "return": { @@ -13016,7 +13295,7 @@ } }, { - "__docId__": 627, + "__docId__": 637, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13026,13 +13305,13 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#detachFromMap", "access": "private", "description": null, - "lineNumber": 157, + "lineNumber": 172, "undocument": true, "params": [], "return": null }, { - "__docId__": 628, + "__docId__": 638, "kind": "method", "name": "disposeInternal", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13042,13 +13321,13 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#disposeInternal", "access": "private", "description": null, - "lineNumber": 160, + "lineNumber": 175, "undocument": true, "params": [], "return": null }, { - "__docId__": 629, + "__docId__": 639, "kind": "member", "name": "mapLibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13056,7 +13335,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#mapLibreMap", "access": "private", "description": null, - "lineNumber": 165, + "lineNumber": 180, "undocument": true, "type": { "types": [ @@ -13065,7 +13344,7 @@ } }, { - "__docId__": 630, + "__docId__": 640, "kind": "method", "name": "getStyle", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13075,7 +13354,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#getStyle", "access": "private", "description": null, - "lineNumber": 169, + "lineNumber": 184, "undocument": true, "params": [], "return": { @@ -13085,7 +13364,7 @@ } }, { - "__docId__": 631, + "__docId__": 641, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13095,7 +13374,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#setMapInternal", "access": "private", "description": null, - "lineNumber": 190, + "lineNumber": 205, "undocument": true, "params": [ { @@ -13108,7 +13387,7 @@ "return": null }, { - "__docId__": 632, + "__docId__": 642, "kind": "method", "name": "updateMaplibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13118,16 +13397,16 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#updateMaplibreMap", "access": "private", "description": null, - "lineNumber": 200, + "lineNumber": 215, "undocument": true, "params": [], "return": null }, { - "__docId__": 633, + "__docId__": 643, "kind": "file", "name": "build/ol/layers/MaplibreStyleLayer.js", - "content": "import debounce from 'lodash.debounce';\nimport { Layer } from 'ol/layer';\nimport { unByKey } from 'ol/Observable';\nimport { Source } from 'ol/source';\nimport { VECTOR_TILE_FEATURE_PROPERTY } from '../../common';\nimport MaplibreStyleLayerRenderer from '../renderers/MaplibreStyleLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((...messages) => {\n // eslint-disable-next-line no-console\n console.warn(...messages);\n }, 1000);\n}\n/**\n * Layer that helps show/hide a specific subset of style layers of a [MaplibreLayer](./MaplibreLayer.js~MaplibreLayer.html).\n *\n * @example\n * import { MaplibreLayer, MocoLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * maplibreLayer: maplibreLayer,\n * layersFilter: (layer) => {\n * // show/hide only style layers related to stations\n * return /station/.test(layer.id);\n * },\n * });\n *\n * @extends {ol/layer/Layer~Layer}\n * @public\n */\nclass MaplibreStyleLayer extends Layer {\n get beforeId() {\n return this.get('beforeId');\n }\n set beforeId(newValue) {\n this.set('beforeId', newValue);\n }\n get layers() {\n return this.get('layers') || [];\n }\n set layers(newValue) {\n this.set('layers', newValue);\n }\n get layersFilter() {\n return this.get('layersFilter');\n }\n set layersFilter(newValue) {\n this.set('layersFilter', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.maplibreLayer instead.\n */\n get mapboxLayer() {\n deprecated('Deprecated. Use maplibreLayer instead.');\n return this.get('maplibreLayer');\n }\n get maplibreLayer() {\n return this.get('maplibreLayer');\n }\n set maplibreLayer(newValue) {\n this.set('maplibreLayer', newValue);\n }\n get queryRenderedLayersFilter() {\n return this.get('queryRenderedLayersFilter');\n }\n set queryRenderedLayersFilter(newValue) {\n this.set('queryRenderedLayersFilter', newValue);\n }\n get sources() {\n return this.get('sources');\n }\n set sources(newValue) {\n this.set('sources', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.layer instead.\n */\n get styleLayer() {\n deprecated('Deprecated. Use MaplibreStyleLayer.layer instead.');\n return this.layers[0];\n }\n /**\n * @deprecated\n */\n set styleLayer(newValue) {\n deprecated('MaplibreStyleLayer.styleLayer is deprecated. Use MaplibreStyleLayer.layer instead.');\n this.layers = [newValue];\n }\n /**\n * Apply visibility to style layers that fits the styleLayersFilter function.\n */\n /**\n * @deprecated\n */\n get styleLayers() {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n return this.layers;\n }\n /**\n * @deprecated\n */\n set styleLayers(newValue) {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n this.layers = newValue;\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} [options.beforeId] The style layer id to use when the options.layers property is defined, unsused otherwise.\n * @param {maplibregl.AddLayerObject[]} [options.layers] The layers to add to the style on load.\n * @param {FilterFunction} [options.layersFilter] Filter function to decide which style layer to apply visiblity on. If not provided, the 'layers' property is used.\n * @param {MaplibreLayer} [options.maplibreLayer] The MaplibreLayer to use.\n * @param {FilterFunction} [options.queryRenderedLayersFilter] Filter function to decide which style layer are available for query.\n * @param {{[id: string]:maplibregl.SourceSpecification}} [options.sources] The sources to add to the style on load.\n * @public\n */\n constructor(options = {\n mapLibreOptions: { style: { layers: [], sources: {}, version: 8 } },\n }) {\n /** Manage renamed property for backward compatibility with v2 */\n if (options.mapboxLayer) {\n deprecated('options.mapboxLayer is deprecated. Use options.maplibreLayer instead.');\n // @ts-expect-error - mapboxLayer is deprecated\n options.maplibreLayer = options.mapboxLayer;\n delete options.mapboxLayer;\n }\n if (options.styleLayer) {\n deprecated('options.styleLayer is deprecated. Use options.layers instead.');\n options.layers = [options.styleLayer];\n delete options.styleLayer;\n }\n if (options.styleLayers) {\n deprecated('options.styleLayers is deprecated. Use options.layers instead.');\n options.layers = options.styleLayers;\n delete options.styleLayers;\n }\n if (options.styleLayersFilter) {\n deprecated('options.styleLayersFilter is deprecated. Use options.layersFilter instead.');\n options.layersFilter = options.styleLayersFilter;\n delete options.styleLayersFilter;\n }\n super(Object.assign({ source: new Source({}) }, options));\n this.highlightedFeatures = [];\n this.olEventsKeys = [];\n this.selectedFeatures = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // For cloning\n this.set('options', options);\n this.beforeId = options.beforeId;\n this.onLoad = this.onLoad.bind(this);\n if (!this.layersFilter && this.layers) {\n this.layersFilter = (layer) => {\n return !!this.layers.find((l) => {\n return layer.id === l.id;\n });\n };\n }\n }\n addLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((layer) => {\n // @ts-expect-error source is optional but exists in TS definition\n const { id, source } = layer;\n if ((!source || (source && mapLibreMap.getSource(source))) &&\n id &&\n !mapLibreMap.getLayer(id)) {\n mapLibreMap.addLayer(layer, this.beforeId);\n }\n });\n this.applyLayoutVisibility();\n }\n }\n addSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.entries(this.sources).forEach(([id, source]) => {\n if (!mapLibreMap.getSource(id)) {\n mapLibreMap.addSource(id, source);\n }\n });\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n applyLayoutVisibility(evt) {\n var _a, _b;\n if (!((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()) || !this.layersFilter) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n const visibilityValue = this.getVisible() ? 'visible' : 'none';\n const layers = style.layers || [];\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < layers.length; i += 1) {\n const layer = layers[i];\n if (this.layersFilter(layer)) {\n const { id } = layer;\n if (mapLibreMap.getLayer(id)) {\n mapLibreMap.setLayoutProperty(id, 'visibility', visibilityValue);\n // OL sets -Infinity, Infinity for minZoom and maxZoom.\n if (Number.isFinite(this.getMinZoom()) ||\n Number.isFinite(this.getMaxZoom())) {\n mapLibreMap.setLayerZoomRange(id, Number.isFinite(this.getMinZoom()) ? this.getMinZoom() - 1 : 0, // Maplibre zoom = ol zoom - 1\n Number.isFinite(this.getMaxZoom()) ? this.getMaxZoom() - 1 : 24);\n }\n }\n }\n }\n }\n /**\n * Initialize the layer.\n * @param {ol/Map~Map} map the Maplibre map.\n * @override\n */\n attachToMap(map) {\n const mapInternal = this.getMapInternal();\n if (!mapInternal || !this.maplibreLayer) {\n return;\n }\n // Apply the initial visibility if possible otherwise we wait for the load event of the layer\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n // mapLibreMap.loaded() and mapLibreMap.isStyleLoaded() are reliable only on the first call of init.\n // On the next call (when a topic change for example), these functions returns false because\n // the style is being modified.\n // That's why we rely on a property instead for the next calls.\n if (mapLibreMap.loaded()) {\n this.onLoad();\n }\n else {\n if (mapLibreMap.isStyleLoaded()) {\n this.onLoad();\n }\n else {\n void mapLibreMap.once('load', this.onLoad);\n }\n }\n }\n // Apply the visibiltity when layer's visibility change.\n this.olEventsKeys.push(\n // @ts-expect-error 'load' is a custom event\n this.maplibreLayer.on('load', this.onLoad.bind(this)), this.on('change:visible', (evt) => {\n // Once the map is loaded we can apply visiblity without waiting\n // the style. Maplibre take care of the application of style changes.\n this.applyLayoutVisibility(evt);\n }), this.on('propertychange', (evt) => {\n if (/(sources|layers|layersFilter|maplibreLayer|beforeId)/.test(evt.key)) {\n this.detachFromMap();\n this.attachToMap(map);\n }\n }), \n // When the style changes we wait that it is loaded to relaunch the onLoad\n this.maplibreLayer.on('propertychange', (evt) => {\n if (evt.key === 'style') {\n const mbMap = evt.target.mapLibreMap;\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('styledata', () => {\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('idle', () => {\n this.onLoad();\n }));\n }));\n }\n }));\n }\n /**\n * Create a copy of the MaplibreStyleLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MapboxStyleLayer} A MaplibreStyleLayer.\n * @public\n */\n clone(newOptions) {\n return new MaplibreStyleLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreStyleLayerRenderer(this);\n }\n /**\n * Terminate the layer.\n * @override\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n if ((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) {\n this.maplibreLayer.mapLibreMap.off('load', this.onLoad);\n this.removeLayers();\n this.removeSources();\n }\n }\n // /**\n // * Request feature information for a given coordinate.\n // * @param {ol/coordinate~Coordinate} coordinate Coordinate to request the information at.\n // * @return {Promise} Promise with features, layer and coordinate.\n // * @deprecated Use getFeatureInfoAtCoordinate([layer], coordinate) from mobility-toolbox-ol package instead.\n // */\n // getFeatureInfoAtCoordinate(\n // coordinate: Coordinate,\n // ): Promise {\n // deprecated(\n // `Deprecated. getFeatureInfoAtCoordinate([layer], coordinate) from ol package instead.`,\n // );\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // // Ignore the getFeatureInfo until the Maplibre map is loaded\n // if (!mapLibreMap.isStyleLoaded()) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // // We query features only on style layers used by this layer.\n // let layers = this.layers || [];\n // if (this.layersFilter) {\n // layers = mapLibreMap.getStyle().layers.filter(this.layersFilter);\n // }\n // if (this.queryRenderedLayersFilter) {\n // layers = mapLibreMap\n // .getStyle()\n // .layers.filter(this.queryRenderedLayersFilter);\n // }\n // return Promise.resolve({\n // coordinate,\n // features: [],\n // layer: this,\n // });\n // // this.maplibreLayer\n // // .getFeatureInfoAtCoordinate(coordinate, {\n // // layers: layers.map((layer) => layer && layer.id),\n // // validate: false,\n // // })\n // // .then((featureInfo: LayerGetFeatureInfoResponse) => {\n // // const features: Feature[] = featureInfo.features.filter(\n // // (feature: Feature) => {\n // // // @ts-expect-error\n // // return this.featureInfoFilter(\n // // feature,\n // // this.map?.getView().getResolution(),\n // // ) as Feature[];\n // // },\n // // );\n // // this.highlight(features);\n // // return { ...featureInfo, features, layer: this };\n // // });\n // }\n /**\n * Highlight a list of features.\n * @param {Array
    } [features=[]] Features to highlight.\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n highlight(features = []) {\n var _a;\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: true}) instead.`);\n // Filter out selected features\n const filtered = ((_a = this.highlightedFeatures) === null || _a === void 0 ? void 0 : _a.filter((feature) => {\n return !(this.selectedFeatures || [])\n .map((feat) => {\n return feat.getId();\n })\n .includes(feature.getId());\n })) || [];\n // Remove previous highlight\n this.setHoverState(filtered, false);\n this.highlightedFeatures = features;\n // Add highlight\n this.setHoverState(this.highlightedFeatures, true);\n }\n /**\n * On Maplibre map load callback function. Add style layers and dynaimc filters.\n */\n onLoad() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap)) {\n return;\n }\n this.addSources();\n this.addLayers();\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n if ((style === null || style === void 0 ? void 0 : style.layers) && this.layersFilter) {\n const styles = style.layers.filter(this.layersFilter);\n this.set('disabled', !styles.length);\n }\n this.applyLayoutVisibility();\n }\n removeLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((styleLayer) => {\n const { id } = styleLayer;\n if (id && (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.getLayer(id))) {\n mapLibreMap.removeLayer(id);\n }\n });\n }\n }\n // /**\n // * Set filter that determines which features should be rendered in a style layer.\n // * @param {maplibregl.filter} filter Determines which features should be rendered in a style layer.\n // */\n // setFilter(filter: { [key: string]: any }) {\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return;\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // this.styleLayers.forEach(({ id }) => {\n // if (id && filter && mapLibreMap.getLayer(id)) {\n // // @ts-expect-error\n // mapLibreMap.setFilter(id, filter);\n // }\n // });\n // }\n removeSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.keys(this.sources).forEach((id) => {\n if (mapLibreMap.getSource(id)) {\n mapLibreMap.removeSource(id);\n }\n });\n }\n }\n /**\n * Select a list of features.\n * @param {Array
      } [features=[]] Features to select.\n * @deprecated Use layer.setFeatureState(features, {selected: true|false}) instead.\n */\n select(features = []) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {selected: true}) instead.`);\n this.setHoverState(this.selectedFeatures || [], false);\n this.selectedFeatures = features;\n this.setHoverState(this.selectedFeatures || [], true);\n }\n /**\n * Set the [feature state](https://maplibre.org/maplibre-style-spec/expressions/#feature-state) of the features.\n *\n * @param {ol/Feature~Feature[]} features\n * @param {{[key: string]: any}} state The feature state\n * @public\n */\n setFeatureState(features, state) {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !features.length) {\n return;\n }\n const mapLibreMap = this.maplibreLayer.mapLibreMap;\n features.forEach((feature) => {\n const { source, sourceLayer } = (feature.get(VECTOR_TILE_FEATURE_PROPERTY) || {});\n if ((!source && !sourceLayer) || !feature.getId()) {\n if (!feature.getId()) {\n deprecated(\"No feature's id found. To use the feature state functionnality, tiles must be generated with --generate-ids. See https://github.com/Maplibre/tippecanoe#adding-calculated-attributes.\", feature.getProperties());\n }\n return;\n }\n if (source) {\n mapLibreMap.setFeatureState({\n id: feature.getId(),\n source,\n sourceLayer,\n }, state);\n }\n else {\n deprecated('No source found for the feature. To use the feature state functionnality, a source must be defined.', feature.getProperties());\n }\n });\n }\n /**\n * Set if features are hovered or not.\n * @param {Array
        } features\n * @param {boolean} state Is the feature hovered\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n setHoverState(features, state) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: ${state}}) instead.`);\n this.setFeatureState(features, { hover: state });\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap(map);\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n}\nexport default MaplibreStyleLayer;\n", + "content": "import debounce from 'lodash.debounce';\nimport { Layer } from 'ol/layer';\nimport { unByKey } from 'ol/Observable';\nimport { Source } from 'ol/source';\nimport { VECTOR_TILE_FEATURE_PROPERTY } from '../../common';\nimport MaplibreStyleLayerRenderer from '../renderers/MaplibreStyleLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((...messages) => {\n // eslint-disable-next-line no-console\n console.warn(...messages);\n }, 1000);\n}\n/**\n * Layer that helps show/hide a specific subset of style layers of a [MaplibreLayer](./MaplibreLayer.js~MaplibreLayer.html).\n *\n * @example\n * import { MaplibreLayer, MocoLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * maplibreLayer: maplibreLayer,\n * layersFilter: (layer) => {\n * // show/hide only style layers related to stations\n * return /station/.test(layer.id);\n * },\n * });\n *\n * @extends {ol/layer/Layer~Layer}\n * @public\n */\nclass MaplibreStyleLayer extends Layer {\n get beforeId() {\n return this.get('beforeId');\n }\n set beforeId(newValue) {\n this.set('beforeId', newValue);\n }\n get layers() {\n return this.get('layers') || [];\n }\n set layers(newValue) {\n this.set('layers', newValue);\n }\n get layersFilter() {\n return this.get('layersFilter');\n }\n set layersFilter(newValue) {\n this.set('layersFilter', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.maplibreLayer instead.\n */\n get mapboxLayer() {\n deprecated('Deprecated. Use maplibreLayer instead.');\n return this.get('maplibreLayer');\n }\n get maplibreLayer() {\n return this.get('maplibreLayer');\n }\n set maplibreLayer(newValue) {\n this.set('maplibreLayer', newValue);\n }\n get queryRenderedLayersFilter() {\n return this.get('queryRenderedLayersFilter');\n }\n set queryRenderedLayersFilter(newValue) {\n this.set('queryRenderedLayersFilter', newValue);\n }\n get sources() {\n return this.get('sources');\n }\n set sources(newValue) {\n this.set('sources', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.layer instead.\n */\n get styleLayer() {\n deprecated('Deprecated. Use MaplibreStyleLayer.layer instead.');\n return this.layers[0];\n }\n /**\n * @deprecated\n */\n set styleLayer(newValue) {\n deprecated('MaplibreStyleLayer.styleLayer is deprecated. Use MaplibreStyleLayer.layer instead.');\n this.layers = [newValue];\n }\n /**\n * Apply visibility to style layers that fits the styleLayersFilter function.\n */\n /**\n * @deprecated\n */\n get styleLayers() {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n return this.layers;\n }\n /**\n * @deprecated\n */\n set styleLayers(newValue) {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n this.layers = newValue;\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} [options.beforeId] The style layer id to use when the options.layers property is defined, unsused otherwise.\n * @param {maplibregl.AddLayerObject[]} [options.layers] The layers to add to the style on load.\n * @param {FilterFunction} [options.layersFilter] Filter function to decide which style layer to apply visiblity on. If not provided, the 'layers' property is used.\n * @param {MaplibreLayer} [options.maplibreLayer] The MaplibreLayer to use.\n * @param {FilterFunction} [options.queryRenderedLayersFilter] Filter function to decide which style layer are available for query.\n * @param {{[id: string]:maplibregl.SourceSpecification}} [options.sources] The sources to add to the style on load.\n * @public\n */\n constructor(options = {\n mapLibreOptions: { style: { layers: [], sources: {}, version: 8 } },\n }) {\n /** Manage renamed property for backward compatibility with v2 */\n if (options.mapboxLayer) {\n deprecated('options.mapboxLayer is deprecated. Use options.maplibreLayer instead.');\n // @ts-expect-error - mapboxLayer is deprecated\n options.maplibreLayer = options.mapboxLayer;\n delete options.mapboxLayer;\n }\n if (options.styleLayer) {\n deprecated('options.styleLayer is deprecated. Use options.layers instead.');\n options.layers = [options.styleLayer];\n delete options.styleLayer;\n }\n if (options.styleLayers) {\n deprecated('options.styleLayers is deprecated. Use options.layers instead.');\n options.layers = options.styleLayers;\n delete options.styleLayers;\n }\n if (options.styleLayersFilter) {\n deprecated('options.styleLayersFilter is deprecated. Use options.layersFilter instead.');\n options.layersFilter = options.styleLayersFilter;\n delete options.styleLayersFilter;\n }\n super(Object.assign({ source: new Source({}) }, options));\n this.highlightedFeatures = [];\n this.olEventsKeys = [];\n this.selectedFeatures = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // For cloning\n this.set('options', options);\n this.beforeId = options.beforeId;\n this.onLoad = this.onLoad.bind(this);\n if (!this.layersFilter && this.layers) {\n this.layersFilter = (layer) => {\n return !!this.layers.find((l) => {\n return layer.id === l.id;\n });\n };\n }\n }\n addLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((layer) => {\n // @ts-expect-error source is optional but exists in TS definition\n const { id, source } = layer;\n if ((!source || (source && mapLibreMap.getSource(source))) &&\n id &&\n !mapLibreMap.getLayer(id)) {\n mapLibreMap.addLayer(layer, this.beforeId);\n }\n });\n this.applyLayoutVisibility();\n }\n }\n addSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.entries(this.sources).forEach(([id, source]) => {\n if (!mapLibreMap.getSource(id)) {\n mapLibreMap.addSource(id, source);\n }\n });\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n applyLayoutVisibility(evt) {\n var _a, _b, _c, _d, _e, _f;\n if (!((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()) || !this.layersFilter) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n const visibilityValue = this.getVisible() ? 'visible' : 'none';\n const layers = style.layers || [];\n // OL sets -Infinity, Infinity for minZoom and maxZoom.\n const isFiniteMinZoom = Number.isFinite(this.getMinZoom());\n const isFiniteMaxZoom = Number.isFinite(this.getMaxZoom());\n // Maplibre zoom = ol zoom - 1\n const minZoom = isFiniteMinZoom ? this.getMinZoom() - 1 : 0;\n const maxZoom = isFiniteMaxZoom ? this.getMaxZoom() - 1 : 24;\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < layers.length; i += 1) {\n const layer = layers[i];\n if (this.layersFilter(layer)) {\n const { id } = layer;\n if (mapLibreMap.getLayer(id)) {\n mapLibreMap.setLayoutProperty(id, 'visibility', visibilityValue);\n if (isFiniteMinZoom || isFiniteMaxZoom) {\n const currentMinZoom = (_d = (_c = mapLibreMap.getLayer(id)) === null || _c === void 0 ? void 0 : _c.minzoom) !== null && _d !== void 0 ? _d : 0;\n const currentMaxZoom = (_f = (_e = mapLibreMap.getLayer(id)) === null || _e === void 0 ? void 0 : _e.maxzoom) !== null && _f !== void 0 ? _f : 24;\n mapLibreMap.setLayerZoomRange(id, currentMinZoom < minZoom ? minZoom : currentMinZoom, currentMaxZoom > maxZoom ? maxZoom : currentMaxZoom);\n }\n }\n }\n }\n }\n /**\n * Initialize the layer.\n * @param {ol/Map~Map} map the Maplibre map.\n * @override\n */\n attachToMap(map) {\n const mapInternal = this.getMapInternal();\n if (!mapInternal || !this.maplibreLayer) {\n return;\n }\n // Apply the initial visibility if possible otherwise we wait for the load event of the layer\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n // mapLibreMap.loaded() and mapLibreMap.isStyleLoaded() are reliable only on the first call of init.\n // On the next call (when a topic change for example), these functions returns false because\n // the style is being modified.\n // That's why we rely on a property instead for the next calls.\n if (mapLibreMap.loaded()) {\n this.onLoad();\n }\n else {\n if (mapLibreMap.isStyleLoaded()) {\n this.onLoad();\n }\n else {\n void mapLibreMap.once('load', this.onLoad);\n }\n }\n }\n // Apply the visibiltity when layer's visibility change.\n this.olEventsKeys.push(\n // @ts-expect-error 'load' is a custom event\n this.maplibreLayer.on('load', this.onLoad.bind(this)), this.on('change:visible', (evt) => {\n // Once the map is loaded we can apply visiblity without waiting\n // the style. Maplibre take care of the application of style changes.\n this.applyLayoutVisibility(evt);\n }), this.on('propertychange', (evt) => {\n if (/(sources|layers|layersFilter|maplibreLayer|beforeId)/.test(evt.key)) {\n this.detachFromMap();\n this.attachToMap(map);\n }\n }), \n // When the style changes we wait that it is loaded to relaunch the onLoad\n this.maplibreLayer.on('propertychange', (evt) => {\n if (evt.key === 'style') {\n const mbMap = evt.target.mapLibreMap;\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('styledata', () => {\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('idle', () => {\n this.onLoad();\n }));\n }));\n }\n }));\n }\n /**\n * Create a copy of the MaplibreStyleLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MapboxStyleLayer} A MaplibreStyleLayer.\n * @public\n */\n clone(newOptions) {\n return new MaplibreStyleLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreStyleLayerRenderer(this);\n }\n /**\n * Terminate the layer.\n * @override\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n if ((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) {\n this.maplibreLayer.mapLibreMap.off('load', this.onLoad);\n this.removeLayers();\n this.removeSources();\n }\n }\n // /**\n // * Request feature information for a given coordinate.\n // * @param {ol/coordinate~Coordinate} coordinate Coordinate to request the information at.\n // * @return {Promise} Promise with features, layer and coordinate.\n // * @deprecated Use getFeatureInfoAtCoordinate([layer], coordinate) from mobility-toolbox-ol package instead.\n // */\n // getFeatureInfoAtCoordinate(\n // coordinate: Coordinate,\n // ): Promise {\n // deprecated(\n // `Deprecated. getFeatureInfoAtCoordinate([layer], coordinate) from ol package instead.`,\n // );\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // // Ignore the getFeatureInfo until the Maplibre map is loaded\n // if (!mapLibreMap.isStyleLoaded()) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // // We query features only on style layers used by this layer.\n // let layers = this.layers || [];\n // if (this.layersFilter) {\n // layers = mapLibreMap.getStyle().layers.filter(this.layersFilter);\n // }\n // if (this.queryRenderedLayersFilter) {\n // layers = mapLibreMap\n // .getStyle()\n // .layers.filter(this.queryRenderedLayersFilter);\n // }\n // return Promise.resolve({\n // coordinate,\n // features: [],\n // layer: this,\n // });\n // // this.maplibreLayer\n // // .getFeatureInfoAtCoordinate(coordinate, {\n // // layers: layers.map((layer) => layer && layer.id),\n // // validate: false,\n // // })\n // // .then((featureInfo: LayerGetFeatureInfoResponse) => {\n // // const features: Feature[] = featureInfo.features.filter(\n // // (feature: Feature) => {\n // // // @ts-expect-error\n // // return this.featureInfoFilter(\n // // feature,\n // // this.map?.getView().getResolution(),\n // // ) as Feature[];\n // // },\n // // );\n // // this.highlight(features);\n // // return { ...featureInfo, features, layer: this };\n // // });\n // }\n /**\n * Highlight a list of features.\n * @param {Array
          } [features=[]] Features to highlight.\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n highlight(features = []) {\n var _a;\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: true}) instead.`);\n // Filter out selected features\n const filtered = ((_a = this.highlightedFeatures) === null || _a === void 0 ? void 0 : _a.filter((feature) => {\n return !(this.selectedFeatures || [])\n .map((feat) => {\n return feat.getId();\n })\n .includes(feature.getId());\n })) || [];\n // Remove previous highlight\n this.setHoverState(filtered, false);\n this.highlightedFeatures = features;\n // Add highlight\n this.setHoverState(this.highlightedFeatures, true);\n }\n /**\n * On Maplibre map load callback function. Add style layers and dynaimc filters.\n */\n onLoad() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap)) {\n return;\n }\n this.addSources();\n this.addLayers();\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n if ((style === null || style === void 0 ? void 0 : style.layers) && this.layersFilter) {\n const styles = style.layers.filter(this.layersFilter);\n this.set('disabled', !styles.length);\n }\n this.applyLayoutVisibility();\n }\n removeLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((styleLayer) => {\n const { id } = styleLayer;\n if (id && (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.getLayer(id))) {\n mapLibreMap.removeLayer(id);\n }\n });\n }\n }\n // /**\n // * Set filter that determines which features should be rendered in a style layer.\n // * @param {maplibregl.filter} filter Determines which features should be rendered in a style layer.\n // */\n // setFilter(filter: { [key: string]: any }) {\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return;\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // this.styleLayers.forEach(({ id }) => {\n // if (id && filter && mapLibreMap.getLayer(id)) {\n // // @ts-expect-error\n // mapLibreMap.setFilter(id, filter);\n // }\n // });\n // }\n removeSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.keys(this.sources).forEach((id) => {\n if (mapLibreMap.getSource(id)) {\n mapLibreMap.removeSource(id);\n }\n });\n }\n }\n /**\n * Select a list of features.\n * @param {Array
            } [features=[]] Features to select.\n * @deprecated Use layer.setFeatureState(features, {selected: true|false}) instead.\n */\n select(features = []) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {selected: true}) instead.`);\n this.setHoverState(this.selectedFeatures || [], false);\n this.selectedFeatures = features;\n this.setHoverState(this.selectedFeatures || [], true);\n }\n /**\n * Set the [feature state](https://maplibre.org/maplibre-style-spec/expressions/#feature-state) of the features.\n *\n * @param {ol/Feature~Feature[]} features\n * @param {{[key: string]: any}} state The feature state\n * @public\n */\n setFeatureState(features, state) {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !features.length) {\n return;\n }\n const mapLibreMap = this.maplibreLayer.mapLibreMap;\n features.forEach((feature) => {\n const { source, sourceLayer } = (feature.get(VECTOR_TILE_FEATURE_PROPERTY) || {});\n if ((!source && !sourceLayer) || !feature.getId()) {\n if (!feature.getId()) {\n deprecated(\"No feature's id found. To use the feature state functionnality, tiles must be generated with --generate-ids. See https://github.com/Maplibre/tippecanoe#adding-calculated-attributes.\", feature.getProperties());\n }\n return;\n }\n if (source) {\n mapLibreMap.setFeatureState({\n id: feature.getId(),\n source,\n sourceLayer,\n }, state);\n }\n else {\n deprecated('No source found for the feature. To use the feature state functionnality, a source must be defined.', feature.getProperties());\n }\n });\n }\n /**\n * Set if features are hovered or not.\n * @param {Array
              } features\n * @param {boolean} state Is the feature hovered\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n setHoverState(features, state) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: ${state}}) instead.`);\n this.setFeatureState(features, { hover: state });\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap(map);\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n}\nexport default MaplibreStyleLayer;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/layers/MaplibreStyleLayer.js", "access": "private", @@ -13135,7 +13414,7 @@ "lineNumber": 1 }, { - "__docId__": 634, + "__docId__": 644, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/MaplibreStyleLayer.js", @@ -13155,7 +13434,7 @@ "ignore": true }, { - "__docId__": 635, + "__docId__": 645, "kind": "class", "name": "MaplibreStyleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js", @@ -13176,7 +13455,7 @@ ] }, { - "__docId__": 636, + "__docId__": 646, "kind": "get", "name": "beforeId", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13195,7 +13474,7 @@ } }, { - "__docId__": 637, + "__docId__": 647, "kind": "set", "name": "beforeId", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13209,7 +13488,7 @@ "undocument": true }, { - "__docId__": 638, + "__docId__": 648, "kind": "get", "name": "layers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13228,7 +13507,7 @@ } }, { - "__docId__": 639, + "__docId__": 649, "kind": "set", "name": "layers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13242,7 +13521,7 @@ "undocument": true }, { - "__docId__": 640, + "__docId__": 650, "kind": "get", "name": "layersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13261,7 +13540,7 @@ } }, { - "__docId__": 641, + "__docId__": 651, "kind": "set", "name": "layersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13275,7 +13554,7 @@ "undocument": true }, { - "__docId__": 642, + "__docId__": 652, "kind": "get", "name": "mapboxLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13294,7 +13573,7 @@ } }, { - "__docId__": 643, + "__docId__": 653, "kind": "get", "name": "maplibreLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13313,7 +13592,7 @@ } }, { - "__docId__": 644, + "__docId__": 654, "kind": "set", "name": "maplibreLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13327,7 +13606,7 @@ "undocument": true }, { - "__docId__": 645, + "__docId__": 655, "kind": "get", "name": "queryRenderedLayersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13346,7 +13625,7 @@ } }, { - "__docId__": 646, + "__docId__": 656, "kind": "set", "name": "queryRenderedLayersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13360,7 +13639,7 @@ "undocument": true }, { - "__docId__": 647, + "__docId__": 657, "kind": "get", "name": "sources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13379,7 +13658,7 @@ } }, { - "__docId__": 648, + "__docId__": 658, "kind": "set", "name": "sources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13393,7 +13672,7 @@ "undocument": true }, { - "__docId__": 649, + "__docId__": 659, "kind": "get", "name": "styleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13412,7 +13691,7 @@ } }, { - "__docId__": 650, + "__docId__": 660, "kind": "set", "name": "styleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13426,7 +13705,7 @@ "deprecated": true }, { - "__docId__": 652, + "__docId__": 662, "kind": "get", "name": "styleLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13445,7 +13724,7 @@ } }, { - "__docId__": 653, + "__docId__": 663, "kind": "set", "name": "styleLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13459,7 +13738,7 @@ "deprecated": true }, { - "__docId__": 655, + "__docId__": 665, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13544,7 +13823,7 @@ ] }, { - "__docId__": 656, + "__docId__": 666, "kind": "member", "name": "highlightedFeatures", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13561,7 +13840,7 @@ } }, { - "__docId__": 657, + "__docId__": 667, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13578,7 +13857,7 @@ } }, { - "__docId__": 658, + "__docId__": 668, "kind": "member", "name": "selectedFeatures", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13595,7 +13874,7 @@ } }, { - "__docId__": 662, + "__docId__": 672, "kind": "method", "name": "addLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13611,7 +13890,7 @@ "return": null }, { - "__docId__": 663, + "__docId__": 673, "kind": "method", "name": "addSources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13627,7 +13906,7 @@ "return": null }, { - "__docId__": 664, + "__docId__": 674, "kind": "method", "name": "applyLayoutVisibility", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13650,7 +13929,7 @@ "return": null }, { - "__docId__": 665, + "__docId__": 675, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13660,7 +13939,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#attachToMap", "access": "private", "description": "Initialize the layer.", - "lineNumber": 232, + "lineNumber": 237, "params": [ { "nullable": null, @@ -13677,7 +13956,7 @@ "return": null }, { - "__docId__": 666, + "__docId__": 676, "kind": "method", "name": "clone", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13687,7 +13966,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#clone", "access": "public", "description": "Create a copy of the MaplibreStyleLayer.", - "lineNumber": 288, + "lineNumber": 293, "params": [ { "nullable": null, @@ -13710,7 +13989,7 @@ } }, { - "__docId__": 667, + "__docId__": 677, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13720,7 +13999,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#createRenderer", "access": "private", "description": null, - "lineNumber": 291, + "lineNumber": 296, "undocument": true, "params": [], "return": { @@ -13730,7 +14009,7 @@ } }, { - "__docId__": 668, + "__docId__": 678, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13740,13 +14019,13 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#detachFromMap", "access": "private", "description": "Terminate the layer.", - "lineNumber": 298, + "lineNumber": 303, "override": true, "params": [], "return": null }, { - "__docId__": 669, + "__docId__": 679, "kind": "method", "name": "highlight", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13756,7 +14035,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#highlight", "access": "private", "description": "Highlight a list of features.", - "lineNumber": 366, + "lineNumber": 371, "deprecated": "Use layer.setFeatureState(features, {hover: true|false}) instead.", "params": [ { @@ -13775,7 +14054,7 @@ "return": null }, { - "__docId__": 671, + "__docId__": 681, "kind": "method", "name": "onLoad", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13785,12 +14064,12 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#onLoad", "access": "private", "description": "On Maplibre map load callback function. Add style layers and dynaimc filters.", - "lineNumber": 386, + "lineNumber": 391, "params": [], "return": null }, { - "__docId__": 672, + "__docId__": 682, "kind": "method", "name": "removeLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13800,13 +14079,13 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#removeLayers", "access": "private", "description": null, - "lineNumber": 401, + "lineNumber": 406, "undocument": true, "params": [], "return": null }, { - "__docId__": 673, + "__docId__": 683, "kind": "method", "name": "removeSources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13816,13 +14095,13 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#removeSources", "access": "private", "description": null, - "lineNumber": 432, + "lineNumber": 437, "undocument": true, "params": [], "return": null }, { - "__docId__": 674, + "__docId__": 684, "kind": "method", "name": "select", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13832,7 +14111,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#select", "access": "private", "description": "Select a list of features.", - "lineNumber": 451, + "lineNumber": 456, "deprecated": "Use layer.setFeatureState(features, {selected: true|false}) instead.", "params": [ { @@ -13851,7 +14130,7 @@ "return": null }, { - "__docId__": 676, + "__docId__": 686, "kind": "method", "name": "setFeatureState", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13861,7 +14140,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#setFeatureState", "access": "public", "description": "Set the [feature state](https://maplibre.org/maplibre-style-spec/expressions/#feature-state) of the features.", - "lineNumber": 464, + "lineNumber": 469, "params": [ { "nullable": null, @@ -13887,7 +14166,7 @@ "return": null }, { - "__docId__": 677, + "__docId__": 687, "kind": "method", "name": "setHoverState", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13897,7 +14176,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#setHoverState", "access": "private", "description": "Set if features are hovered or not.", - "lineNumber": 496, + "lineNumber": 501, "deprecated": "Use layer.setFeatureState(features, {hover: true|false}) instead.", "params": [ { @@ -13924,7 +14203,7 @@ "return": null }, { - "__docId__": 678, + "__docId__": 688, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13934,7 +14213,7 @@ "longname": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer#setMapInternal", "access": "private", "description": null, - "lineNumber": 500, + "lineNumber": 505, "undocument": true, "params": [ { @@ -13947,7 +14226,7 @@ "return": null }, { - "__docId__": 679, + "__docId__": 689, "kind": "file", "name": "build/ol/layers/MapsetLayer.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MapsetLayer_abortController;\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { transformExtent } from 'ol/proj';\nimport { Vector } from 'ol/source';\nimport MapsetAPI from '../../api/MapsetApi';\nimport MapsetKmlFormat from '../utils/MapsetKmlFormat';\nconst kmlFormatter = new MapsetKmlFormat();\n/**\n * An OpenLayers layer able to display plan data from [mapset](https://geops.com/de/solution/mapset).\n *\n * @example\n * import { MapsetLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MapsetLayer({\n * apiKey: 'yourApiKey',\n * // tags: ['test'],\n * // tenants: ['geopstest'],\n * // url: 'https://editor.mapset.io/api/v1',\n * });\n *\n * @see MapsetAPI\n * @see OpenLayers Mapset layer example\n *\n *\n * @extends {ol/layer/VectorLayer~VectorLayer}\n *\n * @public\n */\nclass MapsetLayer extends VectorLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.fetchPlans();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n if (this.api.apiKey !== value) {\n this.api.apiKey = value;\n void this.fetchPlans();\n }\n }\n get doNotRevert32pxScaling() {\n return this.get('doNotRevert32pxScaling');\n }\n set doNotRevert32pxScaling(value) {\n this.set('doNotRevert32pxScaling', value);\n this.updateFeatures();\n }\n get planId() {\n return this.get('planId');\n }\n set planId(value) {\n if (this.planId !== value) {\n this.set('planId', value);\n void this.fetchPlanById(value);\n }\n }\n get plans() {\n return this.get('plans');\n }\n set plans(value) {\n this.set('plans', value);\n this.updateFeatures();\n }\n get tags() {\n return this.api.tags;\n }\n set tags(value) {\n var _a;\n if (((_a = this.api.tags) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tags = value;\n void this.fetchPlans();\n }\n }\n get tenants() {\n return this.api.tenants;\n }\n set tenants(value) {\n var _a;\n if (((_a = this.api.tenants) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tenants = value;\n void this.fetchPlans();\n }\n }\n get timestamp() {\n return this.get('timestamp');\n }\n set timestamp(value) {\n if (this.timestamp !== value) {\n this.set('timestamp', value);\n void this.fetchPlans();\n }\n }\n get url() {\n var _a;\n return (_a = this.api) === null || _a === void 0 ? void 0 : _a.url;\n }\n set url(value) {\n var _a;\n if (this.api && ((_a = this.api) === null || _a === void 0 ? void 0 : _a.url) !== value) {\n this.api.url = value;\n void this.fetchPlans();\n }\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string[]} [options.tags] The tags of the required plans.\n * @param {string} [options.timestamp] The timestamp of the required plans.\n * @param {string[]} [options.tenants] The tenants of the required plans.\n * @param {string} [options.url] The URL of the [geOps Mapset API](https://geops.com/de/solution/mapset).\n * @public\n */\n constructor(options) {\n var _a, _b;\n super(Object.assign({ source: (_a = options.source) !== null && _a !== void 0 ? _a : new Vector() }, (options || {})));\n this.loadAll = true;\n this.olEventsKeys = [];\n _MapsetLayer_abortController.set(this, void 0);\n this.api =\n (_b = options.api) !== null && _b !== void 0 ? _b : new MapsetAPI({\n apiKey: options.apiKey,\n tags: options.tags,\n tenants: options.tenants,\n url: options.url,\n });\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (options.loadAll === false) {\n this.loadAll = options.loadAll;\n }\n }\n fetchPlanById(planId) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a;\n (_a = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _a === void 0 ? void 0 : _a.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (!planId) {\n this.plans = [];\n return;\n }\n let planById;\n try {\n this.dispatchEvent('featuresloadstart');\n planById = yield this.api.getPlanById(planId, {\n signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal,\n });\n this.plans = [planById];\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return;\n }\n // eslint-disable-next-line no-console\n console.error('MapsetLayer: Error fetching plan by ID...', e);\n this.plans = [];\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n return;\n });\n }\n fetchPlans() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (!this.getVisible()) {\n return;\n }\n const view = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView();\n if (!view) {\n return;\n }\n const extent = transformExtent(view.calculateExtent(), view.getProjection(), 'EPSG:4326');\n const zoom = view.getZoom();\n if (!zoom || !extent) {\n this.plans = [];\n return;\n }\n (_b = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _b === void 0 ? void 0 : _b.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n let plans = [];\n try {\n this.dispatchEvent('featuresloadstart');\n plans = yield this.api.getPlans({\n bbox: extent === null || extent === void 0 ? void 0 : extent.toString(),\n timestamp: (_c = this.timestamp) !== null && _c !== void 0 ? _c : new Date().toISOString(),\n zoom,\n }, { signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal });\n this.plans = plans;\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n console.error('MapsetLayer: Error fetching plans...', e);\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n });\n }\n setMapInternal(map) {\n super.setMapInternal(map);\n if (map && this.loadAll) {\n void this.fetchPlans();\n this.olEventsKeys.push(map.on('moveend', () => {\n void this.fetchPlans();\n }), this.on('change:visible', () => {\n void this.fetchPlans();\n }));\n }\n else {\n unByKey(this.olEventsKeys);\n }\n if (map && this.planId) {\n void this.fetchPlanById(this.planId);\n }\n }\n updateFeatures() {\n var _a, _b, _c, _d, _e;\n (_a = this.getSource()) === null || _a === void 0 ? void 0 : _a.clear();\n const map = this.getMapInternal();\n if (map && ((_b = this.plans) === null || _b === void 0 ? void 0 : _b.length) !== 0) {\n const features = (_d = (_c = this.plans) === null || _c === void 0 ? void 0 : _c.flatMap((plan) => {\n return kmlFormatter.readFeatures(plan.data, map.getView().getProjection(), this.doNotRevert32pxScaling);\n })) !== null && _d !== void 0 ? _d : [];\n (_e = this.getSource()) === null || _e === void 0 ? void 0 : _e.addFeatures(features);\n }\n this.dispatchEvent('updatefeatures');\n }\n}\n_MapsetLayer_abortController = new WeakMap();\nexport default MapsetLayer;\n", @@ -13958,7 +14237,7 @@ "lineNumber": 1 }, { - "__docId__": 680, + "__docId__": 690, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/MapsetLayer.js", @@ -13979,7 +14258,7 @@ "ignore": true }, { - "__docId__": 681, + "__docId__": 691, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14000,7 +14279,7 @@ "ignore": true }, { - "__docId__": 682, + "__docId__": 692, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14021,7 +14300,7 @@ "ignore": true }, { - "__docId__": 683, + "__docId__": 693, "kind": "variable", "name": "kmlFormatter", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14042,7 +14321,7 @@ "ignore": true }, { - "__docId__": 684, + "__docId__": 694, "kind": "class", "name": "MapsetLayer", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14067,7 +14346,7 @@ ] }, { - "__docId__": 685, + "__docId__": 695, "kind": "get", "name": "api", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14086,7 +14365,7 @@ } }, { - "__docId__": 686, + "__docId__": 696, "kind": "set", "name": "api", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14100,7 +14379,7 @@ "undocument": true }, { - "__docId__": 687, + "__docId__": 697, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14119,7 +14398,7 @@ } }, { - "__docId__": 688, + "__docId__": 698, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14133,7 +14412,7 @@ "undocument": true }, { - "__docId__": 689, + "__docId__": 699, "kind": "get", "name": "doNotRevert32pxScaling", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14152,7 +14431,7 @@ } }, { - "__docId__": 690, + "__docId__": 700, "kind": "set", "name": "doNotRevert32pxScaling", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14166,7 +14445,7 @@ "undocument": true }, { - "__docId__": 691, + "__docId__": 701, "kind": "get", "name": "planId", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14185,7 +14464,7 @@ } }, { - "__docId__": 692, + "__docId__": 702, "kind": "set", "name": "planId", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14199,7 +14478,7 @@ "undocument": true }, { - "__docId__": 693, + "__docId__": 703, "kind": "get", "name": "plans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14218,7 +14497,7 @@ } }, { - "__docId__": 694, + "__docId__": 704, "kind": "set", "name": "plans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14232,7 +14511,7 @@ "undocument": true }, { - "__docId__": 695, + "__docId__": 705, "kind": "get", "name": "tags", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14251,7 +14530,7 @@ } }, { - "__docId__": 696, + "__docId__": 706, "kind": "set", "name": "tags", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14265,7 +14544,7 @@ "undocument": true }, { - "__docId__": 697, + "__docId__": 707, "kind": "get", "name": "tenants", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14284,7 +14563,7 @@ } }, { - "__docId__": 698, + "__docId__": 708, "kind": "set", "name": "tenants", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14298,7 +14577,7 @@ "undocument": true }, { - "__docId__": 699, + "__docId__": 709, "kind": "get", "name": "timestamp", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14317,7 +14596,7 @@ } }, { - "__docId__": 700, + "__docId__": 710, "kind": "set", "name": "timestamp", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14331,7 +14610,7 @@ "undocument": true }, { - "__docId__": 701, + "__docId__": 711, "kind": "get", "name": "url", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14350,7 +14629,7 @@ } }, { - "__docId__": 702, + "__docId__": 712, "kind": "set", "name": "url", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14364,7 +14643,7 @@ "undocument": true }, { - "__docId__": 703, + "__docId__": 713, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14439,7 +14718,7 @@ ] }, { - "__docId__": 704, + "__docId__": 714, "kind": "member", "name": "loadAll", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14456,7 +14735,7 @@ } }, { - "__docId__": 705, + "__docId__": 715, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14473,7 +14752,7 @@ } }, { - "__docId__": 708, + "__docId__": 718, "kind": "method", "name": "fetchPlanById", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14500,7 +14779,7 @@ } }, { - "__docId__": 712, + "__docId__": 722, "kind": "method", "name": "fetchPlans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14520,7 +14799,7 @@ } }, { - "__docId__": 715, + "__docId__": 725, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14543,7 +14822,7 @@ "return": null }, { - "__docId__": 716, + "__docId__": 726, "kind": "method", "name": "updateFeatures", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14559,10 +14838,10 @@ "return": null }, { - "__docId__": 717, + "__docId__": 727, "kind": "file", "name": "build/ol/layers/MocoLayer.js", - "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _MocoLayer_abortController, _MocoLayer_dataInternal;\nimport { getFeatureCollectionToRenderFromSituation, getGraphByZoom, MocoAPI, } from '..';\nimport { DEFAULT_GRAPH_MAPPING } from '../utils/getGraphByZoom';\nimport MaplibreStyleLayer from './MaplibreStyleLayer';\nexport const MOCO_SOURCE_ID = 'moco';\nexport const MOCO_MD_LAYER_FILTER = 'moco';\n/**\n * An OpenLayers layer able to display data from the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n *\n * @example\n * import { MaplibreLayer, MaplibreStyleLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * apiKey: 'yourApiKey',\n * maplibreLayer: maplibreLayer,\n * // publicAt: new Date(),\n * // loadAll: true,\n * // notifications: undefined,\n * // tenant: \"geopstest\",\n * // url: 'https://moco.geops.io'\n * });\n *\n * @see OpenLayers MaplibreStyle layer example\n * @extends {MaplibreStyleLayer}\n * @private\n */\nclass MocoLayer extends MaplibreStyleLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.updateData();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n this.api.apiKey = value;\n void this.updateData();\n }\n get apiParameters() {\n return this.get('apiParameters');\n }\n set apiParameters(value) {\n this.set('apiParameters', value);\n void this.updateData();\n }\n get loadAll() {\n var _a;\n return (_a = this.get('loadAll')) !== null && _a !== void 0 ? _a : true;\n }\n set loadAll(value) {\n this.set('loadAll', value);\n void this.updateData();\n }\n set publicAt(value) {\n this.set('publicAt', value);\n void this.updateData();\n }\n get publicAt() {\n return this.get('publicAt');\n }\n set situations(value) {\n // If we set situations we do not want to load data from backend\n this.loadAll = false;\n this.set('situations', value);\n void this.updateData();\n }\n get situations() {\n return this.get('situations');\n }\n get tenant() {\n return this.get('tenant');\n }\n set tenant(value) {\n this.set('tenant', value);\n void this.updateData();\n }\n get url() {\n return this.api.url;\n }\n set url(value) {\n this.api.url = value;\n void this.updateData();\n }\n // The useGraphs option allows to filter notifications depending on the current graph.\n // Theoretically useless because this part is handled by the style itself.\n get useGraphs() {\n return this.get('useGraphs');\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiParameters] The url parameters to be included in the MOCO API request.\n * @param {boolean} [options.loadAll=true] If true, all active and published notifications will be loaded, otherwise only the notifications set in 'notifications' will be displayed.\n * @param {boolean} [options.useGraphs=false] If true, only the notifications using the current graphs for the current zoom level will be passed to the maplibre source.\n * @param {MocoNotification[]} [options.notifications] The notifications to display. If not set and loadAll is true, all active and published notifications will be loaded.\n * @param {string} [options.publicAt] The date to filter notifications. If not set, the current date is used.\n * @param {string} [options.tenant] The SSO config to use to get notifications from.\n * @param {string} [options.url] The URL of the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n * @public\n */\n constructor(options) {\n super(Object.assign({ api: new MocoAPI({\n apiKey: options.apiKey,\n tenant: options.tenant,\n url: options.url,\n }), layersFilter: ({ metadata, source, }) => {\n return ((metadata === null || metadata === void 0 ? void 0 : metadata['general.filter']) ===\n MOCO_MD_LAYER_FILTER || source === MOCO_SOURCE_ID);\n } }, options));\n _MocoLayer_abortController.set(this, null);\n /**\n * This is used to store the notifications data that are rendered on the map and to filter them depending on the graph.\n */\n _MocoLayer_dataInternal.set(this, {\n features: [],\n type: 'FeatureCollection',\n });\n }\n attachToMap(map) {\n var _a, _b;\n super.attachToMap(map);\n // If the source is already there (no load event triggered), we update data\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n void this.updateData();\n }\n if (this.useGraphs) {\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n this.olEventsKeys.push(mapInternal.on('moveend', () => {\n this.onZoomEnd();\n }));\n }\n }\n }\n detachFromMap() {\n var _a, _b;\n super.detachFromMap();\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n // Remove the data from the map\n source.setData({\n features: [],\n type: 'FeatureCollection',\n });\n }\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n __classPrivateFieldSet(this, _MocoLayer_abortController, null, \"f\");\n }\n }\n getDataByGraph(data) {\n var _a, _b, _c, _d, _e;\n const zoom = (_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom();\n const graphs = (_e = ((_d = (_c = this.maplibreLayer) === null || _c === void 0 ? void 0 : _c.mapLibreMap) === null || _d === void 0 ? void 0 : _d.getStyle()).metadata) === null || _e === void 0 ? void 0 : _e.graphs;\n const graph = getGraphByZoom(zoom, graphs);\n const newData = {\n features: ((data === null || data === void 0 ? void 0 : data.features) || []).filter((feature) => {\n var _a;\n return ((_a = feature.properties) === null || _a === void 0 ? void 0 : _a.graph) === graph;\n }),\n type: 'FeatureCollection',\n };\n return newData;\n }\n /**\n * This functions load situations from backend depending on the current graph mapping in the style metadata.\n * @returns\n */\n loadData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d, _e;\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n }\n __classPrivateFieldSet(this, _MocoLayer_abortController, new AbortController(), \"f\");\n // Get graphs mapping\n const mdGraphs = (_c = ((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()).metadata) === null || _c === void 0 ? void 0 : _c.graphs;\n const graphMapping = mdGraphs !== null && mdGraphs !== void 0 ? mdGraphs : DEFAULT_GRAPH_MAPPING;\n const graphsString = [...new Set(Object.values(graphMapping))].join(',');\n try {\n const response = yield this.api.export(Object.assign({ graph: graphsString, hasGeoms: true, publicAt: (_d = this.publicAt) === null || _d === void 0 ? void 0 : _d.toISOString(), publicNow: !this.publicAt }, ((_e = this.apiParameters) !== null && _e !== void 0 ? _e : {})), { signal: __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").signal });\n return response.paginatedSituations.results;\n }\n catch (error) {\n if (error && error.name.includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n throw error;\n }\n });\n }\n onLoad() {\n super.onLoad();\n void this.updateData();\n }\n onZoomEnd() {\n var _a, _b;\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source || !__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\").features.length) {\n return;\n }\n // We update the data if the graph has changed\n const newData = this.getDataByGraph(__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\"));\n if (newData !== __classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\")) {\n source.setData(newData);\n }\n }\n /**\n * This function updates the GeoJSON source data, with the current situations available in this.situations.\n * @returns\n */\n updateData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (this.loadAll) {\n const situations = yield this.loadData();\n // We don't use the setter here to avoid infinite loop\n this.set('situations', situations !== null && situations !== void 0 ? situations : []);\n }\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source) {\n // eslint-disable-next-line no-console\n console.warn('MocoLayer: No source found for id : ', MOCO_SOURCE_ID);\n return Promise.reject(new Error('No source found'));\n }\n const data = {\n features: ((_c = this.situations) !== null && _c !== void 0 ? _c : []).flatMap((situation) => {\n return getFeatureCollectionToRenderFromSituation(situation).features;\n }),\n type: 'FeatureCollection',\n };\n __classPrivateFieldSet(this, _MocoLayer_dataInternal, data, \"f\");\n // Apply new data to the source\n if (this.useGraphs) {\n source.setData(this.getDataByGraph(data));\n }\n else {\n source.setData(data);\n }\n return Promise.resolve(true);\n });\n }\n}\n_MocoLayer_abortController = new WeakMap(), _MocoLayer_dataInternal = new WeakMap();\nexport default MocoLayer;\n", + "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _MocoLayer_abortController, _MocoLayer_dataInternal;\nimport { getFeatureCollectionToRenderFromSituation, getGraphByZoom, MocoAPI, } from '..';\nimport { DEFAULT_GRAPH_MAPPING } from '../utils/getGraphByZoom';\nimport MaplibreStyleLayer from './MaplibreStyleLayer';\nexport const MOCO_SOURCE_ID = 'moco';\nexport const MOCO_MD_LAYER_FILTER = 'moco';\n/**\n * An OpenLayers layer able to display data from the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n *\n * @example\n * import { MaplibreLayer, MaplibreStyleLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * apiKey: 'yourApiKey',\n * maplibreLayer: maplibreLayer,\n * // publicAt: new Date(),\n * // loadAll: true,\n * // notifications: undefined,\n * // tenant: \"geopstest\",\n * // url: 'https://moco.geops.io'\n * });\n *\n * @see OpenLayers MaplibreStyle layer example\n * @extends {MaplibreStyleLayer}\n * @private\n */\nclass MocoLayer extends MaplibreStyleLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.updateData();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n this.api.apiKey = value;\n void this.updateData();\n }\n get apiParameters() {\n return this.get('apiParameters');\n }\n set apiParameters(value) {\n this.set('apiParameters', value);\n void this.updateData();\n }\n get loadAll() {\n var _a;\n return (_a = this.get('loadAll')) !== null && _a !== void 0 ? _a : true;\n }\n set loadAll(value) {\n this.set('loadAll', value);\n void this.updateData();\n }\n set publicAt(value) {\n this.set('publicAt', value);\n void this.updateData();\n }\n get publicAt() {\n return this.get('publicAt');\n }\n set situations(value) {\n // If we set situations we do not want to load data from backend\n this.loadAll = false;\n this.set('situations', value);\n void this.updateData();\n }\n get situations() {\n return this.get('situations');\n }\n get tenant() {\n return this.get('tenant');\n }\n set tenant(value) {\n this.set('tenant', value);\n void this.updateData();\n }\n get url() {\n return this.api.url;\n }\n set url(value) {\n this.api.url = value;\n void this.updateData();\n }\n // The useGraphs option allows to filter notifications depending on the current graph.\n // Theoretically useless because this part is handled by the style itself.\n get useGraphs() {\n return this.get('useGraphs');\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiParameters] The url parameters to be included in the MOCO API request.\n * @param {boolean} [options.loadAll=true] If true, all active and published notifications will be loaded, otherwise only the notifications set in 'notifications' will be displayed.\n * @param {boolean} [options.useGraphs=false] If true, only the notifications using the current graphs for the current zoom level will be passed to the maplibre source.\n * @param {MocoNotification[]} [options.notifications] The notifications to display. If not set and loadAll is true, all active and published notifications will be loaded.\n * @param {string} [options.publicAt] The date to filter notifications. If not set, the current date is used.\n * @param {string} [options.tenant] The SSO config to use to get notifications from.\n * @param {string} [options.url] The URL of the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n * @public\n */\n constructor(options) {\n super(Object.assign({ api: new MocoAPI({\n apiKey: options.apiKey,\n tenant: options.tenant,\n url: options.url,\n }), layersFilter: ({ metadata, source, }) => {\n return ((metadata === null || metadata === void 0 ? void 0 : metadata['general.filter']) ===\n MOCO_MD_LAYER_FILTER || source === MOCO_SOURCE_ID);\n } }, options));\n _MocoLayer_abortController.set(this, null);\n /**\n * This is used to store the notifications data that are rendered on the map and to filter them depending on the graph.\n */\n _MocoLayer_dataInternal.set(this, {\n features: [],\n type: 'FeatureCollection',\n });\n }\n attachToMap(map) {\n var _a, _b;\n super.attachToMap(map);\n // If the source is already there (no load event triggered), we update data\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n void this.updateData();\n }\n if (this.useGraphs) {\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n this.olEventsKeys.push(mapInternal.on('moveend', () => {\n this.onZoomEnd();\n }));\n }\n }\n }\n detachFromMap() {\n var _a, _b;\n super.detachFromMap();\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n // Remove the data from the map\n source.setData({\n features: [],\n type: 'FeatureCollection',\n });\n }\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n __classPrivateFieldSet(this, _MocoLayer_abortController, null, \"f\");\n }\n }\n getDataByGraph(data) {\n var _a, _b, _c, _d, _e;\n const zoom = (_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom();\n const graphs = (_e = ((_d = (_c = this.maplibreLayer) === null || _c === void 0 ? void 0 : _c.mapLibreMap) === null || _d === void 0 ? void 0 : _d.getStyle()).metadata) === null || _e === void 0 ? void 0 : _e.graphs;\n const graph = getGraphByZoom(zoom, graphs);\n const newData = {\n features: ((data === null || data === void 0 ? void 0 : data.features) || []).filter((feature) => {\n var _a;\n return ((_a = feature.properties) === null || _a === void 0 ? void 0 : _a.graph) === graph;\n }),\n type: 'FeatureCollection',\n };\n return newData;\n }\n /**\n * This functions load situations from backend depending on the current graph mapping in the style metadata.\n * @returns\n */\n loadData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d, _e;\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n }\n __classPrivateFieldSet(this, _MocoLayer_abortController, new AbortController(), \"f\");\n // Get graphs mapping\n const mdGraphs = (_c = ((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()).metadata) === null || _c === void 0 ? void 0 : _c.graphs;\n const graphMapping = mdGraphs !== null && mdGraphs !== void 0 ? mdGraphs : DEFAULT_GRAPH_MAPPING;\n const graphsString = [...new Set(Object.values(graphMapping))].join(',');\n try {\n const response = yield this.api.export(Object.assign({ graph: graphsString, hasGeoms: true, publicAt: (_d = this.publicAt) === null || _d === void 0 ? void 0 : _d.toISOString(), publicNow: !this.publicAt }, ((_e = this.apiParameters) !== null && _e !== void 0 ? _e : {})), { signal: __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").signal });\n return response.paginatedSituations.results;\n }\n catch (error) {\n if (error && error.name.includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n throw error;\n }\n });\n }\n onLoad() {\n super.onLoad();\n void this.updateData();\n }\n onZoomEnd() {\n var _a, _b;\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source || !__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\").features.length) {\n return;\n }\n // We update the data if the graph has changed\n const newData = this.getDataByGraph(__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\"));\n if (newData !== __classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\")) {\n source.setData(newData);\n }\n }\n /**\n * This function updates the GeoJSON source data, with the current situations available in this.situations.\n * @returns\n */\n updateData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (this.loadAll) {\n const situations = yield this.loadData();\n // We don't use the setter here to avoid infinite loop\n this.set('situations', situations !== null && situations !== void 0 ? situations : []);\n }\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source) {\n // eslint-disable-next-line no-console\n console.warn('MocoLayer: No source found for id : ', MOCO_SOURCE_ID);\n return Promise.reject(new Error('No source found'));\n }\n const data = {\n features: ((_c = this.situations) !== null && _c !== void 0 ? _c : []).flatMap((situation) => {\n return getFeatureCollectionToRenderFromSituation(situation, this.publicAt).features;\n }),\n type: 'FeatureCollection',\n };\n __classPrivateFieldSet(this, _MocoLayer_dataInternal, data, \"f\");\n // Apply new data to the source\n if (this.useGraphs) {\n source.setData(this.getDataByGraph(data));\n }\n else {\n source.setData(data);\n }\n return Promise.resolve(true);\n });\n }\n}\n_MocoLayer_abortController = new WeakMap(), _MocoLayer_dataInternal = new WeakMap();\nexport default MocoLayer;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/layers/MocoLayer.js", "access": "private", @@ -14570,7 +14849,7 @@ "lineNumber": 1 }, { - "__docId__": 718, + "__docId__": 728, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/MocoLayer.js", @@ -14591,7 +14870,7 @@ "ignore": true }, { - "__docId__": 719, + "__docId__": 729, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/ol/layers/MocoLayer.js", @@ -14612,7 +14891,7 @@ "ignore": true }, { - "__docId__": 720, + "__docId__": 730, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/ol/layers/MocoLayer.js", @@ -14633,7 +14912,7 @@ "ignore": true }, { - "__docId__": 721, + "__docId__": 731, "kind": "variable", "name": "MOCO_SOURCE_ID", "memberof": "build/ol/layers/MocoLayer.js", @@ -14653,7 +14932,7 @@ } }, { - "__docId__": 722, + "__docId__": 732, "kind": "variable", "name": "MOCO_MD_LAYER_FILTER", "memberof": "build/ol/layers/MocoLayer.js", @@ -14673,7 +14952,7 @@ } }, { - "__docId__": 723, + "__docId__": 733, "kind": "class", "name": "MocoLayer", "memberof": "build/ol/layers/MocoLayer.js", @@ -14697,7 +14976,7 @@ ] }, { - "__docId__": 724, + "__docId__": 734, "kind": "get", "name": "api", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14716,7 +14995,7 @@ } }, { - "__docId__": 725, + "__docId__": 735, "kind": "set", "name": "api", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14730,7 +15009,7 @@ "undocument": true }, { - "__docId__": 726, + "__docId__": 736, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14749,7 +15028,7 @@ } }, { - "__docId__": 727, + "__docId__": 737, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14763,7 +15042,7 @@ "undocument": true }, { - "__docId__": 728, + "__docId__": 738, "kind": "get", "name": "apiParameters", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14782,7 +15061,7 @@ } }, { - "__docId__": 729, + "__docId__": 739, "kind": "set", "name": "apiParameters", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14796,7 +15075,7 @@ "undocument": true }, { - "__docId__": 730, + "__docId__": 740, "kind": "get", "name": "loadAll", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14815,7 +15094,7 @@ } }, { - "__docId__": 731, + "__docId__": 741, "kind": "set", "name": "loadAll", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14829,7 +15108,7 @@ "undocument": true }, { - "__docId__": 732, + "__docId__": 742, "kind": "set", "name": "publicAt", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14843,7 +15122,7 @@ "undocument": true }, { - "__docId__": 733, + "__docId__": 743, "kind": "get", "name": "publicAt", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14862,7 +15141,7 @@ } }, { - "__docId__": 734, + "__docId__": 744, "kind": "set", "name": "situations", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14876,7 +15155,7 @@ "undocument": true }, { - "__docId__": 736, + "__docId__": 746, "kind": "get", "name": "situations", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14895,7 +15174,7 @@ } }, { - "__docId__": 737, + "__docId__": 747, "kind": "get", "name": "tenant", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14914,7 +15193,7 @@ } }, { - "__docId__": 738, + "__docId__": 748, "kind": "set", "name": "tenant", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14928,7 +15207,7 @@ "undocument": true }, { - "__docId__": 739, + "__docId__": 749, "kind": "get", "name": "url", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14947,7 +15226,7 @@ } }, { - "__docId__": 740, + "__docId__": 750, "kind": "set", "name": "url", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14961,7 +15240,7 @@ "undocument": true }, { - "__docId__": 741, + "__docId__": 751, "kind": "get", "name": "useGraphs", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14980,7 +15259,7 @@ } }, { - "__docId__": 742, + "__docId__": 752, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15089,7 +15368,7 @@ ] }, { - "__docId__": 743, + "__docId__": 753, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15112,7 +15391,7 @@ "return": null }, { - "__docId__": 744, + "__docId__": 754, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15128,7 +15407,7 @@ "return": null }, { - "__docId__": 745, + "__docId__": 755, "kind": "method", "name": "getDataByGraph", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15155,7 +15434,7 @@ } }, { - "__docId__": 746, + "__docId__": 756, "kind": "method", "name": "loadData", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15180,7 +15459,7 @@ } }, { - "__docId__": 747, + "__docId__": 757, "kind": "method", "name": "onLoad", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15196,7 +15475,7 @@ "return": null }, { - "__docId__": 748, + "__docId__": 758, "kind": "method", "name": "onZoomEnd", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15212,7 +15491,7 @@ "return": null }, { - "__docId__": 749, + "__docId__": 759, "kind": "method", "name": "updateData", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15237,7 +15516,7 @@ } }, { - "__docId__": 750, + "__docId__": 760, "kind": "file", "name": "build/ol/layers/RealtimeLayer.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport debounce from 'lodash.debounce';\nimport { getIntersection, isEmpty } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport Layer from 'ol/layer/Layer';\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { Vector as VectorSource } from 'ol/source';\nimport Source from 'ol/source/Source';\nimport { realtimeDefaultStyle } from '../../common/styles';\nimport RealtimeEngine from '../../common/utils/RealtimeEngine';\nimport RealtimeLayerRenderer from '../renderers/RealtimeLayerRenderer';\nimport { fullTrajectoryStyle } from '../styles';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nimport { deprecated } from './MaplibreLayer';\nconst format = new GeoJSON();\n/**\n * An OpenLayers layer able to display data from the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { RealtimeLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new RealtimeLayer({\n * apiKey: \"yourApiKey\"\n * // allowRenderWhenAnimating: false,\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n *\n * @see RealtimeAPI\n * @see OpenLayers Realtime layer example\n *\n *\n * @extends {ol/layer/Layer~Layer}\n *\n *\n * @classproperty {boolean} allowRenderWhenAnimating - Allow rendering of the layer when the map is animating.\n * @public\n */\nclass RealtimeLayer extends Layer {\n get api() {\n return this.engine.api;\n }\n set api(api) {\n this.engine.api = api;\n }\n get canvas() {\n return this.engine.canvas;\n }\n get filter() {\n return this.engine.filter;\n }\n set filter(filter) {\n this.engine.filter = filter;\n }\n get hoverVehicleId() {\n return this.engine.hoverVehicleId;\n }\n set hoverVehicleId(id) {\n this.engine.hoverVehicleId = id;\n }\n get mode() {\n return this.engine.mode;\n }\n set mode(mode) {\n this.engine.mode = mode;\n }\n get pixelRatio() {\n return this.engine.pixelRatio;\n }\n get selectedVehicleId() {\n return this.engine.selectedVehicleId;\n }\n set selectedVehicleId(id) {\n this.engine.selectedVehicleId = id;\n }\n get sort() {\n return this.engine.sort;\n }\n set sort(sort) {\n this.engine.sort = sort;\n }\n get style() {\n var _a;\n return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.style;\n }\n set style(style) {\n if (this.engine) {\n this.engine.style = style;\n }\n }\n get styleOptions() {\n return this.engine.styleOptions;\n }\n set styleOptions(options) {\n this.engine.styleOptions = options;\n }\n get time() {\n return this.engine.time || new Date();\n }\n set time(time) {\n this.engine.time = time;\n }\n get trajectories() {\n return this.engine.trajectories;\n }\n /**\n * Constructor.\n *\n * @param {RealtimeLayerOptions} options\n * @param {boolean} [options.allowRenderWhenAnimating=false] Allow rendering of the layer when the map is animating.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.url=\"wss://api.geops.io/tracker-ws/v1/\"] The [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.\n * @public\n */\n constructor(options) {\n // We use a group to be able to add custom vector layer in extended class.\n // For example TrajservLayer use a vectorLayer to display the complete trajectory.\n super(Object.assign({ minZoom: 4, source: new Source({}) }, options));\n this.allowRenderWhenAnimating = false;\n this.maxNbFeaturesRequested = 100;\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n this.engine = new RealtimeEngine(Object.assign({ getViewState: this.getViewState.bind(this), onIdle: this.onRealtimeEngineIdle.bind(this), onRender: this.onRealtimeEngineRender.bind(this), style: realtimeDefaultStyle }, options));\n this.allowRenderWhenAnimating = !!options.allowRenderWhenAnimating;\n // We store the layer used to highlight the full Trajectory\n this.vectorLayer = new VectorLayer({\n minZoom: this.getMinZoom(),\n source: new VectorSource({ features: [] }),\n style: (feature, resolution) => {\n return (options.fullTrajectoryStyle || fullTrajectoryStyle)(feature, resolution, this);\n },\n updateWhileAnimating: this.allowRenderWhenAnimating,\n updateWhileInteracting: true,\n });\n this.onZoomEndDebounced = debounce(this.onZoomEnd, 100);\n this.onMoveEndDebounced = debounce(this.onMoveEnd, 100);\n }\n /**\n * Add a trajectory.\n * @param trajectory\n */\n addTrajectory(trajectory) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.addTrajectory(trajectory);\n }\n attachToMap() {\n this.engine.attachToMap();\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n // If the layer is visible we start the rendering clock\n if (this.getVisible()) {\n this.engine.start();\n }\n this.olEventsKeys.push(mapInternal.on('movestart', () => {\n if (this.engine.isUpdateBboxOnMoveEnd) {\n this.engine.updateIdleState();\n }\n }), ...mapInternal.on(['moveend', 'change:target'], \n // @ts-expect-error - bad ol definitions\n (evt) => {\n const view = (evt.map || evt.target).getView();\n if (!view || (view === null || view === void 0 ? void 0 : view.getAnimating()) || (view === null || view === void 0 ? void 0 : view.getInteracting())) {\n return;\n }\n const zoom = view.getZoom();\n // Update the interval between render updates\n if (this.currentZoom !== zoom) {\n this.onZoomEndDebounced(evt);\n }\n this.currentZoom = zoom;\n this.onMoveEndDebounced(evt);\n }), this.on('change:visible', (evt) => {\n if (evt.target.getVisible()) {\n this.engine.start();\n }\n else {\n this.engine.stop();\n }\n }), this.on('propertychange', (evt) => {\n // We apply every property change event related to visiblity to the vectorlayer\n if (/(opacity|visible|zIndex|minResolution|maxResolution|minZoom|maxZoom)/.test(evt.key)) {\n this.vectorLayer.set(evt.key, evt.target.get(evt.key));\n }\n }));\n }\n }\n cleanVectorLayer() {\n var _a, _b, _c;\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear(true);\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n /**\n * Create a copy of the RealtimeLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {RealtimeLayer} A RealtimeLayer\n * @public\n */\n clone(newOptions) {\n return new RealtimeLayer(Object.assign(Object.assign({}, this.get('options')), newOptions));\n }\n createRenderer() {\n return new RealtimeLayerRenderer(this);\n }\n /**\n * Destroy the container of the tracker.\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.removeLayer(this.vectorLayer);\n this.engine.detachFromMap();\n }\n /**\n * Get the full trajectory of a vehicle as features.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} A list of features representing a full trajectory.\n * @public\n */\n getFullTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n const data = yield this.engine.api.getFullTrajectory(id, this.engine.mode, this.engine.getGeneralizationLevelByZoom(Math.floor(((_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom()) || 0)));\n if ((_d = (_c = data === null || data === void 0 ? void 0 : data.content) === null || _c === void 0 ? void 0 : _c.features) === null || _d === void 0 ? void 0 : _d.length) {\n return format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n return [];\n });\n }\n /**\n * Get the stop sequences of a vehicle.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} An array of stop sequences.\n * @public\n */\n getStopSequences(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const data = yield this.engine.api.getStopSequence(id);\n return data === null || data === void 0 ? void 0 : data.content;\n });\n }\n /**\n * Get full trajectory and stop sequences of a vehicle.\n *\n * @param {RealtimeTrainId} id A vehicle's id.\n * @returns {Promise<{fullTrajectory: Feature[], stopSequences: RealtimeStopSequence[]}>} An object containing the full trajectory and the stop sequences.\n */\n getTrajectoryInfos(id) {\n return __awaiter(this, void 0, void 0, function* () {\n // When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.\n // Then we combine them in one response.\n const promises = [this.getStopSequences(id), this.getFullTrajectory(id)];\n const [stopSequences, fullTrajectory] = yield Promise.all(promises);\n return {\n fullTrajectory: fullTrajectory,\n stopSequences: stopSequences,\n };\n });\n }\n getVehicles(filterFunc) {\n return this.engine.getVehicles(filterFunc);\n }\n getViewState() {\n const mapInternal = this.getMapInternal();\n if (!(mapInternal === null || mapInternal === void 0 ? void 0 : mapInternal.getView())) {\n return {};\n }\n const view = mapInternal.getView();\n let extent = view.calculateExtent();\n const layerExtent = this.getExtent();\n if (layerExtent) {\n extent = getIntersection(extent, layerExtent);\n // If there is no intersection we use the layer extent\n if (isEmpty(extent)) {\n extent = layerExtent;\n }\n }\n return {\n center: view.getCenter(),\n extent: extent,\n pixelRatio: this.engine.pixelRatio,\n resolution: view.getResolution(),\n rotation: view.getRotation(),\n size: mapInternal.getSize(),\n visible: this.getVisible(),\n zoom: view.getZoom(),\n };\n }\n highlight(features) {\n const feat = Array.isArray(features) ? features[0] : features;\n const id = feat === null || feat === void 0 ? void 0 : feat.get('train_id');\n if (this.hoverVehicleId !== id) {\n this.hoverVehicleId = id;\n this.engine.renderTrajectories(true);\n }\n }\n /**\n * Highlight the trajectory of journey.\n */\n highlightTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const promise = new Promise((resolve) => {\n this.api.subscribeFullTrajectory(id, this.engine.mode, (data) => {\n var _a, _b;\n if (this.selectedVehicleId === id && (data === null || data === void 0 ? void 0 : data.content)) {\n let features = [];\n if ((_b = (_a = data === null || data === void 0 ? void 0 : data.content) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.length) {\n features = format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n this.updateHighlightFeatures(features);\n resolve(features);\n }\n });\n });\n return promise;\n // const features = await this.getFullTrajectory(id);\n // this.updateHighlightFeatures(features);\n // return features;\n });\n }\n onMoveEnd() {\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n this.engine.setBbox();\n }\n onRealtimeEngineIdle() {\n this.changed();\n }\n /**\n * Callback when the RealtimeEngine has rendered successfully.\n */\n onRealtimeEngineRender(renderState, viewState) {\n this.renderedViewState = Object.assign({}, viewState);\n // @ts-expect-error - we are in the same class\n const { container } = this.getRenderer();\n if (container) {\n container.style.transform = '';\n }\n }\n onZoomEnd() {\n this.engine.onZoomEnd();\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n }\n /**\n * Remove a trajectory.\n *\n * @param trajectoryOrId\n */\n removeTrajectory(trajectoryOrId) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.removeTrajectory(trajectoryOrId);\n }\n /**\n * Render the trajectories of the vehicles.\n * @deprecated Use this.engine.renderTrajectories instead.\n */\n renderTrajectories(noInterpolate) {\n deprecated('RealtimeLayer.renderTrajectories is deprecated. Use RealtimeLayer.engine.renderTrajectories instead.');\n this.engine.renderTrajectories(noInterpolate);\n }\n select(features) {\n const feat = Array.isArray(features) ? features[0] : features;\n const id = feat === null || feat === void 0 ? void 0 : feat.get('train_id');\n if (this.selectedVehicleId !== id) {\n if (this.selectedVehicleId) {\n this.api.unsubscribeFullTrajectory(this.selectedVehicleId);\n }\n this.cleanVectorLayer();\n this.selectedVehicleId = id;\n this.engine.renderTrajectories(true);\n }\n if (id) {\n void this.highlightTrajectory(id);\n }\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n shouldRender() {\n var _a, _b;\n return this.allowRenderWhenAnimating\n ? false\n : ((_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView().getAnimating()) ||\n ((_b = this.getMapInternal()) === null || _b === void 0 ? void 0 : _b.getView().getInteracting());\n }\n /**\n * Start the rendering.\n *\n * @public\n */\n start() {\n this.engine.start();\n }\n /**\n * Stop the rendering.\n *\n * @public\n */\n stop() {\n this.engine.stop();\n }\n updateHighlightFeatures(features) {\n var _a, _b, _c, _d, _e, _f;\n this.cleanVectorLayer();\n if (features === null || features === void 0 ? void 0 : features.length) {\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeatures(features);\n }\n if (this.vectorLayer.getMapInternal() &&\n this.vectorLayer.getMapInternal() !== this.getMapInternal()) {\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n // Add the vector layer to the map\n const zIndex = this.getZIndex();\n if (zIndex !== undefined) {\n this.vectorLayer.setZIndex(zIndex - 1);\n if (!this.vectorLayer.getMapInternal()) {\n (_d = this.getMapInternal()) === null || _d === void 0 ? void 0 : _d.addLayer(this.vectorLayer);\n }\n }\n else if (!this.vectorLayer.getMapInternal()) {\n const index = ((_e = this.getMapInternal()) === null || _e === void 0 ? void 0 : _e.getLayers().getArray().indexOf(this)) || 0;\n if (index) {\n (_f = this.getMapInternal()) === null || _f === void 0 ? void 0 : _f.getLayers().insertAt(index, this.vectorLayer);\n }\n }\n return features;\n }\n}\nexport default RealtimeLayer;\n", @@ -15248,7 +15527,7 @@ "lineNumber": 1 }, { - "__docId__": 751, + "__docId__": 761, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15269,7 +15548,7 @@ "ignore": true }, { - "__docId__": 752, + "__docId__": 762, "kind": "variable", "name": "format", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15290,7 +15569,7 @@ "ignore": true }, { - "__docId__": 753, + "__docId__": 763, "kind": "class", "name": "RealtimeLayer", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15321,7 +15600,7 @@ ] }, { - "__docId__": 754, + "__docId__": 764, "kind": "get", "name": "api", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15340,7 +15619,7 @@ } }, { - "__docId__": 755, + "__docId__": 765, "kind": "set", "name": "api", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15354,7 +15633,7 @@ "undocument": true }, { - "__docId__": 756, + "__docId__": 766, "kind": "get", "name": "canvas", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15373,7 +15652,7 @@ } }, { - "__docId__": 757, + "__docId__": 767, "kind": "get", "name": "filter", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15392,7 +15671,7 @@ } }, { - "__docId__": 758, + "__docId__": 768, "kind": "set", "name": "filter", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15406,7 +15685,7 @@ "undocument": true }, { - "__docId__": 759, + "__docId__": 769, "kind": "get", "name": "hoverVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15425,7 +15704,7 @@ } }, { - "__docId__": 760, + "__docId__": 770, "kind": "set", "name": "hoverVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15439,7 +15718,7 @@ "undocument": true }, { - "__docId__": 761, + "__docId__": 771, "kind": "get", "name": "mode", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15458,7 +15737,7 @@ } }, { - "__docId__": 762, + "__docId__": 772, "kind": "set", "name": "mode", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15472,7 +15751,7 @@ "undocument": true }, { - "__docId__": 763, + "__docId__": 773, "kind": "get", "name": "pixelRatio", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15491,7 +15770,7 @@ } }, { - "__docId__": 764, + "__docId__": 774, "kind": "get", "name": "selectedVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15510,7 +15789,7 @@ } }, { - "__docId__": 765, + "__docId__": 775, "kind": "set", "name": "selectedVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15524,7 +15803,7 @@ "undocument": true }, { - "__docId__": 766, + "__docId__": 776, "kind": "get", "name": "sort", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15543,7 +15822,7 @@ } }, { - "__docId__": 767, + "__docId__": 777, "kind": "set", "name": "sort", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15557,7 +15836,7 @@ "undocument": true }, { - "__docId__": 768, + "__docId__": 778, "kind": "get", "name": "style", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15576,7 +15855,7 @@ } }, { - "__docId__": 769, + "__docId__": 779, "kind": "set", "name": "style", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15590,7 +15869,7 @@ "undocument": true }, { - "__docId__": 770, + "__docId__": 780, "kind": "get", "name": "styleOptions", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15609,7 +15888,7 @@ } }, { - "__docId__": 771, + "__docId__": 781, "kind": "set", "name": "styleOptions", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15623,7 +15902,7 @@ "undocument": true }, { - "__docId__": 772, + "__docId__": 782, "kind": "get", "name": "time", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15642,7 +15921,7 @@ } }, { - "__docId__": 773, + "__docId__": 783, "kind": "set", "name": "time", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15656,7 +15935,7 @@ "undocument": true }, { - "__docId__": 774, + "__docId__": 784, "kind": "get", "name": "trajectories", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15675,7 +15954,7 @@ } }, { - "__docId__": 775, + "__docId__": 785, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15734,7 +16013,7 @@ ] }, { - "__docId__": 776, + "__docId__": 786, "kind": "member", "name": "allowRenderWhenAnimating", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15751,7 +16030,7 @@ } }, { - "__docId__": 777, + "__docId__": 787, "kind": "member", "name": "maxNbFeaturesRequested", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15768,7 +16047,7 @@ } }, { - "__docId__": 778, + "__docId__": 788, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15785,7 +16064,7 @@ } }, { - "__docId__": 779, + "__docId__": 789, "kind": "member", "name": "engine", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15802,7 +16081,7 @@ } }, { - "__docId__": 781, + "__docId__": 791, "kind": "member", "name": "vectorLayer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15819,7 +16098,7 @@ } }, { - "__docId__": 782, + "__docId__": 792, "kind": "member", "name": "onZoomEndDebounced", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15836,7 +16115,7 @@ } }, { - "__docId__": 783, + "__docId__": 793, "kind": "member", "name": "onMoveEndDebounced", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15853,7 +16132,7 @@ } }, { - "__docId__": 784, + "__docId__": 794, "kind": "method", "name": "addTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15879,7 +16158,7 @@ "return": null }, { - "__docId__": 785, + "__docId__": 795, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15895,7 +16174,7 @@ "return": null }, { - "__docId__": 786, + "__docId__": 796, "kind": "member", "name": "currentZoom", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15912,7 +16191,7 @@ } }, { - "__docId__": 787, + "__docId__": 797, "kind": "method", "name": "cleanVectorLayer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15928,7 +16207,7 @@ "return": null }, { - "__docId__": 788, + "__docId__": 798, "kind": "method", "name": "clone", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15961,7 +16240,7 @@ } }, { - "__docId__": 789, + "__docId__": 799, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15981,7 +16260,7 @@ } }, { - "__docId__": 790, + "__docId__": 800, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15996,7 +16275,7 @@ "return": null }, { - "__docId__": 791, + "__docId__": 801, "kind": "method", "name": "getFullTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16035,7 +16314,7 @@ } }, { - "__docId__": 792, + "__docId__": 802, "kind": "method", "name": "getStopSequences", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16074,7 +16353,7 @@ } }, { - "__docId__": 793, + "__docId__": 803, "kind": "method", "name": "getTrajectoryInfos", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16113,7 +16392,7 @@ } }, { - "__docId__": 794, + "__docId__": 804, "kind": "method", "name": "getVehicles", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16140,7 +16419,7 @@ } }, { - "__docId__": 795, + "__docId__": 805, "kind": "method", "name": "getViewState", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16160,7 +16439,7 @@ } }, { - "__docId__": 796, + "__docId__": 806, "kind": "method", "name": "highlight", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16183,7 +16462,7 @@ "return": null }, { - "__docId__": 798, + "__docId__": 808, "kind": "method", "name": "highlightTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16209,7 +16488,7 @@ } }, { - "__docId__": 799, + "__docId__": 809, "kind": "method", "name": "onMoveEnd", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16225,7 +16504,7 @@ "return": null }, { - "__docId__": 800, + "__docId__": 810, "kind": "method", "name": "onRealtimeEngineIdle", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16241,7 +16520,7 @@ "return": null }, { - "__docId__": 801, + "__docId__": 811, "kind": "method", "name": "onRealtimeEngineRender", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16269,7 +16548,7 @@ "return": null }, { - "__docId__": 802, + "__docId__": 812, "kind": "member", "name": "renderedViewState", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16286,7 +16565,7 @@ } }, { - "__docId__": 803, + "__docId__": 813, "kind": "method", "name": "onZoomEnd", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16302,7 +16581,7 @@ "return": null }, { - "__docId__": 804, + "__docId__": 814, "kind": "method", "name": "removeTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16328,7 +16607,7 @@ "return": null }, { - "__docId__": 805, + "__docId__": 815, "kind": "method", "name": "renderTrajectories", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16351,7 +16630,7 @@ "return": null }, { - "__docId__": 806, + "__docId__": 816, "kind": "method", "name": "select", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16374,7 +16653,7 @@ "return": null }, { - "__docId__": 808, + "__docId__": 818, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16397,7 +16676,7 @@ "return": null }, { - "__docId__": 809, + "__docId__": 819, "kind": "method", "name": "shouldRender", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16417,7 +16696,7 @@ } }, { - "__docId__": 810, + "__docId__": 820, "kind": "method", "name": "start", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16432,7 +16711,7 @@ "return": null }, { - "__docId__": 811, + "__docId__": 821, "kind": "method", "name": "stop", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16447,7 +16726,7 @@ "return": null }, { - "__docId__": 812, + "__docId__": 822, "kind": "method", "name": "updateHighlightFeatures", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16474,7 +16753,7 @@ } }, { - "__docId__": 813, + "__docId__": 823, "kind": "file", "name": "build/ol/layers/VectorLayer.js", "content": "import { Vector } from 'ol/layer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nimport { deprecated } from './MaplibreLayer';\n/**\n * @deprecated\n */\nclass VectorLayer extends Vector {\n constructor(options) {\n var _a, _b, _c, _d;\n if (!options.source && ((_a = options.olLayer) === null || _a === void 0 ? void 0 : _a.getSource())) {\n options.source = (_d = (_c = (_b = options.olLayer) === null || _b === void 0 ? void 0 : _b.getSource) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : undefined;\n }\n super(options);\n defineDeprecatedProperties(this, options);\n deprecated('Layer is deprecated. Use an OpenLayers Layer instead.');\n // Backward compatibility\n // @ts-expect-error Property just there for backward compatibility\n this.olEventsKeys = [];\n }\n /**\n * @deprecated\n */\n clone(newOptions) {\n return new VectorLayer(Object.assign(Object.assign({}, this.get('options')), newOptions));\n }\n /**\n * @deprecated\n */\n getFeatureInfoAtCoordinate(coordinate) {\n let features = [];\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n const pixel = mapInternal.getPixelFromCoordinate(coordinate);\n features =\n mapInternal.getFeaturesAtPixel(pixel, {\n hitTolerance: this.get('hitTolerance') || 5,\n layerFilter: (l) => {\n return l === this;\n },\n }) || [];\n }\n return Promise.resolve({\n coordinate,\n features,\n layer: this,\n });\n }\n}\nexport default VectorLayer;\n", @@ -16485,7 +16764,7 @@ "lineNumber": 1 }, { - "__docId__": 814, + "__docId__": 824, "kind": "class", "name": "VectorLayer", "memberof": "build/ol/layers/VectorLayer.js", @@ -16504,7 +16783,7 @@ ] }, { - "__docId__": 815, + "__docId__": 825, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/VectorLayer.js~VectorLayer", @@ -16518,7 +16797,7 @@ "undocument": true }, { - "__docId__": 816, + "__docId__": 826, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/VectorLayer.js~VectorLayer", @@ -16535,7 +16814,7 @@ } }, { - "__docId__": 817, + "__docId__": 827, "kind": "method", "name": "clone", "memberof": "build/ol/layers/VectorLayer.js~VectorLayer", @@ -16562,7 +16841,7 @@ } }, { - "__docId__": 818, + "__docId__": 828, "kind": "method", "name": "getFeatureInfoAtCoordinate", "memberof": "build/ol/layers/VectorLayer.js~VectorLayer", @@ -16589,7 +16868,7 @@ } }, { - "__docId__": 819, + "__docId__": 829, "kind": "file", "name": "build/ol/layers/index.js", "content": "export { default as Layer } from './Layer';\nexport * from './Layer';\nexport { default as MaplibreLayer } from './MaplibreLayer';\nexport * from './MaplibreLayer';\nexport { default as MaplibreStyleLayer } from './MaplibreStyleLayer';\nexport * from './MaplibreStyleLayer';\nexport { default as MapsetLayer } from './MapsetLayer';\nexport * from './MapsetLayer';\nexport { default as MocoLayer } from './MocoLayer';\nexport * from './MocoLayer';\nexport { default as RealtimeLayer } from './RealtimeLayer';\nexport * from './RealtimeLayer';\nexport { default as VectorLayer } from './VectorLayer';\nexport * from './VectorLayer';\n", @@ -16600,7 +16879,7 @@ "lineNumber": 1 }, { - "__docId__": 820, + "__docId__": 830, "kind": "file", "name": "build/ol/renderers/MaplibreLayerRenderer.js", "content": "import { MapLibreLayerRenderer } from '@geoblocks/ol-maplibre-layer/lib';\n/**\n * This class is usea renderer for Maplibre Layer to be able to use the native ol\n * functionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.\n * @private\n */\nexport default class MaplibreLayerRenderer extends MapLibreLayerRenderer {\n constructor(layer, translateZoom) {\n super(layer, translateZoom);\n this.ignoreNextRender = false;\n this.tranaslateZoom2 = translateZoom;\n this.setIsReady = this.setIsReady.bind(this);\n this.ignoreNextRender = false;\n }\n prepareFrame() {\n return true;\n }\n renderFrame(frameState) {\n const layer = this.getLayer();\n const { mapLibreMap } = layer;\n const map = layer.getMapInternal();\n if (!layer || !map || !mapLibreMap) {\n // @ts-expect-error - can return null\n return null;\n }\n if (this.ready && this.ignoreNextRender) {\n this.ignoreNextRender = false;\n return mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.getContainer();\n }\n this.ready = false;\n this.ignoreNextRender = false;\n this.updateReadyState();\n const container = super.renderFrame(frameState);\n // Mark the renderer as ready when the map is idle\n void (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.once('idle', this.setIsReady.bind(this)));\n return container;\n }\n setIsReady() {\n if (!this.ready) {\n this.ready = true;\n this.ignoreNextRender = true;\n this.getLayer().changed();\n }\n }\n updateReadyState() {\n var _a, _b, _c, _d;\n void ((_b = (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.off('idle', this.setIsReady.bind(this)));\n void ((_d = (_c = this.getLayer()) === null || _c === void 0 ? void 0 : _c.mapLibreMap) === null || _d === void 0 ? void 0 : _d.once('idle', this.setIsReady.bind(this)));\n }\n}\n", @@ -16611,7 +16890,7 @@ "lineNumber": 1 }, { - "__docId__": 821, + "__docId__": 831, "kind": "class", "name": "MaplibreLayerRenderer", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js", @@ -16629,7 +16908,7 @@ ] }, { - "__docId__": 822, + "__docId__": 832, "kind": "constructor", "name": "constructor", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16643,7 +16922,7 @@ "undocument": true }, { - "__docId__": 823, + "__docId__": 833, "kind": "member", "name": "ignoreNextRender", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16660,7 +16939,7 @@ } }, { - "__docId__": 824, + "__docId__": 834, "kind": "member", "name": "tranaslateZoom2", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16677,7 +16956,7 @@ } }, { - "__docId__": 827, + "__docId__": 837, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16697,7 +16976,7 @@ } }, { - "__docId__": 828, + "__docId__": 838, "kind": "method", "name": "renderFrame", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16724,7 +17003,7 @@ } }, { - "__docId__": 830, + "__docId__": 840, "kind": "member", "name": "ready", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16741,7 +17020,7 @@ } }, { - "__docId__": 832, + "__docId__": 842, "kind": "method", "name": "setIsReady", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16757,7 +17036,7 @@ "return": null }, { - "__docId__": 835, + "__docId__": 845, "kind": "method", "name": "updateReadyState", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16773,7 +17052,7 @@ "return": null }, { - "__docId__": 836, + "__docId__": 846, "kind": "file", "name": "build/ol/renderers/MaplibreStyleLayerRenderer.js", "content": "import GeoJSON from 'ol/format/GeoJSON';\nimport { toLonLat } from 'ol/proj';\nimport LayerRenderer from 'ol/renderer/Layer';\nimport { VECTOR_TILE_FEATURE_PROPERTY } from '../../common';\n/**\n * @private\n */\nconst formats = {\n 'EPSG:3857': new GeoJSON({\n featureProjection: 'EPSG:3857',\n }),\n};\n/**\n * This class is a renderer for Maplibre Layer to be able to use the native ol\n * functionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.\n * @private\n */\nexport default class MaplibreStyleLayerRenderer extends LayerRenderer {\n forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {\n const features = this.getFeaturesAtCoordinate(coordinate, hitTolerance);\n features.forEach((feature) => {\n // @ts-expect-error improve ts types\n callback(feature, this.layer_, feature.getGeometry());\n });\n return features === null || features === void 0 ? void 0 : features[0];\n }\n getFeatures(pixel) {\n var _a, _b;\n const coordinate = (_b = (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.getMapInternal()) === null || _b === void 0 ? void 0 : _b.getCoordinateFromPixel(pixel);\n return Promise.resolve(this.getFeaturesAtCoordinate(coordinate));\n }\n getFeaturesAtCoordinate(coordinate, hitTolerance = 5) {\n var _a, _b, _c;\n if (!coordinate) {\n return [];\n }\n const layer = this.getLayer();\n const map = layer.getMapInternal();\n const mapLibreMap = (_a = layer.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap;\n const projection = ((_c = (_b = map === null || map === void 0 ? void 0 : map.getView()) === null || _b === void 0 ? void 0 : _b.getProjection()) === null || _c === void 0 ? void 0 : _c.getCode()) || 'EPSG:3857';\n let features = [];\n if (!formats[projection]) {\n formats[projection] = new GeoJSON({\n featureProjection: projection,\n });\n }\n if (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.isStyleLoaded()) {\n const pixel = coordinate &&\n mapLibreMap.project(toLonLat(coordinate));\n if ((pixel === null || pixel === void 0 ? void 0 : pixel.x) && (pixel === null || pixel === void 0 ? void 0 : pixel.y)) {\n let pixels = [\n pixel.x,\n pixel.y,\n ];\n if (hitTolerance) {\n const [x, y] = pixels;\n pixels = [\n [x - hitTolerance, y - hitTolerance],\n [x + hitTolerance, y + hitTolerance],\n ];\n }\n // We query features only on style layers used by this layer.\n let layers = layer.layers || [];\n if (layer.layersFilter) {\n layers = mapLibreMap.getStyle().layers.filter(layer.layersFilter);\n }\n if (layer.queryRenderedLayersFilter) {\n layers = mapLibreMap\n .getStyle()\n .layers.filter(layer.queryRenderedLayersFilter);\n }\n // At this point we get GeoJSON Maplibre feature, we transform it to an OpenLayers\n // feature to be consistent with other layers.\n features = mapLibreMap\n .queryRenderedFeatures(pixels, {\n layers: layers.map((l) => {\n return l.id;\n }),\n validate: false,\n // ...layer.queryRenderedFeaturesOptions,\n })\n .map((feature) => {\n const olFeature = formats[projection].readFeature(feature);\n if (olFeature) {\n // We save the original Maplibre feature to avoid losing informations\n // potentially needed for other functionnality like highlighting\n // (id, layer id, source, sourceLayer ...)\n olFeature.set(VECTOR_TILE_FEATURE_PROPERTY, feature);\n }\n return olFeature;\n });\n }\n }\n return features;\n }\n prepareFrame() {\n return true;\n }\n renderFrame(frameState, target) {\n // Return an empty div as a placeholder since nothing is rendered\n return target !== null && target !== void 0 ? target : document.createElement('div');\n }\n}\n", @@ -16784,7 +17063,7 @@ "lineNumber": 1 }, { - "__docId__": 837, + "__docId__": 847, "kind": "variable", "name": "formats", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js", @@ -16804,7 +17083,7 @@ "ignore": true }, { - "__docId__": 838, + "__docId__": 848, "kind": "class", "name": "MaplibreStyleLayerRenderer", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js", @@ -16822,7 +17101,7 @@ ] }, { - "__docId__": 839, + "__docId__": 849, "kind": "method", "name": "forEachFeatureAtCoordinate", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js~MaplibreStyleLayerRenderer", @@ -16867,7 +17146,7 @@ } }, { - "__docId__": 840, + "__docId__": 850, "kind": "method", "name": "getFeatures", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js~MaplibreStyleLayerRenderer", @@ -16894,7 +17173,7 @@ } }, { - "__docId__": 841, + "__docId__": 851, "kind": "method", "name": "getFeaturesAtCoordinate", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js~MaplibreStyleLayerRenderer", @@ -16930,7 +17209,7 @@ } }, { - "__docId__": 842, + "__docId__": 852, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js~MaplibreStyleLayerRenderer", @@ -16950,7 +17229,7 @@ } }, { - "__docId__": 843, + "__docId__": 853, "kind": "method", "name": "renderFrame", "memberof": "build/ol/renderers/MaplibreStyleLayerRenderer.js~MaplibreStyleLayerRenderer", @@ -16983,7 +17262,7 @@ } }, { - "__docId__": 844, + "__docId__": 854, "kind": "file", "name": "build/ol/renderers/RealtimeLayerRenderer.js", "content": "import GeoJSON from 'ol/format/GeoJSON';\nimport CanvasLayerRenderer from 'ol/renderer/canvas/Layer';\nimport { composeCssTransform } from 'ol/transform';\nconst format = new GeoJSON();\n/**\n * This class is a renderer for Maplibre Layer to be able to use the native ol\n * functionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.\n * @private\n */\nexport default class RealtimeLayerRenderer extends CanvasLayerRenderer {\n forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {\n const features = this.getFeaturesAtCoordinate(coordinate, hitTolerance);\n features.forEach((feature) => {\n // @ts-expect-error defintion to fix\n callback(feature, this.layer_, feature.getGeometry());\n });\n return features === null || features === void 0 ? void 0 : features[0];\n }\n getData(pixel) {\n var _a;\n let data;\n try {\n const { pixelRatio } = this.getLayer();\n const context = (_a = this.canvas) === null || _a === void 0 ? void 0 : _a.getContext('2d', {\n willReadFrequently: true,\n });\n data =\n (context === null || context === void 0 ? void 0 : context.getImageData(pixel[0] * (pixelRatio || 1), pixel[1] * (pixelRatio || 1), 1, 1).data) || null; // [3];\n return data;\n }\n catch (err) {\n console.error('error getting data', err);\n }\n return null;\n }\n getFeatures(pixel) {\n var _a, _b;\n const coordinate = (_b = (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.getMapInternal()) === null || _b === void 0 ? void 0 : _b.getCoordinateFromPixel(pixel);\n return Promise.resolve(this.getFeaturesAtCoordinate(coordinate));\n }\n getFeaturesAtCoordinate(coordinate, hitTolerance = 5) {\n if (!coordinate) {\n return [];\n }\n const layer = this.getLayer();\n const featureCollection = layer.engine.getVehiclesAtCoordinate(coordinate, {\n hitTolerance,\n nb: layer.maxNbFeaturesRequested,\n });\n return format.readFeatures(featureCollection);\n }\n prepareFrame() {\n return true;\n }\n renderFrame(frameState) {\n var _a;\n const { canvas, engine, renderedViewState } = this.getLayer();\n this.getLayer().engine.pixelRatio = frameState.pixelRatio;\n this.ready = !!((_a = engine.renderState) === null || _a === void 0 ? void 0 : _a.renderedTrajectories) && engine.isIdle;\n if (!this.container) {\n this.container = document.createElement('div');\n this.container.className = this.getLayer().getClassName();\n this.container.style.position = 'absolute';\n this.container.style.width = '100%';\n this.container.style.height = '100%';\n if (canvas instanceof HTMLCanvasElement) {\n canvas.style.position = 'absolute';\n canvas.style.top = '0';\n canvas.style.left = '0';\n canvas.style.transformOrigin = 'top left';\n this.container.appendChild(canvas);\n }\n }\n if (renderedViewState) {\n const { center, resolution, rotation } = frameState.viewState;\n const { center: renderedCenter, resolution: renderedResolution, rotation: renderedRotation, } = renderedViewState;\n if (renderedResolution / resolution >= 3) {\n // Avoid having really big points when zooming fast.\n const context = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');\n if ((canvas === null || canvas === void 0 ? void 0 : canvas.width) && (canvas === null || canvas === void 0 ? void 0 : canvas.height)) {\n context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);\n }\n }\n else {\n const map = this.getLayer().getMapInternal();\n const pixelCenterRendered = map === null || map === void 0 ? void 0 : map.getPixelFromCoordinate(renderedCenter);\n const pixelCenter = map === null || map === void 0 ? void 0 : map.getPixelFromCoordinate(center);\n if (pixelCenterRendered && pixelCenter) {\n this.container.style.transform = composeCssTransform(pixelCenterRendered[0] - pixelCenter[0], pixelCenterRendered[1] - pixelCenter[1], renderedResolution / resolution, renderedResolution / resolution, rotation - renderedRotation, 0, 0);\n }\n }\n }\n return this.container;\n }\n}\n", @@ -16994,7 +17273,7 @@ "lineNumber": 1 }, { - "__docId__": 845, + "__docId__": 855, "kind": "variable", "name": "format", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js", @@ -17015,7 +17294,7 @@ "ignore": true }, { - "__docId__": 846, + "__docId__": 856, "kind": "class", "name": "RealtimeLayerRenderer", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js", @@ -17033,7 +17312,7 @@ ] }, { - "__docId__": 847, + "__docId__": 857, "kind": "method", "name": "forEachFeatureAtCoordinate", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17078,7 +17357,7 @@ } }, { - "__docId__": 848, + "__docId__": 858, "kind": "method", "name": "getData", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17105,7 +17384,7 @@ } }, { - "__docId__": 849, + "__docId__": 859, "kind": "method", "name": "getFeatures", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17132,7 +17411,7 @@ } }, { - "__docId__": 850, + "__docId__": 860, "kind": "method", "name": "getFeaturesAtCoordinate", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17168,7 +17447,7 @@ } }, { - "__docId__": 851, + "__docId__": 861, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17188,7 +17467,7 @@ } }, { - "__docId__": 852, + "__docId__": 862, "kind": "method", "name": "renderFrame", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17215,7 +17494,7 @@ } }, { - "__docId__": 853, + "__docId__": 863, "kind": "member", "name": "ready", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17232,7 +17511,7 @@ } }, { - "__docId__": 854, + "__docId__": 864, "kind": "member", "name": "container", "memberof": "build/ol/renderers/RealtimeLayerRenderer.js~RealtimeLayerRenderer", @@ -17249,7 +17528,7 @@ } }, { - "__docId__": 855, + "__docId__": 865, "kind": "file", "name": "build/ol/styles/fullTrajectoryDelayStyle.js", "content": "import { Circle, Fill, Stroke, Style } from 'ol/style';\nconst stroke = new Style({\n image: new Circle({\n fill: new Fill({\n color: '#000000',\n }),\n radius: 5,\n }),\n stroke: new Stroke({\n color: '#000000',\n width: 6,\n }),\n zIndex: 2,\n});\nconst fill = new Style({\n image: new Circle({\n fill: new Fill({\n color: '#a0a0a0',\n }),\n radius: 4,\n }),\n stroke: new Stroke({\n color: '#a0a0a0',\n width: 4,\n }),\n zIndex: 3,\n});\n/**\n * @private\n */\nconst fullTrajectoryDelaystyle = () => {\n return [stroke, fill];\n};\nexport default fullTrajectoryDelaystyle;\n", @@ -17260,7 +17539,7 @@ "lineNumber": 1 }, { - "__docId__": 856, + "__docId__": 866, "kind": "variable", "name": "stroke", "memberof": "build/ol/styles/fullTrajectoryDelayStyle.js", @@ -17281,7 +17560,7 @@ "ignore": true }, { - "__docId__": 857, + "__docId__": 867, "kind": "variable", "name": "fill", "memberof": "build/ol/styles/fullTrajectoryDelayStyle.js", @@ -17302,7 +17581,7 @@ "ignore": true }, { - "__docId__": 858, + "__docId__": 868, "kind": "function", "name": "fullTrajectoryDelaystyle", "memberof": "build/ol/styles/fullTrajectoryDelayStyle.js", @@ -17324,7 +17603,7 @@ } }, { - "__docId__": 859, + "__docId__": 869, "kind": "file", "name": "build/ol/styles/fullTrajectoryStyle.js", "content": "import { Circle, Fill, Stroke, Style } from 'ol/style';\nimport { getColorForType } from '../../common/utils/realtimeStyleUtils';\nconst borderStyle = new Style({\n image: new Circle({\n fill: new Fill({\n color: '#000000',\n }),\n radius: 5,\n }),\n stroke: new Stroke({\n color: '#000000',\n width: 6,\n }),\n zIndex: 2,\n});\nconst fullTrajectorystyle = (feature) => {\n const { stroke, type } = feature.getProperties();\n let lineColor = stroke || getColorForType(type) || '#000';\n if (lineColor && !lineColor.startsWith('#')) {\n lineColor = `#${lineColor}`;\n }\n const style = [\n borderStyle,\n new Style({\n image: new Circle({\n fill: new Fill({\n color: lineColor,\n }),\n radius: 4,\n }),\n stroke: new Stroke({\n color: lineColor,\n width: 4,\n }),\n zIndex: 3,\n }),\n ];\n return style;\n};\nexport default fullTrajectorystyle;\n", @@ -17335,7 +17614,7 @@ "lineNumber": 1 }, { - "__docId__": 860, + "__docId__": 870, "kind": "variable", "name": "borderStyle", "memberof": "build/ol/styles/fullTrajectoryStyle.js", @@ -17356,7 +17635,7 @@ "ignore": true }, { - "__docId__": 861, + "__docId__": 871, "kind": "function", "name": "fullTrajectorystyle", "memberof": "build/ol/styles/fullTrajectoryStyle.js", @@ -17386,7 +17665,7 @@ } }, { - "__docId__": 862, + "__docId__": 872, "kind": "file", "name": "build/ol/styles/index.js", "content": "export { default as fullTrajectoryDelayStyle } from './fullTrajectoryDelayStyle';\nexport { default as fullTrajectoryStyle } from './fullTrajectoryStyle';\nexport { default as routingStyle } from './routingStyle';\n", @@ -17397,7 +17676,7 @@ "lineNumber": 1 }, { - "__docId__": 863, + "__docId__": 873, "kind": "file", "name": "build/ol/styles/routingStyle.js", "content": "import { Circle, Fill, Stroke } from 'ol/style';\nimport Style from 'ol/style/Style';\nconst circleStyle = new Circle({\n fill: new Fill({\n color: [255, 0, 0, 1],\n }),\n radius: 6,\n stroke: new Stroke({\n color: [0, 0, 0, 1],\n width: 1,\n }),\n});\nconst blackBorder = new Style({\n stroke: new Stroke({\n color: [0, 0, 0, 1],\n width: 5,\n }),\n});\nconst redLine = new Style({\n image: circleStyle,\n stroke: new Stroke({\n color: [255, 0, 0, 1],\n width: 3,\n }),\n});\nconst dashedRedLine = new Style({\n image: circleStyle,\n stroke: new Stroke({\n color: [255, 0, 0, 1],\n lineDash: [1, 10],\n width: 3,\n }),\n});\nconst routingStyle = (feature, resolution) => {\n var _a;\n const minResolution = feature.get('minResolution');\n const maxResolution = feature.get('maxResolution');\n const inRange = resolution <= minResolution && resolution > maxResolution;\n if (minResolution && maxResolution && !inRange) {\n return [];\n }\n const zIndex = ((_a = feature === null || feature === void 0 ? void 0 : feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' ? 100 : 0;\n let styles = [blackBorder, redLine];\n const mot = feature.get('mot');\n if (mot === 'foot') {\n styles = [dashedRedLine];\n }\n styles = styles.map((style) => {\n const tmp = style.clone();\n tmp.setZIndex(zIndex);\n return tmp;\n });\n return styles;\n};\nexport default routingStyle;\n", @@ -17408,7 +17687,7 @@ "lineNumber": 1 }, { - "__docId__": 864, + "__docId__": 874, "kind": "variable", "name": "circleStyle", "memberof": "build/ol/styles/routingStyle.js", @@ -17429,7 +17708,7 @@ "ignore": true }, { - "__docId__": 865, + "__docId__": 875, "kind": "variable", "name": "blackBorder", "memberof": "build/ol/styles/routingStyle.js", @@ -17450,7 +17729,7 @@ "ignore": true }, { - "__docId__": 866, + "__docId__": 876, "kind": "variable", "name": "redLine", "memberof": "build/ol/styles/routingStyle.js", @@ -17471,7 +17750,7 @@ "ignore": true }, { - "__docId__": 867, + "__docId__": 877, "kind": "variable", "name": "dashedRedLine", "memberof": "build/ol/styles/routingStyle.js", @@ -17492,7 +17771,7 @@ "ignore": true }, { - "__docId__": 868, + "__docId__": 878, "kind": "function", "name": "routingStyle", "memberof": "build/ol/styles/routingStyle.js", @@ -17528,10 +17807,10 @@ } }, { - "__docId__": 869, + "__docId__": 879, "kind": "file", "name": "build/ol/utils/MapsetKmlFormat.js", - "content": "import { replace } from 'lodash';\nimport { Feature, getUid } from 'ol';\nimport { asString } from 'ol/color';\nimport KML from 'ol/format/KML';\nimport CircleGeom from 'ol/geom/Circle';\nimport GeometryCollection from 'ol/geom/GeometryCollection';\nimport MultiPoint from 'ol/geom/MultiPoint';\nimport Point from 'ol/geom/Point';\nimport { fromCircle } from 'ol/geom/Polygon';\nimport { get, transform } from 'ol/proj';\nimport { Circle, Fill, Icon, Stroke, Style, Text } from 'ol/style';\nimport { parse } from 'ol/xml';\nimport getPolygonPattern from './getMapsetPolygonPattern';\nconst CIRCLE_GEOMETRY_CENTER = 'circleGeometryCenter';\nconst CIRCLE_GEOMETRY_RADIUS = 'circleGeometryRadius';\nconst EPSG_4326 = get('EPSG:4326');\n// Default style for KML layer\nconst kmlFill = new Fill({\n color: [255, 0, 0, 0.7],\n});\nconst kmlStroke = new Stroke({\n color: [255, 0, 0, 1],\n width: 1.5,\n});\nconst kmlcircle = new Circle({\n fill: kmlFill,\n radius: 7,\n stroke: kmlStroke,\n});\nconst kmlStyle = new Style({\n fill: kmlFill,\n image: kmlcircle,\n stroke: kmlStroke,\n text: new Text({\n fill: kmlFill,\n font: 'normal 16px Helvetica',\n stroke: new Stroke({\n color: [255, 255, 255, 1],\n width: 3,\n }),\n }),\n});\n// Comes from ol >= 6.7,\n// https://github.com/openlayers/openlayers/blob/main/src/ol/format/KML.js#L320\nconst scaleForSize = (size) => {\n return 32 / Math.min(size[0], size[1]);\n};\nconst applyTextStyleForIcon = (olIcon, olText) => {\n const size = olIcon.getSize() || [48, 48];\n const scale = (olIcon.getScale() || 1);\n const anchor = olIcon.getAnchor() || [\n (size[0] * scale) / 2,\n (size[1] * scale) / 2,\n ];\n const offset = [\n scale * (size[0] - anchor[0]) + 5,\n scale * (size[1] / 2 - anchor[1]),\n ];\n olText.setOffsetX(offset[0]);\n olText.setOffsetY(offset[1]);\n olText.setTextAlign('left');\n};\nconst getVertexCoord = (geom, start = true, index = 0) => {\n const coords = geom === null || geom === void 0 ? void 0 : geom.getCoordinates();\n if (!coords) {\n return undefined;\n }\n const len = coords.length - 1;\n return start ? coords[index] : coords[len - index];\n};\nconst getLineIcon = (feature, icon, color, start = true) => {\n const geom = feature.getGeometry();\n const coordA = getVertexCoord(geom, start, 1);\n const coordB = getVertexCoord(geom, start);\n if (!coordA || !coordB) {\n return new Style();\n }\n const dx = start ? coordA[0] - coordB[0] : coordB[0] - coordA[0];\n const dy = start ? coordA[1] - coordB[1] : coordB[1] - coordA[1];\n const rotation = Math.atan2(dy, dx);\n return new Style({\n geometry: (feat) => {\n const ge = feat.getGeometry();\n return new Point(getVertexCoord(ge, start));\n },\n image: new Icon({\n color,\n rotateWithView: true,\n rotation: -rotation,\n scale: icon.scale,\n size: icon.size, // ie 11\n src: icon.url,\n }),\n zIndex: icon.zIndex,\n });\n};\nclass MapsetKmlFormat {\n constructor() {\n /**\n * Write the tag into a KML string. Returns the KML string with added tag.\n * @param {String} kmlString A string representing a KML file.\n * @param {Object} cameraAttributes Object containing the camera tags (longitude, latitude, altitude, heading, tilt, altitudeMode, roll)\n * as keys with corresponding values. See https://developers.google.com/kml/documentation/kmlreference#camera\n */\n this.writeDocumentCamera = (kmlString, cameraAttributes) => {\n const kmlDoc = parse(this.removeDocumentCamera(kmlString));\n if (cameraAttributes) {\n // Create Camera node with child attributes if the cameraAttributes object is defined\n const cameraNode = kmlDoc.createElement('Camera');\n Object.keys(cameraAttributes).forEach((key) => {\n const cameraAttribute = kmlDoc.createElement(`${key.charAt(0).toUpperCase() + key.slice(1)}`);\n cameraAttribute.innerHTML = cameraAttributes[key];\n cameraNode.appendChild(cameraAttribute);\n });\n const documentNode = kmlDoc.getElementsByTagName('Document')[0];\n documentNode.appendChild(cameraNode);\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n };\n }\n /**\n * Read a KML string.\n * @param {String} kmlString A string representing a KML file.\n * @param {} featureProjection The projection used by the map.\n * @param {} doNotRevert32pxScaling Set it to true if you use ol < 6.7 and last version of react-spatial, Fix the 32px scaling, introduced by (ol >= 6.7), see https://github.com/openlayers/openlayers/pull/12695.\n */\n readFeatures(kmlString, featureProjection, doNotRevert32pxScaling = false) {\n // Since ol 6.7, the KML follows better the spec and GoogleEarth interpretation, see https://github.com/openlayers/openlayers/pull/12695.\n // so the value is interpreted using an image size of 32px.\n // So when revert32pxScaling is true we fix back the scale, to use only, if you use an OL < 6.7.\n // Now the writeFeatures function use the iconScale extended data to set the image's scale.\n // If the extended data is not found it will look at this boolean to define if we must revert the scale or not.\n const features = new KML().readFeatures(kmlString, {\n featureProjection,\n });\n features.forEach((feature) => {\n var _a, _b;\n // Transform back polygon to circle geometry\n const { [CIRCLE_GEOMETRY_CENTER]: circleGeometryCenter, [CIRCLE_GEOMETRY_RADIUS]: circleGeometryRadius, } = (feature === null || feature === void 0 ? void 0 : feature.getProperties()) || {};\n if (feature && circleGeometryCenter && circleGeometryRadius) {\n const circle = new CircleGeom(transform(JSON.parse(circleGeometryCenter), EPSG_4326, featureProjection || EPSG_4326), parseFloat(circleGeometryRadius));\n circle.setProperties((_b = (_a = feature === null || feature === void 0 ? void 0 : feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getProperties()) !== null && _b !== void 0 ? _b : {});\n feature.setGeometry(circle);\n }\n this.sanitizeFeature(feature, doNotRevert32pxScaling);\n });\n return features;\n }\n /**\n * Removes the tag from a KML string. Returns the KML string with removed tag.\n * @param {String} kmlString A string representing a KML file.\n */\n removeDocumentCamera(kmlString) {\n const kmlDoc = parse(kmlString);\n // Remove old Camera node\n const oldCameraNode = kmlDoc.getElementsByTagName('Camera')[0];\n if (oldCameraNode) {\n oldCameraNode.remove();\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n }\n sanitizeFeature(feature, doNotRevert32pxScaling = false) {\n var _a, _b, _c, _d, _e, _f, _g;\n const geom = feature.getGeometry();\n let styles = feature.getStyleFunction();\n // Store maxZoom in properties\n if (feature.get('maxZoom')) {\n feature.set('maxZoom', parseFloat(feature.get('maxZoom')));\n }\n // Store minZoom in properties\n if (feature.get('minZoom')) {\n feature.set('minZoom', parseFloat(feature.get('minZoom')));\n }\n // The use of clone is part of the scale fix for OL > 6.7\n // If an IconStyle has no gx:w and gx:h defined, a scale factor is applied\n // after the image is loaded. To avoided having the scale factor applied we\n // clone the style and keep the scale as it is.\n // Having gx:w and gx:h not defined should not happen, using the last version of the parser/reader.\n const tmpStyles = styles === null || styles === void 0 ? void 0 : styles(feature, 1);\n const style = (_a = (Array.isArray(tmpStyles) ? tmpStyles[0] : tmpStyles)) === null || _a === void 0 ? void 0 : _a.clone();\n let stroke = style === null || style === void 0 ? void 0 : style.getStroke();\n if (feature.get('lineCap')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineCap(feature.get('lineCap'));\n }\n if (feature.get('lineJoin')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineJoin(feature.get('lineJoin'));\n }\n if (feature.get('lineDash')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDash((feature === null || feature === void 0 ? void 0 : feature.get('lineDash')).split(',').map((l) => {\n return parseInt(l, 10);\n }));\n }\n if (feature.get('lineDashOffset')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDashOffset(parseInt(feature.get('lineDashOffset'), 10));\n }\n if (feature.get('miterLimit')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setMiterLimit(parseInt(feature.get('miterLimit'), 10));\n }\n // The canvas draws a stroke width=1 by default if width=0, so we\n // remove the stroke style in that case.\n if (stroke && stroke.getWidth() === 0) {\n stroke = undefined;\n }\n if (feature.get('zIndex')) {\n style === null || style === void 0 ? void 0 : style.setZIndex(parseInt(feature.get('zIndex'), 10));\n }\n // if the feature is a Point and we are offline, we use default vector\n // style.\n // if the feature is a Point and has a name with a text style, we\n // create a correct text style.\n // TODO Handle GeometryCollection displaying name on the first Point\n // geometry.\n if (style && (geom instanceof Point || geom instanceof MultiPoint)) {\n let image = style.getImage();\n let text = null;\n let fill = style.getFill();\n // If the feature has name we display it on the map as Google does\n if (feature.get('name') &&\n style.getText() &&\n ((_b = style.getText()) === null || _b === void 0 ? void 0 : _b.getScale()) !== 0) {\n if (image && image.getScale() === 0) {\n // transparentCircle is used to allow selection\n image = new Circle({\n fill: new Fill({ color: [0, 0, 0, 0] }),\n radius: 1,\n stroke: new Stroke({ color: [0, 0, 0, 0] }),\n });\n }\n // We replace empty white spaces used to keep normal spaces before and after the name.\n let name = feature.get('name');\n if (/\\u200B/g.test(name)) {\n name = name.replace(/\\u200B/g, '');\n feature.set('name', name);\n }\n // For backward compatibility we translate the bold and italic textFont property to a textArray prop\n const font = feature.get('textFont') || 'normal 16px Arial';\n // Since we use rich text in mapset editor we use a text array instead,\n // it's only necessary when there is new lines in the text\n // Manage new lines\n if (name.includes('\\n')) {\n const array = [];\n const split = name.split('\\n');\n split.forEach((txt, idx) => {\n array.push(txt || '\\u200B', txt ? font : '');\n if (idx < split.length - 1) {\n array.push('\\n', '');\n }\n });\n name = array;\n }\n else {\n name = [name, font];\n }\n text = new Text({\n fill: style.getText().getFill(),\n font: `${font.replace(/bold/g, 'normal')}, Arial, sans-serif`, // We manage bold in textArray\n // rotation unsupported by KML, taken instead from custom field.\n rotation: feature.get('textRotation') || 0,\n // stroke: style.getText().getStroke(),\n scale: (_c = style.getText()) === null || _c === void 0 ? void 0 : _c.getScale(),\n // since ol 6.3.1 : https://github.com/openlayers/openlayers/pull/10613/files#diff-1883da8b57e690db7ea0c35ce53c880aR925\n // a default textstroke is added to mimic google earth.\n // it was not the case before, the stroke was always null. So to keep\n // the same behavior we don't copy the stroke style.\n // TODO : maybe we should use this functionnality in the futur.\n text: name,\n });\n if (feature.get('textArray')) {\n try {\n const textArray = JSON.parse(replace(feature.get('textArray'), /\\r?\\n/g, '\\\\n'));\n text.setText(textArray);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('Error parsing textArray', feature.get('textArray'), err);\n }\n }\n if (feature.get('textStrokeColor') && feature.get('textStrokeWidth')) {\n text.setStroke(new Stroke({\n color: feature.get('textStrokeColor'),\n width: parseFloat(feature.get('textStrokeWidth')),\n }));\n }\n if (feature.get('textAlign')) {\n text.setTextAlign(feature.get('textAlign'));\n }\n if (feature.get('textOffsetX')) {\n text.setOffsetX(parseFloat(feature.get('textOffsetX')));\n }\n if (feature.get('textOffsetY')) {\n text.setOffsetY(parseFloat(feature.get('textOffsetY')));\n }\n if (feature.get('textBackgroundFillColor')) {\n text.setBackgroundFill(new Fill({\n color: feature.get('textBackgroundFillColor'),\n }));\n }\n if (feature.get('textPadding')) {\n text.setPadding((_d = feature.get('textPadding')) === null || _d === void 0 ? void 0 : _d.split(',').map((n) => {\n return parseFloat(n);\n }));\n }\n if (image instanceof Icon) {\n applyTextStyleForIcon(image, text);\n }\n }\n if (image instanceof Icon) {\n /* Apply icon rotation if defined (by default only written as\n * tag, which is not read as rotation value by the ol KML module)\n */\n image.setRotation(parseFloat(feature.get('iconRotation')) || 0);\n if (feature.get('iconScale')) {\n image.setScale(parseFloat(feature.get('iconScale')) || 0);\n // We fix the 32px scaling introduced by OL 6.7 only if the image has a size defined.\n }\n else if (!doNotRevert32pxScaling && image.getSize()) {\n const resizeScale = scaleForSize(image.getSize());\n image.setScale(image.getScaleArray()[0] / resizeScale);\n }\n }\n fill = null;\n stroke = null;\n styles = (feat, resolution) => {\n /* Options to be used for picture scaling with map, should have at least\n * a resolution attribute (this is the map resolution at the zoom level when\n * the picture is created), can take an optional constant for further scale\n * adjustment.\n * e.g. { resolution: 0.123, defaultScale: 1 / 6 }\n */\n var _a;\n if (feat.get('pictureOptions')) {\n let pictureOptions = feat.get('pictureOptions');\n if (typeof pictureOptions === 'string') {\n pictureOptions = JSON.parse(pictureOptions);\n }\n feat.set('pictureOptions', pictureOptions);\n if (pictureOptions.resolution) {\n image === null || image === void 0 ? void 0 : image.setScale((pictureOptions.resolution / resolution) *\n ((_a = pictureOptions === null || pictureOptions === void 0 ? void 0 : pictureOptions.defaultScale) !== null && _a !== void 0 ? _a : 1));\n }\n }\n return new Style({\n fill: fill !== null && fill !== void 0 ? fill : undefined,\n image: image !== null && image !== void 0 ? image : undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: text !== null && text !== void 0 ? text : undefined,\n zIndex: style.getZIndex(),\n });\n };\n }\n // Remove image and text styles for polygons and lines\n if (!(geom instanceof Point ||\n geom instanceof MultiPoint ||\n geom instanceof GeometryCollection)) {\n styles = [\n new Style({\n fill: (_e = style === null || style === void 0 ? void 0 : style.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: undefined,\n zIndex: style === null || style === void 0 ? void 0 : style.getZIndex(),\n }),\n ];\n // Parse the fillPattern json string and store parsed object\n const fillPattern = feature.get('fillPattern');\n if (fillPattern) {\n const fillPatternOptions = JSON.parse(fillPattern);\n feature.set('fillPattern', fillPatternOptions);\n /* We set the fill pattern for polygons */\n if (!(style === null || style === void 0 ? void 0 : style.getFill())) {\n styles[0].setFill(new Fill());\n }\n const patternOrColor = (fillPatternOptions === null || fillPatternOptions === void 0 ? void 0 : fillPatternOptions.empty)\n ? [0, 0, 0, 0]\n : getPolygonPattern(fillPatternOptions.id, fillPatternOptions.color);\n (_g = (_f = styles[0]) === null || _f === void 0 ? void 0 : _f.getFill()) === null || _g === void 0 ? void 0 : _g.setColor(patternOrColor);\n }\n // Add line's icons styles\n if (feature.get('lineStartIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineStartIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor()));\n }\n if (feature.get('lineEndIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineEndIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor(), false));\n }\n }\n feature.setStyle(styles);\n }\n /**\n * Create a KML string.\n * @param {VectorLayer} layer A react-spatial VectorLayer.\n * @param {} featureProjection The current projection used by the features.\n * @param {} fixGxyAndGxh If the KML contains gx:w and gx:h, (ol >= 6.7), it will fix the bug introduced by https://github.com/openlayers/openlayers/pull/12695.\n */\n writeFeatures(layer, featureProjection, mapResolution) {\n var _a, _b;\n let featString;\n // const olLayer = layer.olLayer || layer.get('olLayer') || layer;\n const exportFeatures = [];\n [...((_b = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getFeatures()) !== null && _b !== void 0 ? _b : [])]\n .sort((a, b) => {\n // The order of features must be kept.\n // We could use the useSpatialIndex = false property on the layer\n // but we prefer to sort feature by ol uid because ol uid is an integer\n // increased on each creation of a feature.\n // So we will keep the order of creation made by the the KML parser.\n // Ideally we should order by the zIndex of the style only.\n if (getUid(a) <= getUid(b)) {\n return -1;\n }\n return 1;\n })\n .forEach((feature) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;\n const clone = feature.clone();\n if (((_a = clone.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Circle') {\n // We transform circle elements into polygons\n // because circle not supported in KML spec and in ol KML parser\n const circleGeom = feature.getGeometry();\n clone.setGeometry(fromCircle(circleGeom, 100));\n clone.set(CIRCLE_GEOMETRY_CENTER, JSON.stringify(transform(circleGeom.getCenter(), featureProjection, EPSG_4326)));\n clone.set(CIRCLE_GEOMETRY_RADIUS, circleGeom.getRadius());\n }\n clone.setId(feature.getId());\n (_b = clone.getGeometry()) === null || _b === void 0 ? void 0 : _b.transform(featureProjection, EPSG_4326);\n // We remove all ExtendedData not related to style.\n Object.keys(feature.getProperties()).forEach((key) => {\n if (![\n CIRCLE_GEOMETRY_CENTER,\n CIRCLE_GEOMETRY_RADIUS,\n 'description',\n 'geometry',\n 'name',\n ].includes(key)) {\n clone.unset(key, true);\n }\n });\n let styles;\n if (feature.getStyleFunction()) {\n styles = (_c = feature.getStyleFunction()) === null || _c === void 0 ? void 0 : _c(feature, mapResolution);\n }\n else if (layer === null || layer === void 0 ? void 0 : layer.getStyleFunction()) {\n styles = (_d = layer.getStyleFunction()) === null || _d === void 0 ? void 0 : _d(feature, mapResolution);\n }\n const mainStyle = Array.isArray(styles) ? styles[0] : styles;\n const newStyle = {\n fill: (_e = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: (_f = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getImage()) !== null && _f !== void 0 ? _f : undefined,\n stroke: (_g = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getStroke()) !== null && _g !== void 0 ? _g : undefined,\n text: (_h = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getText()) !== null && _h !== void 0 ? _h : undefined,\n zIndex: (_j = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getZIndex()) !== null && _j !== void 0 ? _j : undefined,\n };\n if (newStyle.zIndex) {\n clone.set('zIndex', newStyle.zIndex);\n }\n const text = (_k = newStyle.text) === null || _k === void 0 ? void 0 : _k.getText();\n if (text) {\n let kmlText = '';\n if (Array.isArray(text)) {\n // text can be a string or an array of strings\n clone.set('textArray', JSON.stringify(text));\n const textArray = text;\n // in the KML we just add the text without the bold or italic information\n kmlText = textArray\n .map((t, idx) => {\n return idx % 2 === 0 ? t : '';\n })\n .join('')\n .replace(/\\u200B/g, '');\n }\n // We add the current text as features's name so it will be added as Placemark's name in the kml\n if (kmlText) {\n // If we see spaces at the beginning or at the end we add a empty\n // white space at the beginning and at the end.\n if (/^(\\s|\\n)|(\\n|\\s)$/g.test(kmlText)) {\n clone.set('name', `\\u200B${kmlText}\\u200B`);\n }\n else {\n clone.set('name', kmlText);\n }\n }\n }\n // Set custom properties to be converted in extendedData in KML.\n if ((_l = newStyle.text) === null || _l === void 0 ? void 0 : _l.getRotation()) {\n clone.set('textRotation', newStyle.text.getRotation());\n }\n if ((_m = newStyle.text) === null || _m === void 0 ? void 0 : _m.getFont()) {\n clone.set('textFont', newStyle.text.getFont());\n }\n if ((_o = newStyle.text) === null || _o === void 0 ? void 0 : _o.getTextAlign()) {\n clone.set('textAlign', newStyle.text.getTextAlign());\n }\n if ((_p = newStyle.text) === null || _p === void 0 ? void 0 : _p.getOffsetX()) {\n clone.set('textOffsetX', newStyle.text.getOffsetX());\n }\n if ((_q = newStyle.text) === null || _q === void 0 ? void 0 : _q.getOffsetY()) {\n clone.set('textOffsetY', newStyle.text.getOffsetY());\n }\n if ((_r = newStyle.text) === null || _r === void 0 ? void 0 : _r.getStroke()) {\n if ((_s = newStyle.text.getStroke()) === null || _s === void 0 ? void 0 : _s.getColor()) {\n clone.set('textStrokeColor', asString((_t = newStyle.text.getStroke()) === null || _t === void 0 ? void 0 : _t.getColor()));\n }\n if ((_u = newStyle.text.getStroke()) === null || _u === void 0 ? void 0 : _u.getWidth()) {\n clone.set('textStrokeWidth', (_v = newStyle.text.getStroke()) === null || _v === void 0 ? void 0 : _v.getWidth());\n }\n }\n if ((_w = newStyle.text) === null || _w === void 0 ? void 0 : _w.getBackgroundFill()) {\n clone.set('textBackgroundFillColor', asString((_x = newStyle.text.getBackgroundFill()) === null || _x === void 0 ? void 0 : _x.getColor()));\n }\n if ((_y = newStyle.text) === null || _y === void 0 ? void 0 : _y.getPadding()) {\n clone.set('textPadding', (_z = newStyle.text.getPadding()) === null || _z === void 0 ? void 0 : _z.join());\n }\n if ((_0 = newStyle.stroke) === null || _0 === void 0 ? void 0 : _0.getLineCap()) {\n clone.set('lineCap', newStyle.stroke.getLineCap());\n }\n if ((_1 = newStyle.stroke) === null || _1 === void 0 ? void 0 : _1.getLineJoin()) {\n clone.set('lineJoin', newStyle.stroke.getLineJoin());\n }\n if ((_2 = newStyle.stroke) === null || _2 === void 0 ? void 0 : _2.getLineDash()) {\n clone.set('lineDash', (_3 = newStyle.stroke.getLineDash()) === null || _3 === void 0 ? void 0 : _3.join(','));\n }\n if ((_4 = newStyle.stroke) === null || _4 === void 0 ? void 0 : _4.getLineDashOffset()) {\n clone.set('lineDashOffset', newStyle.stroke.getLineDashOffset());\n }\n if ((_5 = newStyle.stroke) === null || _5 === void 0 ? void 0 : _5.getMiterLimit()) {\n clone.set('miterLimit', newStyle.stroke.getMiterLimit());\n }\n if (newStyle.image instanceof Circle) {\n newStyle.image = undefined;\n }\n if (newStyle.image) {\n const imgSource = newStyle.image.getSrc();\n if (!/(http(s?)):\\/\\//gi.test(imgSource)) {\n // eslint-disable-next-line no-console\n console.log('Local image source not supported for KML export.' +\n 'Should use remote web server');\n }\n if (newStyle.image.getRotation()) {\n // We set the icon rotation as extended data\n clone.set('iconRotation', newStyle.image.getRotation());\n }\n if (newStyle.image.getScale()) {\n // We set the scale as extended metadata because the in the KML is related to a 32px img, since ol >= 6.10.\n clone.set('iconScale', newStyle.image.getScale());\n }\n // Set map resolution to use for icon-to-map proportional scaling\n if (feature.get('pictureOptions')) {\n clone.set('pictureOptions', JSON.stringify(feature.get('pictureOptions')));\n }\n }\n // In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc)\n if (feature.get('fillPattern')) {\n clone.set('fillPattern', JSON.stringify(feature.get('fillPattern')));\n newStyle.fill = undefined;\n }\n // maxZoom: maximum zoom level at which the feature is displayed\n if (feature.get('maxZoom')) {\n clone.set('maxZoom', parseFloat(feature.get('maxZoom')));\n }\n // minZoom: minimum zoom level at which the feature is displayed\n if (feature.get('minZoom')) {\n clone.set('minZoom', parseFloat(feature.get('minZoom')));\n }\n // If only text is displayed we must specify an\n // image style with scale=0\n if (newStyle.text && !newStyle.image) {\n newStyle.image = new Icon({\n scale: 0,\n src: 'noimage',\n });\n }\n // In case we use line's icon .\n const extraLineStyles = (Array.isArray(styles) && styles.slice(1)) || [];\n extraLineStyles.forEach((extraLineStyle) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n if (extraLineStyle &&\n extraLineStyle.getImage() instanceof Icon &&\n extraLineStyle.getGeometry()) {\n const coord = (_b = (_a = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getGeometry()) === null || _a === void 0 ? void 0 : _a(feature)) === null || _b === void 0 ? void 0 : _b.getCoordinates();\n const startCoord = (_c = feature.getGeometry()) === null || _c === void 0 ? void 0 : _c.getFirstCoordinate();\n if ((coord === null || coord === void 0 ? void 0 : coord[0]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[0]) &&\n (coord === null || coord === void 0 ? void 0 : coord[1]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[1])) {\n clone.set('lineStartIcon', JSON.stringify({\n scale: (_d = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _d === void 0 ? void 0 : _d.getScale(),\n size: (_e = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _e === void 0 ? void 0 : _e.getSize(),\n url: (_f = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _f === void 0 ? void 0 : _f.getSrc(),\n zIndex: extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getZIndex(),\n }));\n }\n else {\n clone.set('lineEndIcon', JSON.stringify({\n scale: (_g = extraLineStyle.getImage()) === null || _g === void 0 ? void 0 : _g.getScale(),\n size: (_h = extraLineStyle.getImage()) === null || _h === void 0 ? void 0 : _h.getSize(),\n url: (_j = extraLineStyle.getImage()) === null || _j === void 0 ? void 0 : _j.getSrc(),\n zIndex: extraLineStyle.getZIndex(),\n }));\n }\n }\n });\n const olStyle = new Style(newStyle);\n clone.setStyle(olStyle);\n if (!(clone.getGeometry() instanceof Point &&\n olStyle.getText() &&\n !((_6 = olStyle.getText()) === null || _6 === void 0 ? void 0 : _6.getText()))) {\n exportFeatures.push(clone);\n }\n });\n if (exportFeatures.length > 0) {\n if (exportFeatures.length === 1) {\n // force the add of a node\n exportFeatures.push(new Feature());\n }\n featString = new KML({\n defaultStyle: [kmlStyle],\n extractStyles: true,\n }).writeFeatures(exportFeatures);\n // Remove no image hack\n featString = featString.replace(/\\s*noimage<\\/href>\\s*<\\/Icon>/g, '');\n // Remove empty placemark added to have\n // tag\n featString = featString.replace(//g, '');\n // Add KML document name\n if (layer.get('name')) {\n featString = featString.replace(//, `${layer.get('name')}`);\n }\n }\n return featString;\n }\n}\nexport default MapsetKmlFormat;\n", + "content": "import { replace } from 'lodash';\nimport { Feature, getUid } from 'ol';\nimport { asString } from 'ol/color';\nimport KML from 'ol/format/KML';\nimport CircleGeom from 'ol/geom/Circle';\nimport GeometryCollection from 'ol/geom/GeometryCollection';\nimport MultiPoint from 'ol/geom/MultiPoint';\nimport Point from 'ol/geom/Point';\nimport { fromCircle } from 'ol/geom/Polygon';\nimport { get, transform } from 'ol/proj';\nimport { Circle, Fill, Icon, Stroke, Style, Text } from 'ol/style';\nimport { parse } from 'ol/xml';\nimport getPolygonPattern from './getMapsetPolygonPattern';\nconst CIRCLE_GEOMETRY_CENTER = 'circleGeometryCenter';\nconst CIRCLE_GEOMETRY_RADIUS = 'circleGeometryRadius';\nconst EPSG_4326 = get('EPSG:4326');\n// Default style for KML layer\nconst kmlFill = new Fill({\n color: [255, 0, 0, 0.7],\n});\nconst kmlStroke = new Stroke({\n color: [255, 0, 0, 1],\n width: 1.5,\n});\nconst kmlcircle = new Circle({\n fill: kmlFill,\n radius: 7,\n stroke: kmlStroke,\n});\nconst kmlStyle = new Style({\n fill: kmlFill,\n image: kmlcircle,\n stroke: kmlStroke,\n text: new Text({\n fill: kmlFill,\n font: 'normal 16px Helvetica',\n stroke: new Stroke({\n color: [255, 255, 255, 1],\n width: 3,\n }),\n }),\n});\n// Comes from ol >= 6.7,\n// https://github.com/openlayers/openlayers/blob/main/src/ol/format/KML.js#L320\nconst scaleForSize = (size) => {\n return 32 / Math.min(size[0], size[1]);\n};\nconst applyTextStyleForIcon = (olIcon, olText) => {\n const size = olIcon.getSize() || [48, 48];\n const scale = (olIcon.getScale() || 1);\n const anchor = olIcon.getAnchor() || [\n (size[0] * scale) / 2,\n (size[1] * scale) / 2,\n ];\n const offset = [\n scale * (size[0] - anchor[0]) + 5,\n scale * (size[1] / 2 - anchor[1]),\n ];\n olText.setOffsetX(offset[0]);\n olText.setOffsetY(offset[1]);\n olText.setTextAlign('left');\n};\nconst getVertexCoord = (geom, start = true, index = 0) => {\n const coords = geom === null || geom === void 0 ? void 0 : geom.getCoordinates();\n if (!coords) {\n return undefined;\n }\n const len = coords.length - 1;\n return start ? coords[index] : coords[len - index];\n};\nconst getLineIcon = (feature, icon, color, start = true) => {\n const geom = feature.getGeometry();\n const coordA = getVertexCoord(geom, start, 1);\n const coordB = getVertexCoord(geom, start);\n if (!coordA || !coordB) {\n return new Style();\n }\n const dx = start ? coordA[0] - coordB[0] : coordB[0] - coordA[0];\n const dy = start ? coordA[1] - coordB[1] : coordB[1] - coordA[1];\n const rotation = Math.atan2(dy, dx);\n return new Style({\n geometry: (feat) => {\n const ge = feat.getGeometry();\n return new Point(getVertexCoord(ge, start));\n },\n image: new Icon({\n color,\n rotateWithView: true,\n rotation: -rotation,\n scale: icon.scale,\n size: icon.size, // ie 11\n src: icon.url,\n }),\n zIndex: icon.zIndex,\n });\n};\nclass MapsetKmlFormat {\n constructor() {\n /**\n * Write the tag into a KML string. Returns the KML string with added tag.\n * @param {String} kmlString A string representing a KML file.\n * @param {Object} cameraAttributes Object containing the camera tags (longitude, latitude, altitude, heading, tilt, altitudeMode, roll)\n * as keys with corresponding values. See https://developers.google.com/kml/documentation/kmlreference#camera\n */\n this.writeDocumentCamera = (kmlString, cameraAttributes) => {\n const kmlDoc = parse(this.removeDocumentCamera(kmlString));\n if (cameraAttributes) {\n // Create Camera node with child attributes if the cameraAttributes object is defined\n const cameraNode = kmlDoc.createElement('Camera');\n Object.keys(cameraAttributes).forEach((key) => {\n const cameraAttribute = kmlDoc.createElement(`${key.charAt(0).toUpperCase() + key.slice(1)}`);\n cameraAttribute.innerHTML = cameraAttributes[key];\n cameraNode.appendChild(cameraAttribute);\n });\n const documentNode = kmlDoc.getElementsByTagName('Document')[0];\n documentNode.appendChild(cameraNode);\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n };\n }\n /**\n * Read a KML string.\n * @param {String} kmlString A string representing a KML file.\n * @param {} featureProjection The projection used by the map.\n * @param {} doNotRevert32pxScaling Set it to true if you use ol < 6.7 and last version of react-spatial, Fix the 32px scaling, introduced by (ol >= 6.7), see https://github.com/openlayers/openlayers/pull/12695.\n */\n readFeatures(kmlString, featureProjection, doNotRevert32pxScaling = false) {\n // Since ol 6.7, the KML follows better the spec and GoogleEarth interpretation, see https://github.com/openlayers/openlayers/pull/12695.\n // so the value is interpreted using an image size of 32px.\n // So when revert32pxScaling is true we fix back the scale, to use only, if you use an OL < 6.7.\n // Now the writeFeatures function use the iconScale extended data to set the image's scale.\n // If the extended data is not found it will look at this boolean to define if we must revert the scale or not.\n const features = new KML().readFeatures(kmlString, {\n featureProjection,\n });\n features.forEach((feature) => {\n var _a, _b;\n // Transform back polygon to circle geometry\n const { [CIRCLE_GEOMETRY_CENTER]: circleGeometryCenter, [CIRCLE_GEOMETRY_RADIUS]: circleGeometryRadius, } = (feature === null || feature === void 0 ? void 0 : feature.getProperties()) || {};\n if (feature && circleGeometryCenter && circleGeometryRadius) {\n const circle = new CircleGeom(transform(JSON.parse(circleGeometryCenter), EPSG_4326, featureProjection || EPSG_4326), parseFloat(circleGeometryRadius));\n circle.setProperties((_b = (_a = feature === null || feature === void 0 ? void 0 : feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getProperties()) !== null && _b !== void 0 ? _b : {});\n feature.setGeometry(circle);\n }\n this.sanitizeFeature(feature, doNotRevert32pxScaling);\n });\n return features;\n }\n /**\n * Removes the tag from a KML string. Returns the KML string with removed tag.\n * @param {String} kmlString A string representing a KML file.\n */\n removeDocumentCamera(kmlString) {\n const kmlDoc = parse(kmlString);\n // Remove old Camera node\n const oldCameraNode = kmlDoc.getElementsByTagName('Camera')[0];\n if (oldCameraNode) {\n oldCameraNode.remove();\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n }\n sanitizeFeature(feature, doNotRevert32pxScaling = false) {\n var _a, _b, _c, _d, _e, _f, _g;\n const geom = feature.getGeometry();\n let styles = feature.getStyleFunction();\n // Store maxZoom in properties\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n feature.set('maxZoom', maxZoom);\n }\n // Store minZoom in properties\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n feature.set('minZoom', minZoom);\n }\n // The use of clone is part of the scale fix for OL > 6.7\n // If an IconStyle has no gx:w and gx:h defined, a scale factor is applied\n // after the image is loaded. To avoided having the scale factor applied we\n // clone the style and keep the scale as it is.\n // Having gx:w and gx:h not defined should not happen, using the last version of the parser/reader.\n const tmpStyles = styles === null || styles === void 0 ? void 0 : styles(feature, 1);\n const style = (_a = (Array.isArray(tmpStyles) ? tmpStyles[0] : tmpStyles)) === null || _a === void 0 ? void 0 : _a.clone();\n let stroke = style === null || style === void 0 ? void 0 : style.getStroke();\n if (feature.get('lineCap')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineCap(feature.get('lineCap'));\n }\n if (feature.get('lineJoin')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineJoin(feature.get('lineJoin'));\n }\n if (feature.get('lineDash')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDash((feature === null || feature === void 0 ? void 0 : feature.get('lineDash')).split(',').map((l) => {\n return parseInt(l, 10);\n }));\n }\n if (feature.get('lineDashOffset')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDashOffset(parseInt(feature.get('lineDashOffset'), 10));\n }\n if (feature.get('miterLimit')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setMiterLimit(parseInt(feature.get('miterLimit'), 10));\n }\n // The canvas draws a stroke width=1 by default if width=0, so we\n // remove the stroke style in that case.\n if (stroke && stroke.getWidth() === 0) {\n stroke = undefined;\n }\n if (feature.get('zIndex')) {\n style === null || style === void 0 ? void 0 : style.setZIndex(parseInt(feature.get('zIndex'), 10));\n }\n // if the feature is a Point and we are offline, we use default vector\n // style.\n // if the feature is a Point and has a name with a text style, we\n // create a correct text style.\n // TODO Handle GeometryCollection displaying name on the first Point\n // geometry.\n if (style && (geom instanceof Point || geom instanceof MultiPoint)) {\n let image = style.getImage();\n let text = null;\n let fill = style.getFill();\n // If the feature has name we display it on the map as Google does\n if (feature.get('name') &&\n style.getText() &&\n ((_b = style.getText()) === null || _b === void 0 ? void 0 : _b.getScale()) !== 0) {\n if (image && image.getScale() === 0) {\n // transparentCircle is used to allow selection\n image = new Circle({\n fill: new Fill({ color: [0, 0, 0, 0] }),\n radius: 1,\n stroke: new Stroke({ color: [0, 0, 0, 0] }),\n });\n }\n // We replace empty white spaces used to keep normal spaces before and after the name.\n let name = feature.get('name');\n if (/\\u200B/g.test(name)) {\n name = name.replace(/\\u200B/g, '');\n feature.set('name', name);\n }\n // For backward compatibility we translate the bold and italic textFont property to a textArray prop\n const font = feature.get('textFont') || 'normal 16px Arial';\n // Since we use rich text in mapset editor we use a text array instead,\n // it's only necessary when there is new lines in the text\n // Manage new lines\n if (name.includes('\\n')) {\n const array = [];\n const split = name.split('\\n');\n split.forEach((txt, idx) => {\n array.push(txt || '\\u200B', txt ? font : '');\n if (idx < split.length - 1) {\n array.push('\\n', '');\n }\n });\n name = array;\n }\n else {\n name = [name, font];\n }\n text = new Text({\n fill: style.getText().getFill(),\n font: `${font.replace(/bold/g, 'normal')}, Arial, sans-serif`, // We manage bold in textArray\n // rotation unsupported by KML, taken instead from custom field.\n rotation: feature.get('textRotation') || 0,\n // stroke: style.getText().getStroke(),\n scale: (_c = style.getText()) === null || _c === void 0 ? void 0 : _c.getScale(),\n // since ol 6.3.1 : https://github.com/openlayers/openlayers/pull/10613/files#diff-1883da8b57e690db7ea0c35ce53c880aR925\n // a default textstroke is added to mimic google earth.\n // it was not the case before, the stroke was always null. So to keep\n // the same behavior we don't copy the stroke style.\n // TODO : maybe we should use this functionnality in the futur.\n text: name,\n });\n if (feature.get('textArray')) {\n try {\n const textArray = JSON.parse(replace(feature.get('textArray'), /\\r?\\n/g, '\\\\n'));\n text.setText(textArray);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('Error parsing textArray', feature.get('textArray'), err);\n }\n }\n if (feature.get('textStrokeColor') && feature.get('textStrokeWidth')) {\n text.setStroke(new Stroke({\n color: feature.get('textStrokeColor'),\n width: parseFloat(feature.get('textStrokeWidth')),\n }));\n }\n if (feature.get('textAlign')) {\n text.setTextAlign(feature.get('textAlign'));\n }\n if (feature.get('textOffsetX')) {\n text.setOffsetX(parseFloat(feature.get('textOffsetX')));\n }\n if (feature.get('textOffsetY')) {\n text.setOffsetY(parseFloat(feature.get('textOffsetY')));\n }\n if (feature.get('textBackgroundFillColor')) {\n text.setBackgroundFill(new Fill({\n color: feature.get('textBackgroundFillColor'),\n }));\n }\n if (feature.get('textPadding')) {\n text.setPadding((_d = feature.get('textPadding')) === null || _d === void 0 ? void 0 : _d.split(',').map((n) => {\n return parseFloat(n);\n }));\n }\n if (image instanceof Icon) {\n applyTextStyleForIcon(image, text);\n }\n }\n if (image instanceof Icon) {\n /* Apply icon rotation if defined (by default only written as\n * tag, which is not read as rotation value by the ol KML module)\n */\n image.setRotation(parseFloat(feature.get('iconRotation')) || 0);\n if (feature.get('iconScale')) {\n image.setScale(parseFloat(feature.get('iconScale')) || 0);\n // We fix the 32px scaling introduced by OL 6.7 only if the image has a size defined.\n }\n else if (!doNotRevert32pxScaling && image.getSize()) {\n const resizeScale = scaleForSize(image.getSize());\n image.setScale(image.getScaleArray()[0] / resizeScale);\n }\n }\n fill = null;\n stroke = null;\n styles = (feat, resolution) => {\n /* Options to be used for picture scaling with map, should have at least\n * a resolution attribute (this is the map resolution at the zoom level when\n * the picture is created), can take an optional constant for further scale\n * adjustment.\n * e.g. { resolution: 0.123, defaultScale: 1 / 6 }\n */\n var _a;\n if (feat.get('pictureOptions')) {\n let pictureOptions = feat.get('pictureOptions');\n if (typeof pictureOptions === 'string') {\n pictureOptions = JSON.parse(pictureOptions);\n }\n feat.set('pictureOptions', pictureOptions);\n if (pictureOptions.resolution) {\n image === null || image === void 0 ? void 0 : image.setScale((pictureOptions.resolution / resolution) *\n ((_a = pictureOptions === null || pictureOptions === void 0 ? void 0 : pictureOptions.defaultScale) !== null && _a !== void 0 ? _a : 1));\n }\n }\n return new Style({\n fill: fill !== null && fill !== void 0 ? fill : undefined,\n image: image !== null && image !== void 0 ? image : undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: text !== null && text !== void 0 ? text : undefined,\n zIndex: style.getZIndex(),\n });\n };\n }\n // Remove image and text styles for polygons and lines\n if (!(geom instanceof Point ||\n geom instanceof MultiPoint ||\n geom instanceof GeometryCollection)) {\n styles = [\n new Style({\n fill: (_e = style === null || style === void 0 ? void 0 : style.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: undefined,\n zIndex: style === null || style === void 0 ? void 0 : style.getZIndex(),\n }),\n ];\n // Parse the fillPattern json string and store parsed object\n const fillPattern = feature.get('fillPattern');\n if (fillPattern) {\n const fillPatternOptions = JSON.parse(fillPattern);\n feature.set('fillPattern', fillPatternOptions);\n /* We set the fill pattern for polygons */\n if (!(style === null || style === void 0 ? void 0 : style.getFill())) {\n styles[0].setFill(new Fill());\n }\n const patternOrColor = (fillPatternOptions === null || fillPatternOptions === void 0 ? void 0 : fillPatternOptions.empty)\n ? [0, 0, 0, 0]\n : getPolygonPattern(fillPatternOptions.id, fillPatternOptions.color);\n (_g = (_f = styles[0]) === null || _f === void 0 ? void 0 : _f.getFill()) === null || _g === void 0 ? void 0 : _g.setColor(patternOrColor);\n }\n // Add line's icons styles\n if (feature.get('lineStartIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineStartIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor()));\n }\n if (feature.get('lineEndIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineEndIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor(), false));\n }\n }\n feature.setStyle(styles);\n }\n /**\n * Create a KML string.\n * @param {VectorLayer} layer A openlayers VectorLayer.\n * @param {} featureProjection The current projection used by the features.\n * @param {} mapResolution The current map resolution.\n */\n writeFeatures(layer, featureProjection, mapResolution) {\n var _a, _b;\n let featString;\n const exportFeatures = [];\n [...((_b = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getFeatures()) !== null && _b !== void 0 ? _b : [])]\n .sort((a, b) => {\n // The order of features must be kept.\n // We could use the useSpatialIndex = false property on the layer\n // but we prefer to sort feature by ol uid because ol uid is an integer\n // increased on each creation of a feature.\n // So we will keep the order of creation made by the the KML parser.\n // Ideally we should order by the zIndex of the style only.\n if (getUid(a) <= getUid(b)) {\n return -1;\n }\n return 1;\n })\n .forEach((feature) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;\n const clone = feature.clone();\n if (((_a = clone.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Circle') {\n // We transform circle elements into polygons\n // because circle not supported in KML spec and in ol KML parser\n const circleGeom = feature.getGeometry();\n clone.setGeometry(fromCircle(circleGeom, 100));\n clone.set(CIRCLE_GEOMETRY_CENTER, JSON.stringify(transform(circleGeom.getCenter(), featureProjection, EPSG_4326)));\n clone.set(CIRCLE_GEOMETRY_RADIUS, circleGeom.getRadius());\n }\n clone.setId(feature.getId());\n (_b = clone.getGeometry()) === null || _b === void 0 ? void 0 : _b.transform(featureProjection, EPSG_4326);\n // We remove all ExtendedData not related to style.\n Object.keys(feature.getProperties()).forEach((key) => {\n if (![\n CIRCLE_GEOMETRY_CENTER,\n CIRCLE_GEOMETRY_RADIUS,\n 'description',\n 'geometry',\n 'name',\n ].includes(key)) {\n clone.unset(key, true);\n }\n });\n let styles;\n if (feature.getStyleFunction()) {\n styles = (_c = feature.getStyleFunction()) === null || _c === void 0 ? void 0 : _c(feature, mapResolution);\n }\n else if (layer === null || layer === void 0 ? void 0 : layer.getStyleFunction()) {\n styles = (_d = layer.getStyleFunction()) === null || _d === void 0 ? void 0 : _d(feature, mapResolution);\n }\n const mainStyle = Array.isArray(styles) ? styles[0] : styles;\n const newStyle = {\n fill: (_e = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: (_f = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getImage()) !== null && _f !== void 0 ? _f : undefined,\n stroke: (_g = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getStroke()) !== null && _g !== void 0 ? _g : undefined,\n text: (_h = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getText()) !== null && _h !== void 0 ? _h : undefined,\n zIndex: (_j = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getZIndex()) !== null && _j !== void 0 ? _j : undefined,\n };\n if (newStyle.zIndex) {\n clone.set('zIndex', newStyle.zIndex);\n }\n const text = (_k = newStyle.text) === null || _k === void 0 ? void 0 : _k.getText();\n if (text) {\n let kmlText = '';\n if (Array.isArray(text)) {\n // text can be a string or an array of strings\n clone.set('textArray', JSON.stringify(text));\n const textArray = text;\n // in the KML we just add the text without the bold or italic information\n kmlText = textArray\n .map((t, idx) => {\n return idx % 2 === 0 ? t : '';\n })\n .join('')\n .replace(/\\u200B/g, '');\n }\n // We add the current text as features's name so it will be added as Placemark's name in the kml\n if (kmlText) {\n // If we see spaces at the beginning or at the end we add a empty\n // white space at the beginning and at the end.\n if (/^(\\s|\\n)|(\\n|\\s)$/g.test(kmlText)) {\n clone.set('name', `\\u200B${kmlText}\\u200B`);\n }\n else {\n clone.set('name', kmlText);\n }\n }\n }\n // Set custom properties to be converted in extendedData in KML.\n if ((_l = newStyle.text) === null || _l === void 0 ? void 0 : _l.getRotation()) {\n clone.set('textRotation', newStyle.text.getRotation());\n }\n if ((_m = newStyle.text) === null || _m === void 0 ? void 0 : _m.getFont()) {\n clone.set('textFont', newStyle.text.getFont());\n }\n if ((_o = newStyle.text) === null || _o === void 0 ? void 0 : _o.getTextAlign()) {\n clone.set('textAlign', newStyle.text.getTextAlign());\n }\n if ((_p = newStyle.text) === null || _p === void 0 ? void 0 : _p.getOffsetX()) {\n clone.set('textOffsetX', newStyle.text.getOffsetX());\n }\n if ((_q = newStyle.text) === null || _q === void 0 ? void 0 : _q.getOffsetY()) {\n clone.set('textOffsetY', newStyle.text.getOffsetY());\n }\n if ((_r = newStyle.text) === null || _r === void 0 ? void 0 : _r.getStroke()) {\n if ((_s = newStyle.text.getStroke()) === null || _s === void 0 ? void 0 : _s.getColor()) {\n clone.set('textStrokeColor', asString((_t = newStyle.text.getStroke()) === null || _t === void 0 ? void 0 : _t.getColor()));\n }\n if ((_u = newStyle.text.getStroke()) === null || _u === void 0 ? void 0 : _u.getWidth()) {\n clone.set('textStrokeWidth', (_v = newStyle.text.getStroke()) === null || _v === void 0 ? void 0 : _v.getWidth());\n }\n }\n if ((_w = newStyle.text) === null || _w === void 0 ? void 0 : _w.getBackgroundFill()) {\n clone.set('textBackgroundFillColor', asString((_x = newStyle.text.getBackgroundFill()) === null || _x === void 0 ? void 0 : _x.getColor()));\n }\n if ((_y = newStyle.text) === null || _y === void 0 ? void 0 : _y.getPadding()) {\n clone.set('textPadding', (_z = newStyle.text.getPadding()) === null || _z === void 0 ? void 0 : _z.join());\n }\n if ((_0 = newStyle.stroke) === null || _0 === void 0 ? void 0 : _0.getLineCap()) {\n clone.set('lineCap', newStyle.stroke.getLineCap());\n }\n if ((_1 = newStyle.stroke) === null || _1 === void 0 ? void 0 : _1.getLineJoin()) {\n clone.set('lineJoin', newStyle.stroke.getLineJoin());\n }\n if ((_2 = newStyle.stroke) === null || _2 === void 0 ? void 0 : _2.getLineDash()) {\n clone.set('lineDash', (_3 = newStyle.stroke.getLineDash()) === null || _3 === void 0 ? void 0 : _3.join(','));\n }\n if ((_4 = newStyle.stroke) === null || _4 === void 0 ? void 0 : _4.getLineDashOffset()) {\n clone.set('lineDashOffset', newStyle.stroke.getLineDashOffset());\n }\n if ((_5 = newStyle.stroke) === null || _5 === void 0 ? void 0 : _5.getMiterLimit()) {\n clone.set('miterLimit', newStyle.stroke.getMiterLimit());\n }\n if (newStyle.image instanceof Circle) {\n newStyle.image = undefined;\n }\n if (newStyle.image) {\n const imgSource = newStyle.image.getSrc();\n if (!/(http(s?)):\\/\\//gi.test(imgSource)) {\n // eslint-disable-next-line no-console\n console.log('Local image source not supported for KML export.' +\n 'Should use remote web server');\n }\n if (newStyle.image.getRotation()) {\n // We set the icon rotation as extended data\n clone.set('iconRotation', newStyle.image.getRotation());\n }\n if (newStyle.image.getScale()) {\n // We set the scale as extended metadata because the in the KML is related to a 32px img, since ol >= 6.10.\n clone.set('iconScale', newStyle.image.getScale());\n }\n // Set map resolution to use for icon-to-map proportional scaling\n if (feature.get('pictureOptions')) {\n clone.set('pictureOptions', JSON.stringify(feature.get('pictureOptions')));\n }\n }\n // In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc)\n if (feature.get('fillPattern')) {\n clone.set('fillPattern', JSON.stringify(feature.get('fillPattern')));\n newStyle.fill = undefined;\n }\n // maxZoom: maximum zoom level at which the feature is displayed\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n clone.set('maxZoom', maxZoom);\n }\n // minZoom: minimum zoom level at which the feature is displayed\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n clone.set('minZoom', minZoom);\n }\n // If only text is displayed we must specify an\n // image style with scale=0\n if (newStyle.text && !newStyle.image) {\n newStyle.image = new Icon({\n scale: 0,\n src: 'noimage',\n });\n }\n // In case we use line's icon .\n const extraLineStyles = (Array.isArray(styles) && styles.slice(1)) || [];\n extraLineStyles.forEach((extraLineStyle) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n if (extraLineStyle &&\n extraLineStyle.getImage() instanceof Icon &&\n extraLineStyle.getGeometry()) {\n const coord = (_b = (_a = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getGeometry()) === null || _a === void 0 ? void 0 : _a(feature)) === null || _b === void 0 ? void 0 : _b.getCoordinates();\n const startCoord = (_c = feature.getGeometry()) === null || _c === void 0 ? void 0 : _c.getFirstCoordinate();\n if ((coord === null || coord === void 0 ? void 0 : coord[0]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[0]) &&\n (coord === null || coord === void 0 ? void 0 : coord[1]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[1])) {\n clone.set('lineStartIcon', JSON.stringify({\n scale: (_d = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _d === void 0 ? void 0 : _d.getScale(),\n size: (_e = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _e === void 0 ? void 0 : _e.getSize(),\n url: (_f = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _f === void 0 ? void 0 : _f.getSrc(),\n zIndex: extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getZIndex(),\n }));\n }\n else {\n clone.set('lineEndIcon', JSON.stringify({\n scale: (_g = extraLineStyle.getImage()) === null || _g === void 0 ? void 0 : _g.getScale(),\n size: (_h = extraLineStyle.getImage()) === null || _h === void 0 ? void 0 : _h.getSize(),\n url: (_j = extraLineStyle.getImage()) === null || _j === void 0 ? void 0 : _j.getSrc(),\n zIndex: extraLineStyle.getZIndex(),\n }));\n }\n }\n });\n const olStyle = new Style(newStyle);\n clone.setStyle(olStyle);\n if (!(clone.getGeometry() instanceof Point &&\n olStyle.getText() &&\n !((_6 = olStyle.getText()) === null || _6 === void 0 ? void 0 : _6.getText()))) {\n exportFeatures.push(clone);\n }\n });\n if (exportFeatures.length > 0) {\n if (exportFeatures.length === 1) {\n // force the add of a node\n exportFeatures.push(new Feature());\n }\n featString = new KML({\n defaultStyle: [kmlStyle],\n extractStyles: true,\n }).writeFeatures(exportFeatures);\n // Remove no image hack\n featString = featString.replace(/\\s*noimage<\\/href>\\s*<\\/Icon>/g, '');\n // Remove empty placemark added to have\n // tag\n featString = featString.replace(//g, '');\n // Add KML document name\n if (layer.get('name')) {\n featString = featString.replace(//, `${layer.get('name')}`);\n }\n }\n return featString;\n }\n}\nexport default MapsetKmlFormat;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "access": "private", @@ -17539,7 +17818,7 @@ "lineNumber": 1 }, { - "__docId__": 870, + "__docId__": 880, "kind": "variable", "name": "CIRCLE_GEOMETRY_CENTER", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17560,7 +17839,7 @@ "ignore": true }, { - "__docId__": 871, + "__docId__": 881, "kind": "variable", "name": "CIRCLE_GEOMETRY_RADIUS", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17581,7 +17860,7 @@ "ignore": true }, { - "__docId__": 872, + "__docId__": 882, "kind": "variable", "name": "EPSG_4326", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17602,7 +17881,7 @@ "ignore": true }, { - "__docId__": 873, + "__docId__": 883, "kind": "variable", "name": "kmlFill", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17623,7 +17902,7 @@ "ignore": true }, { - "__docId__": 874, + "__docId__": 884, "kind": "variable", "name": "kmlStroke", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17644,7 +17923,7 @@ "ignore": true }, { - "__docId__": 875, + "__docId__": 885, "kind": "variable", "name": "kmlcircle", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17665,7 +17944,7 @@ "ignore": true }, { - "__docId__": 876, + "__docId__": 886, "kind": "variable", "name": "kmlStyle", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17686,7 +17965,7 @@ "ignore": true }, { - "__docId__": 877, + "__docId__": 887, "kind": "function", "name": "scaleForSize", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17717,7 +17996,7 @@ "ignore": true }, { - "__docId__": 878, + "__docId__": 888, "kind": "function", "name": "applyTextStyleForIcon", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17750,7 +18029,7 @@ "ignore": true }, { - "__docId__": 879, + "__docId__": 889, "kind": "function", "name": "getVertexCoord", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17799,7 +18078,7 @@ "ignore": true }, { - "__docId__": 880, + "__docId__": 890, "kind": "function", "name": "getLineIcon", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17851,7 +18130,7 @@ "ignore": true }, { - "__docId__": 881, + "__docId__": 891, "kind": "class", "name": "MapsetKmlFormat", "memberof": "build/ol/utils/MapsetKmlFormat.js", @@ -17867,7 +18146,7 @@ "interface": false }, { - "__docId__": 882, + "__docId__": 892, "kind": "constructor", "name": "constructor", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -17881,7 +18160,7 @@ "undocument": true }, { - "__docId__": 883, + "__docId__": 893, "kind": "member", "name": "writeDocumentCamera", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -17919,7 +18198,7 @@ } }, { - "__docId__": 884, + "__docId__": 894, "kind": "method", "name": "readFeatures", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -17969,7 +18248,7 @@ } }, { - "__docId__": 885, + "__docId__": 895, "kind": "method", "name": "removeDocumentCamera", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -17999,7 +18278,7 @@ } }, { - "__docId__": 886, + "__docId__": 896, "kind": "method", "name": "sanitizeFeature", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -18031,7 +18310,7 @@ "return": null }, { - "__docId__": 887, + "__docId__": 897, "kind": "method", "name": "writeFeatures", "memberof": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat", @@ -18041,7 +18320,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#writeFeatures", "access": "private", "description": "Create a KML string.", - "lineNumber": 394, + "lineNumber": 396, "params": [ { "nullable": null, @@ -18051,7 +18330,7 @@ "spread": false, "optional": false, "name": "layer", - "description": "A react-spatial VectorLayer." + "description": "A openlayers VectorLayer." }, { "nullable": null, @@ -18070,8 +18349,8 @@ ], "spread": false, "optional": false, - "name": "fixGxyAndGxh", - "description": "If the KML contains gx:w and gx:h, (ol >= 6.7), it will fix the bug introduced by https://github.com/openlayers/openlayers/pull/12695." + "name": "mapResolution", + "description": "The current map resolution." } ], "return": { @@ -18081,7 +18360,7 @@ } }, { - "__docId__": 888, + "__docId__": 898, "kind": "file", "name": "build/ol/utils/defineDeprecatedProperties.js", "content": "import debounce from 'lodash.debounce';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n // eslint-disable-next-line no-console\n console.warn(message);\n }, 1000);\n}\nconst onChildrenChange = (obj, oldValue) => {\n // Set the parent property\n (oldValue || []).forEach((child) => {\n child.set('parent', undefined);\n });\n (obj.get('children') || []).forEach((child) => {\n child.set('parent', obj);\n });\n};\n/**\n * obj function defines properties taht were used in mbt v2.\n * They are all marked als deprecated.\n * @param obj\n * @returns\n */\nconst defineDeprecatedProperties = (obj, options) => {\n if (options.properties) {\n deprecated(\"Deprecated. Don't use properties options. Pass the values directly in options object.\");\n obj.setProperties(options.properties);\n }\n // Update parent property\n obj.on('propertychange', (evt) => {\n if (evt.key === 'children') {\n onChildrenChange(evt.target, evt.oldValue);\n }\n if (evt.key === 'map') {\n const map = evt.target.get(evt.key);\n if (map) {\n (evt.target.get('children') || []).forEach((child) => {\n map.addLayer(child);\n });\n }\n else if (evt.oldValue) {\n (evt.target.get('children') || []).forEach((child) => {\n var _a;\n (_a = evt.oldValue) === null || _a === void 0 ? void 0 : _a.removeLayer(child);\n });\n }\n }\n });\n // Save options for cloning\n obj.set('options', options);\n // Force triggering the on children property change event\n obj.set('children', [...(options.children || [])]);\n Object.defineProperties(obj, {\n children: {\n /** @deprecated */\n get: () => {\n deprecated(\"Layer.children is deprecated. Use the Layer.get('children') method instead.\");\n return obj.get('children') || [];\n },\n /** @deprecated */\n set: (newValue) => {\n deprecated(\"Layer.children is deprecated. Use the Layer.set('children', children) method instead.\");\n obj.set('children', newValue || []);\n },\n },\n copyrights: {\n /** @deprecated */\n get: () => {\n deprecated('Layer.copyrights is deprecated. Get the attributions from the source object');\n return obj.get('copyrights');\n },\n /** @deprecated */\n set: (newCopyrights) => {\n deprecated('Layer.copyrights is deprecated. Set the attributions to the source object.');\n const arrValue = newCopyrights && !Array.isArray(newCopyrights)\n ? [newCopyrights]\n : newCopyrights;\n obj.set('copyrights', arrValue || []);\n },\n },\n disabled: {\n /** @deprecated */\n get() {\n deprecated(\"Layer.disabled is deprecated. Use the Layer.get('disabled') method instead.\");\n return obj.get('disabled');\n },\n /** @deprecated */\n set(newValue) {\n deprecated(\"Layer.disabled is deprecated. Use the Layer.set('disabled', newValue) method instead.\");\n obj.set('disabled', newValue);\n },\n },\n group: {\n /** @deprecated */\n get() {\n deprecated(\"Layer.group is deprecated. Use the Layer.get('group') method instead.\");\n return obj.get('group');\n },\n },\n hitTolerance: {\n /** @deprecated */\n get() {\n deprecated('Layer.hitTolerance is deprecated. Pass the hitTolerance when you request the features.');\n return obj.get('hitTolerance') || 5;\n },\n /** @deprecated */\n set(newValue) {\n deprecated('Layer.hitTolerance is deprecated. Pass the hitTolerance when you request the features.');\n obj.set('hitTolerance', newValue);\n },\n },\n key: {\n /** @deprecated */\n get() {\n deprecated('Layer.key is deprecated. Use the Layer.get(\"key\") method instead.');\n return obj.get('key') || obj.get('name');\n },\n },\n map: {\n /** @deprecated */\n get() {\n deprecated('Layer.map is deprecated. Use the Layer.get(\"map\") method instead.');\n return obj.getMapInternal();\n },\n },\n name: {\n /** @deprecated */\n get() {\n deprecated(\"Layer.name is deprecated. Use the Layer.get('name') method instead.\");\n return obj.get('name');\n },\n },\n olLayer: {\n /** @deprecated */\n get() {\n deprecated(\"Layer.olLayer is deprecated. mobility-toolbox-js/ol layers inherits now from ol/layer/Layer class. obj getter is only a redirect to the current 'this' object.\");\n return obj;\n },\n /** @deprecated */\n set() {\n deprecated('Layer.olLayer is deprecated. mobility-toolbox-js/ol layers inherits now from ol/layer/Layer class. obj setter has no effect.');\n },\n },\n olListenersKeys: {\n /** @deprecated */\n get() {\n deprecated('Layer.olListenersKeys is deprecated. Use the Layer.olEventsKeys instead.');\n //@ts-expect-error Property just there for backward compatibility\n return obj.olEventsKeys || [];\n },\n set(newValue) {\n deprecated('Layer.olListenersKeys is deprecated. Use the Layer.olEventsKeys instead.');\n //@ts-expect-error Property just there for backward compatibility\n obj.olEventsKeys = newValue;\n },\n },\n options: {\n /** @deprecated */\n get() {\n deprecated('Layer.options is deprecated. Use the Layer.get(\"options\") method instead.');\n return obj.get('options');\n },\n set(newValue) {\n deprecated('Layer.options is deprecated. Use the Layer.set(\"options\", newValue) method instead.');\n return obj.set('options', newValue);\n },\n },\n parent: {\n /** @deprecated */\n get() {\n deprecated(\"Layer.parent is deprecated. Use the Layer.get('parent') method instead.\");\n return obj.get('parent');\n },\n /** @deprecated */\n set(newValue) {\n deprecated(\"Layer.parent is deprecated. Use the Layer.set('parent', parent) method instead.\");\n obj.set('parent', newValue);\n },\n },\n properties: {\n /** @deprecated */\n get() {\n deprecated('Layer.properties is deprecated. Use the Layer.getProperties() method instead.');\n return obj.getProperties();\n },\n /** @deprecated */\n set(newValue) {\n deprecated('Layer.properties is deprecated. Use the Layer.setProperties(newValue) method instead.');\n obj.setProperties(newValue);\n },\n },\n visible: {\n /** @deprecated */\n get() {\n deprecated('Layer.visible is deprecated. Use the Layer.getVisible() method instead.');\n return obj.getVisible();\n },\n /** @deprecated */\n set(newValue) {\n deprecated('Layer.visible is deprecated. Use the Layer.setVisible(newValue) method instead.');\n obj.setVisible(newValue);\n },\n },\n });\n};\nexport default defineDeprecatedProperties;\n", @@ -18092,7 +18371,7 @@ "lineNumber": 1 }, { - "__docId__": 889, + "__docId__": 899, "kind": "function", "name": "deprecated", "memberof": "build/ol/utils/defineDeprecatedProperties.js", @@ -18112,7 +18391,7 @@ "ignore": true }, { - "__docId__": 890, + "__docId__": 900, "kind": "function", "name": "onChildrenChange", "memberof": "build/ol/utils/defineDeprecatedProperties.js", @@ -18145,7 +18424,7 @@ "ignore": true }, { - "__docId__": 891, + "__docId__": 901, "kind": "function", "name": "defineDeprecatedProperties", "memberof": "build/ol/utils/defineDeprecatedProperties.js", @@ -18184,7 +18463,7 @@ } }, { - "__docId__": 892, + "__docId__": 902, "kind": "file", "name": "build/ol/utils/getFeatureInfoAtCoordinate.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport { getUid } from 'ol';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport { getLayersAsFlatArray } from '../../common';\n/**\n * @private\n */\nconst format = new GeoJSON();\n/**\n * @private\n */\nconst getFeaturesFromWMS = (source, options, abortController) => {\n let url;\n const { coordinate, params, projection, resolution } = options;\n if (source && resolution && projection) {\n url = source.getFeatureInfoUrl(coordinate, resolution, projection, Object.assign({ info_format: 'application/json', query_layers: source.getParams().layers }, params));\n }\n // @ts-expect-error url can be undefined\n return fetch(url, { signal: abortController.signal })\n .then((resp) => {\n return resp.json();\n })\n .then((featureCollection) => {\n return format.readFeatures(featureCollection);\n })\n .catch(() => {\n return [];\n });\n};\n/**\n * @private\n */\nlet abortControllers = {};\n/**\n * Fetches feature information at a given coordinate from the provided layers.\n * It supports WMS sources and MapLibre layers and custom layer via the method `layer.getFeatureInfoAtCoordinate`.\n *\n * @param {Coordinate} coordinate - The coordinate to query for feature information.\n * @param {ol/layer/BaseLayer~BaseLayer[]} layers - The layers to query for feature information.\n * @param {number} hitTolerance - The pixel tolerance for feature selection.\n * @param {boolean} ignoreLayerMethod - If true, it ignores the `getFeatureInfoAtCoordinate` method on layers.\n * @returns {LayerGetFeatureInfoResponse[]} A promise that resolves to an array of feature information responses.\n * @private\n */\nconst getFeatureInfoAtCoordinate = (coordinate_1, layers_1, ...args_1) => __awaiter(void 0, [coordinate_1, layers_1, ...args_1], void 0, function* (coordinate, layers, hitTolerance = 5, ignoreLayerMethod = false) {\n // Kill all previous requests\n Object.values(abortControllers).forEach((abortController) => {\n abortController === null || abortController === void 0 ? void 0 : abortController.abort();\n });\n abortControllers = {};\n const flatLayers = getLayersAsFlatArray(layers);\n const promises = flatLayers.map((baseLayer) => __awaiter(void 0, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n const map = baseLayer.getMapInternal();\n const projection = (_b = (_a = map === null || map === void 0 ? void 0 : map.getView()) === null || _a === void 0 ? void 0 : _a.getProjection()) === null || _b === void 0 ? void 0 : _b.getCode();\n const emptyResponse = {\n coordinate,\n features: [],\n layer: baseLayer,\n };\n if (!projection) {\n return Promise.resolve(emptyResponse);\n }\n const layer = baseLayer;\n // For backward compatibility\n // @ts-expect-error getFeatureInfoAtCoordinate is deprecated\n if (!ignoreLayerMethod && layer.getFeatureInfoAtCoordinate) {\n // @ts-expect-error getFeatureInfoAtCoordinate is deprecated\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n return layer.getFeatureInfoAtCoordinate(coordinate);\n }\n // WMS sources\n // Here we don't use instanceof, to be able to use this function if a layer comes from 2 different ol versions.\n const source = layer === null || layer === void 0 ? void 0 : layer.getSource();\n if (source === null || source === void 0 ? void 0 : source.getFeatureInfoUrl) {\n const id = getUid(layer);\n // Abort and recreates one controller per layer\n (_c = abortControllers[id]) === null || _c === void 0 ? void 0 : _c.abort();\n abortControllers[id] = new AbortController();\n const resolution = (_d = map === null || map === void 0 ? void 0 : map.getView()) === null || _d === void 0 ? void 0 : _d.getResolution();\n const features = yield getFeaturesFromWMS(source, {\n coordinate,\n params: {\n info_format: 'application/json',\n query_layers: source.getParams().layers,\n },\n projection,\n resolution,\n }, abortControllers[id]).catch(() => {\n return [];\n });\n const featureInfoResponse = {\n coordinate,\n features,\n layer,\n };\n return Promise.resolve(featureInfoResponse);\n }\n // Other layers\n // For last resort we try the map function to get the features from the map\n const pixel = map === null || map === void 0 ? void 0 : map.getPixelFromCoordinate(coordinate);\n if (!pixel) {\n return Promise.resolve(emptyResponse);\n }\n const features = map === null || map === void 0 ? void 0 : map.getFeaturesAtPixel(pixel, {\n hitTolerance: layer.get('hitTolerance') || hitTolerance || 5,\n layerFilter: (l) => {\n return l === layer;\n },\n });\n return Promise.resolve({\n coordinate,\n features,\n layer,\n });\n }));\n return Promise.all(promises);\n});\nexport default getFeatureInfoAtCoordinate;\n", @@ -18195,7 +18474,7 @@ "lineNumber": 1 }, { - "__docId__": 893, + "__docId__": 903, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/utils/getFeatureInfoAtCoordinate.js", @@ -18216,7 +18495,7 @@ "ignore": true }, { - "__docId__": 894, + "__docId__": 904, "kind": "variable", "name": "format", "memberof": "build/ol/utils/getFeatureInfoAtCoordinate.js", @@ -18236,7 +18515,7 @@ "ignore": true }, { - "__docId__": 895, + "__docId__": 905, "kind": "function", "name": "getFeaturesFromWMS", "memberof": "build/ol/utils/getFeatureInfoAtCoordinate.js", @@ -18278,7 +18557,7 @@ "ignore": true }, { - "__docId__": 896, + "__docId__": 906, "kind": "variable", "name": "abortControllers", "memberof": "build/ol/utils/getFeatureInfoAtCoordinate.js", @@ -18298,7 +18577,7 @@ "ignore": true }, { - "__docId__": 897, + "__docId__": 907, "kind": "function", "name": "getFeatureInfoAtCoordinate", "memberof": "build/ol/utils/getFeatureInfoAtCoordinate.js", @@ -18370,7 +18649,7 @@ } }, { - "__docId__": 898, + "__docId__": 908, "kind": "file", "name": "build/ol/utils/getGraphByZoom.js", "content": "export const DEFAULT_GRAPH = 'osm';\nexport const DEFAULT_GRAPH_MAPPING = {\n 1: DEFAULT_GRAPH,\n};\n/**\n * This function return which graph to use based on the current zoom level.\n *\n * The list of graphs available for a maplibre style is available in the style metadata.\n *\n * @param {number} zoom - The current zoom level of the map.\n * @param {StyleMetadataGraphs} styleMetadata - The style metadata containing the graph mapping.\n * @returns {string} - The graph to use for the given zoom level.\n */\nexport default function getGraphByZoom(zoom = 0, styleMetadata = DEFAULT_GRAPH_MAPPING) {\n var _a;\n const breakPoints = Object.keys(styleMetadata).map((k) => {\n return parseFloat(k);\n });\n const closest = breakPoints.reverse().find((bp) => {\n return bp <= Math.floor(zoom) - 1; // - 1 due to ol zoom !== mapbox zoom\n });\n let key = closest;\n key !== null && key !== void 0 ? key : (key = Math.min(...breakPoints));\n return (_a = styleMetadata[key]) !== null && _a !== void 0 ? _a : DEFAULT_GRAPH;\n}\n", @@ -18381,7 +18660,7 @@ "lineNumber": 1 }, { - "__docId__": 899, + "__docId__": 909, "kind": "variable", "name": "DEFAULT_GRAPH", "memberof": "build/ol/utils/getGraphByZoom.js", @@ -18401,7 +18680,7 @@ } }, { - "__docId__": 900, + "__docId__": 910, "kind": "variable", "name": "DEFAULT_GRAPH_MAPPING", "memberof": "build/ol/utils/getGraphByZoom.js", @@ -18421,7 +18700,7 @@ } }, { - "__docId__": 901, + "__docId__": 911, "kind": "function", "name": "getGraphByZoom", "memberof": "build/ol/utils/getGraphByZoom.js", @@ -18473,7 +18752,7 @@ } }, { - "__docId__": 902, + "__docId__": 912, "kind": "file", "name": "build/ol/utils/getMapsetPolygonPattern.js", "content": "import { DEVICE_PIXEL_RATIO } from 'ol/has';\nconst getPolygonPattern = (patternId = 1, color = [235, 0, 0, 1]) => {\n if (patternId === 1) {\n return color;\n }\n const canvasElement = document.createElement('canvas');\n const pixelRatio = DEVICE_PIXEL_RATIO;\n canvasElement.width = 20 * pixelRatio;\n canvasElement.height = 20 * pixelRatio;\n let pattern = {};\n const ctx = canvasElement.getContext('2d');\n if (!ctx) {\n return undefined;\n }\n ctx.strokeStyle = `rgba(${color.toString()})`;\n ctx.fillStyle = `rgba(${color.toString()})`;\n ctx.lineWidth = 3;\n switch (patternId) {\n case 2:\n /* Hatched pattern */\n /* Ascending line */\n ctx.beginPath();\n ctx.moveTo(0, canvasElement.height);\n ctx.lineTo(0, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, 0);\n ctx.lineTo(canvasElement.width, 0);\n ctx.lineTo(canvasElement.width, ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, canvasElement.height);\n ctx.lineTo(ctx.lineWidth / 2, canvasElement.height);\n ctx.fill();\n ctx.closePath();\n /* Descending line */\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(0, ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, canvasElement.height);\n ctx.lineTo(canvasElement.width, canvasElement.height);\n ctx.lineTo(canvasElement.width, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, 0);\n ctx.lineTo(0, 0);\n ctx.fill();\n ctx.closePath();\n pattern = ctx.createPattern(canvasElement, 'repeat');\n pattern.canvas = canvasElement;\n break;\n case 3:\n /* Shade ascending pattern */\n /* Corner triangle */\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(0, ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, 0);\n ctx.fill();\n ctx.closePath();\n /* Ascending line */\n ctx.beginPath();\n ctx.moveTo(0, canvasElement.height);\n ctx.lineTo(0, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, 0);\n ctx.lineTo(canvasElement.width, 0);\n ctx.lineTo(canvasElement.width, ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, canvasElement.height);\n ctx.lineTo(ctx.lineWidth / 2, canvasElement.height);\n ctx.fill();\n ctx.closePath();\n /* Corner triangle */\n ctx.beginPath();\n ctx.moveTo(canvasElement.width, canvasElement.height);\n ctx.lineTo(canvasElement.width, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, canvasElement.height);\n ctx.fill();\n ctx.closePath();\n pattern = ctx.createPattern(canvasElement, 'repeat');\n pattern.canvas = canvasElement;\n break;\n case 4:\n /* Shade descending pattern */\n /* Corner triangle */\n ctx.beginPath();\n ctx.moveTo(canvasElement.width, 0);\n ctx.lineTo(canvasElement.width, ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, 0);\n ctx.fill();\n ctx.closePath();\n /* Descending line */\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(0, ctx.lineWidth / 2);\n ctx.lineTo(canvasElement.width - ctx.lineWidth / 2, canvasElement.height);\n ctx.lineTo(canvasElement.width, canvasElement.height);\n ctx.lineTo(canvasElement.width, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, 0);\n ctx.lineTo(0, 0);\n ctx.fill();\n ctx.closePath();\n /* Corner triangle */\n ctx.beginPath();\n ctx.moveTo(0, canvasElement.height);\n ctx.lineTo(0, canvasElement.height - ctx.lineWidth / 2);\n ctx.lineTo(ctx.lineWidth / 2, canvasElement.height);\n ctx.fill();\n ctx.closePath();\n pattern = ctx.createPattern(canvasElement, 'repeat');\n pattern.canvas = canvasElement;\n break;\n default:\n }\n if (patternId === 0) {\n pattern.empty = true;\n }\n pattern.id = patternId;\n pattern.color = color;\n return pattern;\n};\nexport default getPolygonPattern;\n", @@ -18484,7 +18763,7 @@ "lineNumber": 1 }, { - "__docId__": 903, + "__docId__": 913, "kind": "function", "name": "getPolygonPattern", "memberof": "build/ol/utils/getMapsetPolygonPattern.js", @@ -18531,7 +18810,7 @@ } }, { - "__docId__": 904, + "__docId__": 914, "kind": "file", "name": "build/ol/utils/index.js", "content": "export { default as getFeatureInfoAtCoordinate } from './getFeatureInfoAtCoordinate';\nexport { default as getGraphByZoom } from './getGraphByZoom';\nexport { default as getMapsetPolygonPattern } from './getMapsetPolygonPattern';\nexport { default as MapsetKmlFormat } from './MapsetKmlFormat';\n", @@ -18542,10 +18821,10 @@ "lineNumber": 1 }, { - "__docId__": 905, + "__docId__": 915, "kind": "file", "name": "build/types/moco/gql/fragment-masking.js", - "content": "export function useFragment(_documentNode, fragmentType) {\n return fragmentType;\n}\nexport function makeFragmentData(data, _fragment) {\n return data;\n}\nexport function isFragmentReady(queryNode, fragmentNode, data) {\n var _a, _b;\n const deferredFields = (_a = queryNode.__meta__) === null || _a === void 0 ? void 0 : _a.deferredFields;\n if (!deferredFields)\n return true;\n const fragDef = fragmentNode.definitions[0];\n const fragName = (_b = fragDef === null || fragDef === void 0 ? void 0 : fragDef.name) === null || _b === void 0 ? void 0 : _b.value;\n const fields = (fragName && deferredFields[fragName]) || [];\n return fields.length > 0 && fields.every(field => data && field in data);\n}\n", + "content": "export function useFragment(_documentNode, fragmentType) {\n return fragmentType;\n}\nexport function makeFragmentData(data, _fragment) {\n return data;\n}\nexport function isFragmentReady(queryNode, fragmentNode, data) {\n var _a, _b;\n const deferredFields = (_a = queryNode.__meta__) === null || _a === void 0 ? void 0 : _a.deferredFields;\n if (!deferredFields)\n return true;\n const fragDef = fragmentNode.definitions[0];\n const fragName = (_b = fragDef === null || fragDef === void 0 ? void 0 : fragDef.name) === null || _b === void 0 ? void 0 : _b.value;\n const fields = (fragName && deferredFields[fragName]) || [];\n return fields.length > 0 && fields.every((field) => data && field in data);\n}\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/types/moco/gql/fragment-masking.js", "access": "private", @@ -18553,7 +18832,7 @@ "lineNumber": 1 }, { - "__docId__": 906, + "__docId__": 916, "kind": "function", "name": "useFragment", "memberof": "build/types/moco/gql/fragment-masking.js", @@ -18589,7 +18868,7 @@ } }, { - "__docId__": 907, + "__docId__": 917, "kind": "function", "name": "makeFragmentData", "memberof": "build/types/moco/gql/fragment-masking.js", @@ -18625,7 +18904,7 @@ } }, { - "__docId__": 908, + "__docId__": 918, "kind": "function", "name": "isFragmentReady", "memberof": "build/types/moco/gql/fragment-masking.js", @@ -18667,10 +18946,10 @@ } }, { - "__docId__": 909, + "__docId__": 919, "kind": "file", "name": "build/types/moco/gql/gql.js", - "content": "const documents = [];\nexport function graphql(source) {\n var _a;\n return (_a = documents[source]) !== null && _a !== void 0 ? _a : {};\n}\n", + "content": "const documents = {};\nexport function graphql(source) {\n var _a;\n return (_a = documents[source]) !== null && _a !== void 0 ? _a : {};\n}\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/types/moco/gql/gql.js", "access": "private", @@ -18678,7 +18957,7 @@ "lineNumber": 1 }, { - "__docId__": 910, + "__docId__": 920, "kind": "variable", "name": "documents", "memberof": "build/types/moco/gql/gql.js", @@ -18693,13 +18972,13 @@ "undocument": true, "type": { "types": [ - "*[]" + "{}" ] }, "ignore": true }, { - "__docId__": 911, + "__docId__": 921, "kind": "function", "name": "graphql", "memberof": "build/types/moco/gql/gql.js", @@ -18729,7 +19008,7 @@ } }, { - "__docId__": 912, + "__docId__": 922, "kind": "file", "name": "build/types/moco/gql/graphql.js", "content": "export var MotChoices;\n(function (MotChoices) {\n MotChoices[\"Bus\"] = \"BUS\";\n MotChoices[\"Cablecar\"] = \"CABLECAR\";\n MotChoices[\"Coach\"] = \"COACH\";\n MotChoices[\"Ferry\"] = \"FERRY\";\n MotChoices[\"Funicular\"] = \"FUNICULAR\";\n MotChoices[\"Gondola\"] = \"GONDOLA\";\n MotChoices[\"Rail\"] = \"RAIL\";\n MotChoices[\"Subway\"] = \"SUBWAY\";\n MotChoices[\"Tram\"] = \"TRAM\";\n})(MotChoices || (MotChoices = {}));\nexport var OperationMessageKind;\n(function (OperationMessageKind) {\n OperationMessageKind[\"Error\"] = \"ERROR\";\n OperationMessageKind[\"Info\"] = \"INFO\";\n OperationMessageKind[\"Permission\"] = \"PERMISSION\";\n OperationMessageKind[\"Validation\"] = \"VALIDATION\";\n OperationMessageKind[\"Warning\"] = \"WARNING\";\n})(OperationMessageKind || (OperationMessageKind = {}));\nexport var Ordering;\n(function (Ordering) {\n Ordering[\"Asc\"] = \"ASC\";\n Ordering[\"AscNullsFirst\"] = \"ASC_NULLS_FIRST\";\n Ordering[\"AscNullsLast\"] = \"ASC_NULLS_LAST\";\n Ordering[\"Desc\"] = \"DESC\";\n Ordering[\"DescNullsFirst\"] = \"DESC_NULLS_FIRST\";\n Ordering[\"DescNullsLast\"] = \"DESC_NULLS_LAST\";\n})(Ordering || (Ordering = {}));\nexport var PublicationLineStyleCategoryChoices;\n(function (PublicationLineStyleCategoryChoices) {\n PublicationLineStyleCategoryChoices[\"Construction\"] = \"CONSTRUCTION\";\n PublicationLineStyleCategoryChoices[\"Disruption\"] = \"DISRUPTION\";\n PublicationLineStyleCategoryChoices[\"IndustrialAction\"] = \"INDUSTRIAL_ACTION\";\n PublicationLineStyleCategoryChoices[\"LiftFailure\"] = \"LIFT_FAILURE\";\n PublicationLineStyleCategoryChoices[\"Other\"] = \"OTHER\";\n PublicationLineStyleCategoryChoices[\"RailReplacement\"] = \"RAIL_REPLACEMENT\";\n PublicationLineStyleCategoryChoices[\"SpecialEvent\"] = \"SPECIAL_EVENT\";\n PublicationLineStyleCategoryChoices[\"VehicleFaulure\"] = \"VEHICLE_FAULURE\";\n PublicationLineStyleCategoryChoices[\"Warning\"] = \"WARNING\";\n})(PublicationLineStyleCategoryChoices || (PublicationLineStyleCategoryChoices = {}));\nexport var ServiceConditionEnumeration;\n(function (ServiceConditionEnumeration) {\n ServiceConditionEnumeration[\"AdditionalRide\"] = \"ADDITIONAL_RIDE\";\n ServiceConditionEnumeration[\"AdditionalStop\"] = \"ADDITIONAL_STOP\";\n ServiceConditionEnumeration[\"Boarding\"] = \"BOARDING\";\n ServiceConditionEnumeration[\"ChangeOfPlatform\"] = \"CHANGE_OF_PLATFORM\";\n ServiceConditionEnumeration[\"Delay\"] = \"DELAY\";\n ServiceConditionEnumeration[\"DiscontinuedOperation\"] = \"DISCONTINUED_OPERATION\";\n ServiceConditionEnumeration[\"Disruption\"] = \"DISRUPTION\";\n ServiceConditionEnumeration[\"DisturbanceRectified\"] = \"DISTURBANCE_RECTIFIED\";\n ServiceConditionEnumeration[\"Diverted\"] = \"DIVERTED\";\n ServiceConditionEnumeration[\"GoToGate\"] = \"GO_TO_GATE\";\n ServiceConditionEnumeration[\"IrregularTraffic\"] = \"IRREGULAR_TRAFFIC\";\n ServiceConditionEnumeration[\"LimitedOperation\"] = \"LIMITED_OPERATION\";\n ServiceConditionEnumeration[\"LineCancellation\"] = \"LINE_CANCELLATION\";\n ServiceConditionEnumeration[\"MajorDelays\"] = \"MAJOR_DELAYS\";\n ServiceConditionEnumeration[\"MinorDelays\"] = \"MINOR_DELAYS\";\n ServiceConditionEnumeration[\"OnTime\"] = \"ON_TIME\";\n ServiceConditionEnumeration[\"OperationTimeExtension\"] = \"OPERATION_TIME_EXTENSION\";\n ServiceConditionEnumeration[\"ReplacementRide\"] = \"REPLACEMENT_RIDE\";\n ServiceConditionEnumeration[\"StopCancelled\"] = \"STOP_CANCELLED\";\n ServiceConditionEnumeration[\"StopMoved\"] = \"STOP_MOVED\";\n ServiceConditionEnumeration[\"StopOnDemand\"] = \"STOP_ON_DEMAND\";\n ServiceConditionEnumeration[\"SubstitutedStop\"] = \"SUBSTITUTED_STOP\";\n ServiceConditionEnumeration[\"TemporarilyNonStopping\"] = \"TEMPORARILY_NON_STOPPING\";\n ServiceConditionEnumeration[\"TemporaryStopplace\"] = \"TEMPORARY_STOPPLACE\";\n ServiceConditionEnumeration[\"TrainShortened\"] = \"TRAIN_SHORTENED\";\n ServiceConditionEnumeration[\"TripCancellation\"] = \"TRIP_CANCELLATION\";\n ServiceConditionEnumeration[\"UndefinedStatus\"] = \"UNDEFINED_STATUS\";\n ServiceConditionEnumeration[\"Unknown\"] = \"UNKNOWN\";\n ServiceConditionEnumeration[\"WagonOrderChanged\"] = \"WAGON_ORDER_CHANGED\";\n})(ServiceConditionEnumeration || (ServiceConditionEnumeration = {}));\nexport var ServiceConditionGroupEnumeration;\n(function (ServiceConditionGroupEnumeration) {\n ServiceConditionGroupEnumeration[\"Changes\"] = \"CHANGES\";\n ServiceConditionGroupEnumeration[\"Disruption\"] = \"DISRUPTION\";\n ServiceConditionGroupEnumeration[\"Information\"] = \"INFORMATION\";\n})(ServiceConditionGroupEnumeration || (ServiceConditionGroupEnumeration = {}));\nexport var SeverityEnumeration;\n(function (SeverityEnumeration) {\n SeverityEnumeration[\"Normal\"] = \"NORMAL\";\n SeverityEnumeration[\"NoImpact\"] = \"NO_IMPACT\";\n SeverityEnumeration[\"Severe\"] = \"SEVERE\";\n SeverityEnumeration[\"Slight\"] = \"SLIGHT\";\n SeverityEnumeration[\"Undefined\"] = \"UNDEFINED\";\n SeverityEnumeration[\"Unknown\"] = \"UNKNOWN\";\n SeverityEnumeration[\"VerySevere\"] = \"VERY_SEVERE\";\n SeverityEnumeration[\"VerySlight\"] = \"VERY_SLIGHT\";\n})(SeverityEnumeration || (SeverityEnumeration = {}));\nexport var SeverityGroupEnumeration;\n(function (SeverityGroupEnumeration) {\n SeverityGroupEnumeration[\"High\"] = \"HIGH\";\n SeverityGroupEnumeration[\"Low\"] = \"LOW\";\n SeverityGroupEnumeration[\"Normal\"] = \"NORMAL\";\n SeverityGroupEnumeration[\"Undefined\"] = \"UNDEFINED\";\n})(SeverityGroupEnumeration || (SeverityGroupEnumeration = {}));\n", @@ -18740,10 +19019,10 @@ "lineNumber": 1 }, { - "__docId__": 913, + "__docId__": 923, "kind": "file", "name": "build/types/moco/gql/index.js", - "content": "export * from \"./fragment-masking\";\nexport * from \"./gql\";\n", + "content": "export * from './fragment-masking';\nexport * from './gql';\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/types/moco/gql/index.js", "access": "private", @@ -18760,7 +19039,7 @@ }, { "kind": "packageJSON", - "content": "{\n \"name\": \"mobility-toolbox-js\",\n \"license\": \"MIT\",\n \"description\": \"Toolbox for JavaScript applications in the domains of mobility and logistics.\",\n \"version\": \"3.4.8-beta.15\",\n \"homepage\": \"https://mobility-toolbox-js.geops.io/\",\n \"exports\": {\n \".\": \"./index.js\",\n \"./api\": \"./api/index.js\",\n \"./maplibre\": \"./maplibre/index.js\",\n \"./ol\": \"./ol/index.js\",\n \"./types\": \"./types/index.d.ts\"\n },\n \"dependencies\": {\n \"@geoblocks/ol-maplibre-layer\": \"^1.0.3\",\n \"@geops/geops-ui\": \"0.3.6\",\n \"@turf/helpers\": \"7.2.0\",\n \"@turf/transform-rotate\": \"7.2.0\",\n \"lodash.debounce\": \"4.0.8\",\n \"lodash.throttle\": \"4.1.1\",\n \"uuid\": \"13.0.0\"\n },\n \"peerDependencies\": {\n \"maplibre-gl\": \">=4\",\n \"ol\": \">=9\"\n },\n \"devDependencies\": {\n \"@babel/preset-env\": \"^7.28.5\",\n \"@babel/preset-typescript\": \"^7.28.5\",\n \"@commitlint/cli\": \"20.1.0\",\n \"@commitlint/config-conventional\": \"20.0.0\",\n \"@geops/eslint-config-react\": \"1.6.0-beta.1\",\n \"@graphql-codegen/cli\": \"^6.0.1\",\n \"@graphql-codegen/typescript\": \"^5.0.2\",\n \"@graphql-codegen/typescript-operations\": \"^5.0.2\",\n \"@types/geojson\": \"7946.0.16\",\n \"@types/lodash\": \"^4.17.20\",\n \"@types/lodash.debounce\": \"4.0.9\",\n \"@types/lodash.throttle\": \"4.1.9\",\n \"@types/mapbox-gl\": \"3.4.1\",\n \"@types/offscreencanvas\": \"2019.7.3\",\n \"@types/topojson\": \"3.2.6\",\n \"@types/uuid\": \"11.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"8.46.3\",\n \"@typescript-eslint/parser\": \"8.46.3\",\n \"cypress\": \"15.6.0\",\n \"esbuild\": \"0.25.12\",\n \"esdoc\": \"1.1.0\",\n \"esdoc-ecmascript-proposal-plugin\": \"1.0.0\",\n \"esdoc-publish-html-plugin\": \"1.1.2\",\n \"esdoc-standard-plugin\": \"1.0.0\",\n \"esdoc-typescript-plugin\": \"1.0.1\",\n \"eslint\": \"9.39.1\",\n \"fixpack\": \"4.0.0\",\n \"graphql\": \"^16.12.0\",\n \"husky\": \"9.1.7\",\n \"is-ci\": \"4.1.0\",\n \"jest\": \"30.2.0\",\n \"jest-canvas-mock\": \"2.5.2\",\n \"jest-environment-jsdom\": \"30.2.0\",\n \"jest-fetch-mock\": \"3.0.3\",\n \"jest-serializer-html\": \"7.1.0\",\n \"jest-transformer-svg\": \"2.1.0\",\n \"jest-websocket-mock\": \"2.5.0\",\n \"lint-staged\": \"16.2.6\",\n \"maplibre-gl\": \"5.10.0\",\n \"mock-socket\": \"9.3.1\",\n \"next\": \"15.5.6\",\n \"next-transpile-modules\": \"10.0.1\",\n \"ol\": \"10.6.0\",\n \"openapi-typescript\": \"5\",\n \"prettier\": \"3.6.2\",\n \"raw-loader\": \"4.0.2\",\n \"sort-json\": \"2.0.1\",\n \"standard-version\": \"9.5.0\",\n \"start-server-and-test\": \"2.1.2\",\n \"stylelint\": \"16.25.0\",\n \"stylelint-config-recommended-scss\": \"16.0.2\",\n \"stylelint-config-standard\": \"39.0.1\",\n \"stylelint-scss\": \"6.12.1\",\n \"ts-jest\": \"^29.4.5\",\n \"typescript\": \"5.9.3\",\n \"vite\": \"^7.2.1\"\n },\n \"scripts\": {\n \"apidoc\": \"esdoc && cp apidoc/index.json doc/src/components/Esdoc\",\n \"build\": \"yarn build:tsc && yarn esbuild:iife\",\n \"build:tsc\": \"rm -rf build && yarn tsc && cp package.json build/ && cp README.md build/ && cp LICENSE build/ && cp -R src/types build/ && find build -type f -name '*.test.*' -delete\",\n \"clean\": \"rm -rf .next && rm -rf doc/.next\",\n \"coverage\": \"yarn test --watchAll=false --coverage --coverageDirectory=coverage\",\n \"cy:open\": \"cypress open\",\n \"cy:test\": \"start-server-and-test dev http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:chrome\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:edge\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser edge'\",\n \"cy:test:firefox\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser firefox'\",\n \"dev\": \"vite\",\n \"doc\": \"yarn build && yarn apidoc && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn build\",\n \"doc:dev\": \"yarn clean && yarn build && yarn apidoc && yarn doc:dev:examples\",\n \"doc:dev:examples\": \"yarn clean && yarn build && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn dev\",\n \"esbuild\": \"yarn esbuild:all && yarn esbuild:iife\",\n \"esbuild:all\": \"esbuild src/index.js src/**/*.js src/**/*.ts src/**/**/*.js src/**/**/*.ts --target=chrome100 --outdir=build/ --loader:.js=jsx\",\n \"esbuild:iife\": \"yarn esbuild:iife:unminify && yarn esbuild:iife:minify\",\n \"esbuild:iife:base\": \"esbuild src/iife.js --bundle --sourcemap --target=chrome100\",\n \"esbuild:iife:minify\": \"yarn esbuild:iife:base --minify --outfile=build/mbt.min.js\",\n \"esbuild:iife:unminify\": \"yarn esbuild:iife:base --outfile=build/mbt.js\",\n \"format\": \"prettier --write 'src/**/*.js' 'src/**/*.ts' 'src/**/*.test.js' && eslint src/**/*.js src/**/*.test.js src/**/*.ts --fix && stylelint 'src/**/*.css' 'src/**/*.scss' --fix --allow-empty-input\",\n \"lint\": \"eslint src/**/*.js src/**/*.ts && stylelint src/**/*.css src/**/*.scss --allow-empty-input\",\n \"prepare\": \"is-ci || husky\",\n \"publish:beta\": \"HUSKY=0 yarn release -- --prerelease beta --skip.changelog && yarn run build && cd build && HUSKY=0 yarn publish --tag beta && git push origin HEAD && git push --tags \",\n \"publish:beta:dryrun\": \"yarn release -- --prerelease beta --dry-run --skip.changelog\",\n \"publish:public\": \"yarn release && yarn run build && cd build && HUSKY=0 yarn publish && git push origin HEAD && git push --tags \",\n \"publish:public:dryrun\": \"yarn release --dry-run\",\n \"release\": \"standard-version\",\n \"start\": \"yarn doc && cd doc && yarn start\",\n \"start:examples\": \"cd doc && yarn build && yarn start\",\n \"test\": \"TZ='UTC' jest \",\n \"test:watch\": \"yarn test --watchAll\",\n \"tsc\": \"tsc\",\n \"types:backend\": \" yarn types:stops && yarn types:routing && yarn types:moco\",\n \"types:moco\": \"openapi-typescript https://moco.geops.io/api/schema/?format=json --output src/types/moco.d.ts && graphql-codegen --config graphql-codegen-moco.ts\",\n \"types:routing\": \"openapi-typescript https://developer.geops.io/swagger/routing.json --output src/types/routing.d.ts\",\n \"types:stops\": \"openapi-typescript https://developer.geops.io/swagger/stops.json --output src/types/stops.d.ts\",\n \"up\": \"yarn upgrade-interactive --latest\"\n },\n \"browserslist\": [\n \">0.2%\",\n \"not dead\",\n \"not op_mini all\",\n \"not ie <= 11\",\n \"not android < 5\"\n ],\n \"keywords\": [\n \"mobility\",\n \"realtime\",\n \"routing\",\n \"stops\",\n \"toolbox\"\n ],\n \"packageManager\": \"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/geops/mobility-toolbox-js\"\n },\n \"sideEffects\": false\n}\n", + "content": "{\n \"name\": \"mobility-toolbox-js\",\n \"license\": \"MIT\",\n \"description\": \"Toolbox for JavaScript applications in the domains of mobility and logistics.\",\n \"version\": \"3.6.7\",\n \"homepage\": \"https://mobility-toolbox-js.geops.io/\",\n \"exports\": {\n \".\": \"./index.js\",\n \"./api\": \"./api/index.js\",\n \"./maplibre\": \"./maplibre/index.js\",\n \"./ol\": \"./ol/index.js\",\n \"./types\": \"./types/index.d.ts\"\n },\n \"dependencies\": {\n \"@geoblocks/ol-maplibre-layer\": \"^1.0.3\",\n \"@turf/helpers\": \"7.3.2\",\n \"@turf/transform-rotate\": \"7.3.2\",\n \"lodash.debounce\": \"4.0.8\",\n \"lodash.throttle\": \"4.1.1\",\n \"uuid\": \"13.0.0\"\n },\n \"peerDependencies\": {\n \"maplibre-gl\": \">=4\",\n \"ol\": \">=9\"\n },\n \"devDependencies\": {\n \"@babel/preset-env\": \"^7.28.6\",\n \"@babel/preset-typescript\": \"^7.28.5\",\n \"@commitlint/cli\": \"20.3.1\",\n \"@commitlint/config-conventional\": \"20.3.1\",\n \"@geops/eslint-config-react\": \"1.6.0-beta.1\",\n \"@graphql-codegen/cli\": \"^6.1.1\",\n \"@graphql-codegen/typescript\": \"^5.0.7\",\n \"@graphql-codegen/typescript-operations\": \"^5.0.7\",\n \"@types/geojson\": \"7946.0.16\",\n \"@types/lodash\": \"^4.17.23\",\n \"@types/lodash.debounce\": \"4.0.9\",\n \"@types/lodash.throttle\": \"4.1.9\",\n \"@types/mapbox-gl\": \"3.4.1\",\n \"@types/offscreencanvas\": \"2019.7.3\",\n \"@types/topojson\": \"3.2.6\",\n \"@types/uuid\": \"11.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"8.53.1\",\n \"@typescript-eslint/parser\": \"8.53.1\",\n \"cypress\": \"15.8.1\",\n \"esbuild\": \"0.27.2\",\n \"esdoc\": \"1.1.0\",\n \"esdoc-ecmascript-proposal-plugin\": \"1.0.0\",\n \"esdoc-publish-html-plugin\": \"1.1.2\",\n \"esdoc-standard-plugin\": \"1.0.0\",\n \"esdoc-typescript-plugin\": \"1.0.1\",\n \"eslint\": \"9.39.2\",\n \"fixpack\": \"4.0.0\",\n \"graphql\": \"^16.12.0\",\n \"husky\": \"9.1.7\",\n \"is-ci\": \"4.1.0\",\n \"jest\": \"30.2.0\",\n \"jest-canvas-mock\": \"2.5.2\",\n \"jest-environment-jsdom\": \"30.2.0\",\n \"jest-fetch-mock\": \"3.0.3\",\n \"jest-serializer-html\": \"7.1.0\",\n \"jest-transformer-svg\": \"2.1.0\",\n \"jest-websocket-mock\": \"2.5.0\",\n \"lint-staged\": \"16.2.7\",\n \"maplibre-gl\": \"5.16.0\",\n \"mock-socket\": \"9.3.1\",\n \"next\": \"15.5.6\",\n \"next-transpile-modules\": \"10.0.1\",\n \"ol\": \"10.7.0\",\n \"openapi-typescript\": \"5\",\n \"prettier\": \"3.8.1\",\n \"raw-loader\": \"4.0.2\",\n \"sort-json\": \"2.0.1\",\n \"standard-version\": \"9.5.0\",\n \"start-server-and-test\": \"2.1.3\",\n \"stylelint\": \"17.0.0\",\n \"stylelint-config-recommended-scss\": \"17.0.0\",\n \"stylelint-config-standard\": \"40.0.0\",\n \"stylelint-scss\": \"7.0.0\",\n \"ts-jest\": \"^29.4.6\",\n \"typescript\": \"5.9.3\",\n \"vite\": \"^7.3.1\"\n },\n \"scripts\": {\n \"apidoc\": \"esdoc && cp apidoc/index.json doc/src/components/Esdoc\",\n \"build\": \"yarn build:tsc && yarn esbuild:iife\",\n \"build:tsc\": \"rm -rf build && yarn tsc && cp package.json build/ && cp README.md build/ && cp LICENSE build/ && cp -R src/types build/ && find build -type f -name '*.test.*' -delete\",\n \"clean\": \"rm -rf .next && rm -rf doc/.next\",\n \"coverage\": \"yarn test --watchAll=false --coverage --coverageDirectory=coverage\",\n \"cy:open\": \"cypress open\",\n \"cy:test\": \"start-server-and-test dev http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:chrome\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:edge\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser edge'\",\n \"cy:test:firefox\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser firefox'\",\n \"dev\": \"vite\",\n \"doc\": \"yarn build && yarn apidoc && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn build\",\n \"doc:dev\": \"yarn clean && yarn build && yarn apidoc && yarn doc:dev:examples\",\n \"doc:dev:examples\": \"yarn clean && yarn build && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn dev\",\n \"esbuild\": \"yarn esbuild:all && yarn esbuild:iife\",\n \"esbuild:all\": \"esbuild src/index.js src/**/*.js src/**/*.ts src/**/**/*.js src/**/**/*.ts --target=chrome100 --outdir=build/ --loader:.js=jsx\",\n \"esbuild:iife\": \"yarn esbuild:iife:unminify && yarn esbuild:iife:minify\",\n \"esbuild:iife:base\": \"esbuild src/iife.js --bundle --sourcemap --target=chrome100\",\n \"esbuild:iife:minify\": \"yarn esbuild:iife:base --minify --outfile=build/mbt.min.js\",\n \"esbuild:iife:unminify\": \"yarn esbuild:iife:base --outfile=build/mbt.js\",\n \"format\": \"prettier --write 'src/**/*.js' 'src/**/*.ts' 'src/**/*.test.js' && eslint src/**/*.js src/**/*.test.js src/**/*.ts --fix && stylelint 'src/**/*.css' 'src/**/*.scss' --fix --allow-empty-input\",\n \"lint\": \"eslint src/**/*.js src/**/*.ts && stylelint src/**/*.css src/**/*.scss --allow-empty-input\",\n \"publish:beta\": \"HUSKY=0 yarn release -- --prerelease beta --skip.changelog && yarn run build && cd build && HUSKY=0 yarn publish --tag beta && git push origin HEAD && git push --tags \",\n \"publish:beta:dryrun\": \"yarn release -- --prerelease beta --dry-run --skip.changelog\",\n \"publish:public\": \"yarn release && yarn run build && cd build && HUSKY=0 yarn publish && git push origin HEAD && git push --tags \",\n \"publish:public:dryrun\": \"yarn release --dry-run\",\n \"release\": \"standard-version\",\n \"start\": \"yarn doc && cd doc && yarn start\",\n \"start:examples\": \"cd doc && yarn build && yarn start\",\n \"test\": \"TZ='UTC' jest \",\n \"test:watch\": \"yarn test --watchAll\",\n \"tsc\": \"tsc\",\n \"types:backend\": \" yarn types:stops && yarn types:routing && yarn types:moco && yarn types:realtime && yarn format\",\n \"types:moco\": \"openapi-typescript https://moco.geops.io/api/schema/?format=json --output src/types/moco.d.ts && graphql-codegen --config graphql-codegen-moco.ts\",\n \"types:realtime\": \"openapi-typescript https://tralis-tracker-api.geops.io/api/openapi.json --output src/types/realtimerest.d.ts\",\n \"types:routing\": \"openapi-typescript https://developer.geops.io/swagger/routing.json --output src/types/routing.d.ts\",\n \"types:stops\": \"openapi-typescript https://developer.geops.io/swagger/stops.json --output src/types/stops.d.ts\",\n \"up\": \"yarn upgrade-interactive --latest\"\n },\n \"browserslist\": [\n \">0.2%\",\n \"not dead\",\n \"not op_mini all\",\n \"not ie <= 11\",\n \"not android < 5\"\n ],\n \"keywords\": [\n \"mobility\",\n \"realtime\",\n \"routing\",\n \"stops\",\n \"toolbox\"\n ],\n \"packageManager\": \"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/geops/mobility-toolbox-js\"\n },\n \"sideEffects\": false\n}\n", "longname": "/home/olivier/GIT/mobility-toolbox-js/package.json", "name": "package.json", "static": true, @@ -18909,7 +19188,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#mapLibreMap", "access": "public", "description": "The Maplibre map object. Readonly.", - "lineNumber": 49, + "lineNumber": 51, "type": { "types": [ "maplibregl.Map" @@ -18924,7 +19203,7 @@ "longname": "build/ol/layers/MaplibreLayer.js~MaplibreLayer#style", "access": "public", "description": "The [geOps Maps API](https://developer.geops.io/apis/maps) style.", - "lineNumber": 49, + "lineNumber": 51, "type": { "types": [ "string" diff --git a/doc/yarn.lock b/doc/yarn.lock index 3763549e..02fda624 100644 --- a/doc/yarn.lock +++ b/doc/yarn.lock @@ -289,13 +289,6 @@ resolved "https://registry.yarnpkg.com/@geoblocks/ol-maplibre-layer/-/ol-maplibre-layer-1.0.3.tgz#996345296b0b2d1b8ad06b78424caa5b69296b6f" integrity sha512-NKr7iqIezw5XWKy6Dw32mYdo3tcNXIOb+wI/nguhiqKxntFvvpiQAsv38lM9xpTkqlDRd1JKLfAHaqtc7jy4Ug== -"@geops/geops-ui@0.3.6": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@geops/geops-ui/-/geops-ui-0.3.6.tgz#f5e3f661d0db24f279a5ef51c62b3410b98647a7" - integrity sha512-xj6U73NoXxfyne9yE13zxP5COfp3V9g/JL/LIB/NJkatWsrqzsCfWJoqwKyw7M4gZ/gPTxuzf7Az2epWyzxVJQ== - dependencies: - prop-types "^15.7.2" - "@geops/geops-ui@^0.3.7": version "0.3.7" resolved "https://registry.yarnpkg.com/@geops/geops-ui/-/geops-ui-0.3.7.tgz#82cc597332e49bcb287b4804a80bb618cb58248c" @@ -863,93 +856,94 @@ dependencies: tslib "^2.8.0" -"@turf/centroid@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/centroid/-/centroid-7.3.1.tgz#8cf5b1793157fa95e683fd0643d0fbd8a6bec4dd" - integrity sha512-hRnsDdVBH4pX9mAjYympb2q5W8TCMUMNEjcRrAF7HTCyjIuRmjJf8vUtlzf7TTn9RXbsvPc1vtm3kLw20Jm8DQ== +"@turf/centroid@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/centroid/-/centroid-7.3.2.tgz#d8a01f98626d63557363afce3cb59edaa73dd39a" + integrity sha512-zWlX/t7goUx+FqCYzyscO7muXPSADb5nTGXWAbRR51P3Zsdx24P5tJshJhrHwIb3OR9a+YE4ig568Clex6tc2g== dependencies: - "@turf/helpers" "7.3.1" - "@turf/meta" "7.3.1" + "@turf/helpers" "7.3.2" + "@turf/meta" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/clone@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/clone/-/clone-7.3.1.tgz#beed14b581937060095e742c248029076b787f1f" - integrity sha512-r7xDOfw9ohA7PhZW+8X9RMsO4szB4YqkhEROaELJyLtQ1bo8VNFtndpZdE6YHQpD7Pjlvlb6i99q8w1QLisEPg== +"@turf/clone@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/clone/-/clone-7.3.2.tgz#a77acc251689c835152dd2dba20d10fcefa84629" + integrity sha512-ET6EqfEbDq4EsvyhC5Fwyg5hkkRGcHUM7v63sqbLtz4bY2cSAZ1gGcgmBQdztSXQyKqSsFkIXpp1amfrLATNOQ== dependencies: - "@turf/helpers" "7.3.1" + "@turf/helpers" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/helpers@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-7.3.1.tgz#2f0e666ecdefbf75d0df1b94ea1f5ccc6e4abc5b" - integrity sha512-zkL34JVhi5XhsuMEO0MUTIIFEJ8yiW1InMu4hu/oRqamlY4mMoZql0viEmH6Dafh/p+zOl8OYvMJ3Vm3rFshgg== +"@turf/helpers@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-7.3.2.tgz#deb2a1a5bb84d8db78571bc89ca8b75586e31ed7" + integrity sha512-5HFN42rgWjSobdTMxbuq+ZdXPcqp1IbMgFYULTLCplEQM3dXhsyRFe7DCss4Eiw12iW3q6Z5UeTNVfITsE5lgA== dependencies: "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/invariant@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-7.3.1.tgz#9b0bb8f74af870f0b10a2e9285e62f4983f99ac2" - integrity sha512-IdZJfDjIDCLH+Gu2yLFoSM7H23sdetIo5t4ET1/25X8gi3GE2XSqbZwaGjuZgNh02nisBewLqNiJs2bo+hrqZA== +"@turf/invariant@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-7.3.2.tgz#490ea975572a7dfebed5ce0dd20a7dd8d0517602" + integrity sha512-brGmL1EFhZH/YNXhq6S+8sPWBEnmvEyxMWJO8bUNOFZyWHYiRTwxQHZM+An1blkbQ77PiEzsdNAspZqE1j7YKA== dependencies: - "@turf/helpers" "7.3.1" + "@turf/helpers" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/meta@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-7.3.1.tgz#af2076f6388ea87585190c99b8530cbb05e38944" - integrity sha512-NWsfOE5RVtWpLQNkfOF/RrYvLRPwwruxhZUV0UFIzHqfiRJ50aO9Y6uLY4bwCUe2TumLJQSR4yaoA72Rmr2mnQ== +"@turf/meta@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-7.3.2.tgz#e31320bf0602692664291b827eb6eb7344430a45" + integrity sha512-FIcIY+ZsAe9QV4fHciTXeuRz2TKIVaEjivkl4vMFCibdj7FUkWDofqOncbIre1xPrgktQeh20ZrmD+p0kf3n4Q== dependencies: - "@turf/helpers" "7.3.1" + "@turf/helpers" "7.3.2" "@types/geojson" "^7946.0.10" + tslib "^2.8.1" -"@turf/rhumb-bearing@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/rhumb-bearing/-/rhumb-bearing-7.3.1.tgz#ba721bcba6ab5a8244d804a7decc61486b6045dd" - integrity sha512-GA/EUSOMapLp6qK5kOX+PkFg2MMUHzUSm/jVezv6Fted0dAlCgXHOrKgLm0tN8PqbH7Oj9xQhv9+3/1ze7W8YA== +"@turf/rhumb-bearing@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/rhumb-bearing/-/rhumb-bearing-7.3.2.tgz#4d7b035f103c113e245a5fce6a981ea79ab7c2c4" + integrity sha512-RoiZ9ZihgjKI8G2QUmikxEe9Z7+yL1m+1notOQ2eEMZ3+9rlhxKkLAfTZyioSlTsV3ovQmr2k30TKGL4CMQzWw== dependencies: - "@turf/helpers" "7.3.1" - "@turf/invariant" "7.3.1" + "@turf/helpers" "7.3.2" + "@turf/invariant" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/rhumb-destination@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/rhumb-destination/-/rhumb-destination-7.3.1.tgz#632af13024818c918a6d87d3a06f14b6454d4b44" - integrity sha512-HjtAFr5DTISUn9b4oaZpX79tYl72r4EyAj40HKwjQeV6KkwIe5/h4zryOSEpnvAK2Gnkmu1GxYeTGfM5z3J9JA== +"@turf/rhumb-destination@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/rhumb-destination/-/rhumb-destination-7.3.2.tgz#16325497efcff94a4ba3d44b9b66340a1a486d88" + integrity sha512-i43WHFzugO6D8aBk/jli0XL3GGI21JmPJRd1odz4HSxfbjjZe+WOf+amwouGFuDCkE73/odXn5ohx4iA1F3MSQ== dependencies: - "@turf/helpers" "7.3.1" - "@turf/invariant" "7.3.1" + "@turf/helpers" "7.3.2" + "@turf/invariant" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/rhumb-distance@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/rhumb-distance/-/rhumb-distance-7.3.1.tgz#8d070df1a881c97f29306bf679021da1d617d0eb" - integrity sha512-9ZvXU0ii2aywdphLhiawl3uxMEHucMmXCBiRj3WhmssTY9CZkFii9iImbJEqz5glxh6/gzXDcz1CCFQUdNP2xA== +"@turf/rhumb-distance@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/rhumb-distance/-/rhumb-distance-7.3.2.tgz#84a3721d1e14cf02ef0175716a53cfd18b14787b" + integrity sha512-8ZZ8EGeZREnWCk5a6pNFazSBxIqRCdPLAGPukCTpJONN3kke4Y3ftw7/Cd4rjX6tnkE2qT/I+vo67weqSuC5pg== dependencies: - "@turf/helpers" "7.3.1" - "@turf/invariant" "7.3.1" + "@turf/helpers" "7.3.2" + "@turf/invariant" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" -"@turf/transform-rotate@7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@turf/transform-rotate/-/transform-rotate-7.3.1.tgz#832f8abc9d39b1c69f16d1065946938fe025fa58" - integrity sha512-KAYebOkk7IT2j7S8M+ZxDAmyqeni9ZZGU9ouD6mvd/hTpDOlGG+ORRmg312RxG0NiThzCHLyeG1Nea1nEud6bg== - dependencies: - "@turf/centroid" "7.3.1" - "@turf/clone" "7.3.1" - "@turf/helpers" "7.3.1" - "@turf/invariant" "7.3.1" - "@turf/meta" "7.3.1" - "@turf/rhumb-bearing" "7.3.1" - "@turf/rhumb-destination" "7.3.1" - "@turf/rhumb-distance" "7.3.1" +"@turf/transform-rotate@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@turf/transform-rotate/-/transform-rotate-7.3.2.tgz#03f032beaf104cbd00cee2667f4a5c9eecf45949" + integrity sha512-e50qc5JG/lryhYa1/z6KBS0EIiHUXZte+3ZHJXlNq4HjpoY6M0/sAZprRkRqmNbo4UN2PS7HNRKnDSNA6swofA== + dependencies: + "@turf/centroid" "7.3.2" + "@turf/clone" "7.3.2" + "@turf/helpers" "7.3.2" + "@turf/invariant" "7.3.2" + "@turf/meta" "7.3.2" + "@turf/rhumb-bearing" "7.3.2" + "@turf/rhumb-destination" "7.3.2" + "@turf/rhumb-distance" "7.3.2" "@types/geojson" "^7946.0.10" tslib "^2.8.1" @@ -4407,12 +4401,11 @@ mkdirp@^0.5.1: minimist "^1.2.6" mobility-toolbox-js@./../build: - version "3.6.1-beta.2" + version "3.6.7" dependencies: "@geoblocks/ol-maplibre-layer" "^1.0.3" - "@geops/geops-ui" "0.3.6" - "@turf/helpers" "7.3.1" - "@turf/transform-rotate" "7.3.1" + "@turf/helpers" "7.3.2" + "@turf/transform-rotate" "7.3.2" lodash.debounce "4.0.8" lodash.throttle "4.1.1" uuid "13.0.0" diff --git a/src/common/utils/renderTrajectories.ts b/src/common/utils/renderTrajectories.ts index 4f1e0888..b3f02a92 100644 --- a/src/common/utils/renderTrajectories.ts +++ b/src/common/utils/renderTrajectories.ts @@ -169,6 +169,12 @@ const renderTrajectories = ( cacheNbTrainAtPixel[key] = 1; cacheDistanceOffset[key] = 40 * resolution; } else { + // console.log( + // 'Collision detected for train id', + // id, + // 'at pixel', + // roundedPX, + // ); // if (!hoverVehicleId) { px[0] += 40 * cacheNbTrainAtPixel[key]; // // } From 41c42768ed16159adb1cc84bc7ff4975bb7a1540 Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Fri, 27 Feb 2026 16:48:28 +0100 Subject: [PATCH 3/6] fix: 5 at 5 pixel --- src/common/utils/renderTrajectories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/utils/renderTrajectories.ts b/src/common/utils/renderTrajectories.ts index b3f02a92..dc9ced85 100644 --- a/src/common/utils/renderTrajectories.ts +++ b/src/common/utils/renderTrajectories.ts @@ -161,7 +161,7 @@ const renderTrajectories = ( if (resolution < 1) { const roundedPX = px.map((p) => { - return Math.round(p); + return Math.round(p / 5) * 5; }); const key = `${roundedPX.toString()}`; if (!cachePixel[key]) { From ff9b5318886c585015a98cd001e8788ee07e9bad Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Fri, 27 Feb 2026 16:50:13 +0100 Subject: [PATCH 4/6] fix: remove log --- dev.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev.js b/dev.js index 5e3252dd..ce395fea 100644 --- a/dev.js +++ b/dev.js @@ -89,7 +89,9 @@ map.on('pointermove', (evt) => { // realtimeLayer.hoverVehicleId = feature?.get('train_id'); realtimeLayer.highlight(feature); - console.log(feature?.getProperties()); + if (feature) { + console.log(feature?.getProperties()); + } map.getTargetElement().style.cursor = feature ? 'pointer' : ''; }); From ca911ff970ee48e807baad530c6e700605f0b287 Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Tue, 17 Mar 2026 11:01:16 +0100 Subject: [PATCH 5/6] fix: add a new vector layer to display multiple trins on hover --- dev.js | 140 ++- doc/src/components/Esdoc/index.json | 1290 ++++++++++++------------ doc/yarn.lock | 2 +- src/common/styles/realtimeStyle.ts | 41 +- src/common/utils/RealtimeEngine.ts | 33 +- src/common/utils/renderTrajectories.ts | 92 +- src/ol/layers/RealtimeLayer.ts | 88 +- src/types/common.d.ts | 4 +- 8 files changed, 952 insertions(+), 738 deletions(-) diff --git a/dev.js b/dev.js index 615d3dd7..0d847b0d 100644 --- a/dev.js +++ b/dev.js @@ -15,6 +15,10 @@ import { } from './build/ol'; import 'ol/ol.css'; import { toLonLat, transformExtent } from 'ol/proj'; +import { Icon, Style, Circle, Fill, Stroke } from 'ol/style'; +import { Point } from 'ol/geom'; +import { radiansToDegrees } from '@turf/helpers'; +import { NEXT_CACHE_TAG_MAX_LENGTH } from 'next/dist/lib/constants'; window.apiKey = '5cc87b12d7c5370001c1d6554840ecb89d2743d2b0aad0588b8ba7eb'; @@ -48,12 +52,106 @@ const realtimeLayer = new RealtimeLayer({ }, // style: realtimeByMotStyle, // tenant: 'sbm', - // tenant: 'trenord', + tenant: 'trenord', // bboxParameters: { // line_tags: 'RVF', // }, }); +const getPointOnLine = (angleDeg, distance, originX = 0, originY = 0) => { + // 1. Convert angle from degrees to radians + const angleRad = (angleDeg + 90) * (Math.PI / 180); + + // 2. Calculate the offset from the origin using Cosine (X) and Sine (Y) + const deltaX = Math.cos(angleRad) * distance; + const deltaY = Math.sin(angleRad) * distance; + + // 3. Add the offset to the origin coordinates + const x = originX + deltaX; + const y = originY - deltaY; + + return [ + Math.floor(x), // Rounded for better readability + Math.floor(y), + ]; +}; + +const cacheFirtsAnchor = []; +let cacheFirstRotation = 0; +const realtimeLayerHover = new VectorLayer({ + source: new VectorSource(), + style: (feature) => { + // const canvas = + // realtimeLayer.engine.renderState?.styleCacheByTrajectoryId?.[ + // feature.get('train_id') + // ]; + const canvas = realtimeLayer.style( + { + type: 'Feature', + properties: feature.getProperties(), + geometry: { + type: 'LineString', + coordinates: feature.getGeometry()?.getCoordinates() || [], + }, + }, + realtimeLayer.renderedViewState, + { + ...realtimeLayer.styleOptions, + showDelayText: false, + showDelayBg: true, + hoverVehicleId: feature.get('train_id'), + hoverVehicleIds: [feature.get('train_id')], + }, + ); + const index = realtimeLayer.hoverVehicleIds?.indexOf( + feature.get('train_id'), + ); + if (index === 0) { + cacheFirstRotation = feature.get('rotation') || 0; + } + + if (canvas) { + return new Style({ + image: new Icon({ + img: canvas, + imgSize: [canvas.width, canvas.height], + scale: 1, + anchor: getPointOnLine( + radiansToDegrees(cacheFirstRotation), + (index * canvas.height) / 2, + canvas.width / 2, + canvas.height / 2, + ), + anchorXUnits: 'pixels', + anchorYUnits: 'pixels', + }), + geometry: (feature) => { + const coords = feature.get('coordinate'); + if (coords) { + return new Point(coords); + } + return feature.getGeometry(); + }, + }); + } + return new Style({ + image: new Circle({ + radius: 50, + fill: new Fill({ color: 'rgba(255, 0, 0, 0.5)' }), + stroke: new Stroke({ color: 'red', width: 2 }), + }), + stroke: new Stroke({ color: 'blue', width: 20 }), + geometry: (feature) => { + const coords = feature.get('coordinate'); + if (coords) { + return new Point(coords); + } + return feature.getGeometry(); + }, + }); + }, +}); + const mocoLayer = new MocoLayer({ apiKey: window.apiKey, // tenant: 'rvf', @@ -65,9 +163,10 @@ const mocoLayer = new MocoLayer({ const map = new Map({ layers: [ baseLayer, - // realtimeLayer, + realtimeLayer, + realtimeLayerHover, // mocoLayer, - mapsetLayer, + // mapsetLayer, ], target: 'map', view: new View({ @@ -84,18 +183,32 @@ map.on('pointermove', (evt) => { return; } const pixel = map.getEventPixel(evt.originalEvent); - const [feature] = map.getFeaturesAtPixel(pixel, { - hitTolerance: 10, + const features = map.getFeaturesAtPixel(pixel, { + hitTolerance: 15, layerFilter: (l) => l === realtimeLayer, }); + const featuresHovered = map + .getFeaturesAtPixel(pixel, { + hitTolerance: 15, + layerFilter: (l) => l === realtimeLayerHover, + }) + .filter((f) => realtimeLayer.selectedVehicleId !== f.get('train_id')); + console.log(features.map((f) => f.get('train_id'))); - // realtimeLayer.hoverVehicleId = feature?.get('train_id'); + const featuresIds = features.map((f) => f.get('train_id')); + const featuresHoveredIds = featuresHovered.map((f) => f.get('train_id')); + const noFeaturesHovered = + !featuresHovered.length && !featuresHoveredIds.length; - realtimeLayer.highlight(feature); - if (feature) { - console.log(feature?.getProperties()); + if (features.length > featuresHovered.length || noFeaturesHovered) { + realtimeLayer.highlight(features); + realtimeLayerHover.getSource().clear(); + realtimeLayerHover.getSource().addFeatures(features); + if (features.length) { + console.log(features.map((f) => f.getProperties())); + } + map.getTargetElement().style.cursor = features.length ? 'pointer' : ''; } - map.getTargetElement().style.cursor = feature ? 'pointer' : ''; }); map.on('singleclick', (evt) => { @@ -107,8 +220,13 @@ map.on('singleclick', (evt) => { hitTolerance: 10, layerFilter: (l) => l === realtimeLayer, }); + const [featureHover] = map.getFeaturesAtPixel(pixel, { + hitTolerance: 30, + layerFilter: (l) => l === realtimeLayerHover, + }); + realtimeLayerHover.getSource().clear(); - realtimeLayer.select([feature]); + realtimeLayer.select([featureHover || feature]); }); map.on('moveend', () => { const zoom = map.getView().getZoom(); diff --git a/doc/src/components/Esdoc/index.json b/doc/src/components/Esdoc/index.json index 01fa08a5..afe621ae 100644 --- a/doc/src/components/Esdoc/index.json +++ b/doc/src/components/Esdoc/index.json @@ -3944,7 +3944,7 @@ "__docId__": 194, "kind": "file", "name": "build/api/WebSocketAPI.js", - "content": "/**\n * Class used to facilitate connection to a WebSocketAPI and\n * also to manage properly messages send to the WebSocketAPI.\n * This class must not contain any specific implementation.\n * @private\n */\nclass WebSocketAPI {\n constructor() {\n this.defineProperties();\n }\n /**\n * Get the websocket request string.\n *\n * @param {string} method Request mehtod {GET, SUB}.\n * @param {WebSocketParameters} params Request parameters.\n * @param {string} params.channel Channel name\n * @param {string} [params.args] Request arguments\n * @param {Number|string} [params.id] Request identifier\n * @return {string} request string\n * @private\n */\n static getRequestString(method, params = {}) {\n let reqStr = `${method} ${params.channel}`;\n reqStr += params.args ? ` ${params.args}` : '';\n reqStr += params.id ? ` ${params.id}` : '';\n return reqStr.trim();\n }\n addEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.addEventListener('message', onMessage);\n if (onError) {\n this.websocket.addEventListener('error', onError);\n this.websocket.addEventListener('close', onError);\n }\n }\n }\n /**\n * Close the websocket definitively.\n *\n * @private\n */\n close() {\n if (this.websocket && (this.open || this.connecting)) {\n this.websocket.onclose = () => { };\n this.websocket.close();\n this.messagesOnOpen = [];\n }\n }\n /**\n * (Re)connect the websocket.\n *\n * @param {string} url Websocket url.\n * @param {function} onOpen Callback called when the websocket connection is opened and before subscriptions of previous subscriptions.\n * @private\n */\n connect(url, onOpen = () => { }) {\n var _a;\n // if no url specify, close the current websocket and do nothing.\n if (!url) {\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();\n return;\n }\n // Behavior when a websocket already exists.\n if (this.websocket) {\n // If the current websocket has the same url and is open or is connecting, do nothing.\n if (this.websocket.url === url && (this.open || this.connecting)) {\n return;\n }\n // If the current websocket has not the same url and is open or is connecting, close it.\n if (this.websocket.url !== url && (this.open || this.connecting)) {\n this.websocket.close();\n }\n }\n this.websocket = new WebSocket(url);\n if (!this.open) {\n this.websocket.addEventListener('open', () => {\n onOpen();\n this.subscribePreviousSubscriptions();\n });\n }\n else {\n onOpen();\n this.subscribePreviousSubscriptions();\n }\n }\n defineProperties() {\n Object.defineProperties(this, {\n closed: {\n get: () => {\n return !!(!this.websocket ||\n this.websocket.readyState === this.websocket.CLOSED);\n },\n },\n closing: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CLOSING);\n },\n },\n connecting: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CONNECTING);\n },\n },\n /**\n * Array of message to send on open.\n * @type {Array}\n * @private\n */\n messagesOnOpen: {\n value: [],\n writable: true,\n },\n open: {\n get: () => {\n return !!(this.websocket && this.websocket.readyState === this.websocket.OPEN);\n },\n },\n /**\n * List of channels subscribed.\n * @type {WebSocketSubscribed}\n * @private\n */\n subscribed: {\n value: {},\n writable: true,\n },\n /**\n * Array of subscriptions.\n * @type {Array}\n * @private\n */\n subscriptions: {\n value: [],\n writable: true,\n },\n });\n }\n /**\n * Sends a get request to the websocket.\n * The callback is called only once, when the response is received or when the call returns an error.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on message event\n * @param {function} errorCb Callback on error and close event\n * @private\n */\n get(params, cb, errorCb) {\n const requestString = WebSocketAPI.getRequestString('GET', params);\n this.send(requestString);\n // We wrap the callbacks to make sure they are called only once.\n const once = (callback) => {\n return (...args) => {\n // @ts-expect-error - We know that args is an array\n callback(...args);\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n const { onErrorCb, onMessageCb } = this.requests[index];\n this.removeEvents(onMessageCb, onErrorCb);\n this.requests.splice(index, 1);\n };\n };\n const { onErrorCb, onMessageCb } = this.listen(params, once(cb), errorCb && once(errorCb));\n // Store requests and callbacks to be able to remove them.\n if (!this.requests) {\n this.requests = [];\n }\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n const newReq = {\n cb,\n errorCb,\n onErrorCb,\n onMessageCb,\n params,\n requestString,\n };\n if (index > -1) {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests[index] = newReq;\n }\n else {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests.push(newReq);\n }\n }\n /**\n * Listen to websocket messages.\n *\n * @param {WebSocketParameters} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @return {{onMessage: function, errorCb: function}} Object with onMessage and error callbacks\n * @private\n */\n listen(params, cb, errorCb) {\n // Remove the previous identical callback\n this.unlisten(params, cb);\n // We wrap the message callback to be sure we only propagate the message if it is for the right channel.\n const onMessage = (evt) => {\n let data;\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data = JSON.parse(evt.data);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('WebSocket: unable to parse JSON data', err, evt.data);\n return;\n }\n let source = params.channel;\n source += params.args ? ` ${params.args}` : '';\n // Buffer channel message return a list of other channels to propagate to proper callbacks.\n let contents;\n if (data.source === 'buffer') {\n // @ts-expect-error - We know that the data is a WebSocketAPIBufferMessageEventData\n contents = data\n .content;\n }\n else {\n contents = [data];\n }\n contents.forEach((content) => {\n // Because of backend optimization, the last content is null.\n if ((content === null || content === void 0 ? void 0 : content.source) === source &&\n (!params.id || params.id === data.client_reference)) {\n cb(content);\n }\n });\n };\n this.addEvents(onMessage, errorCb);\n return { onErrorCb: errorCb, onMessageCb: onMessage };\n }\n removeEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.removeEventListener('message', onMessage);\n if (onError) {\n this.websocket.removeEventListener('error', onError);\n this.websocket.removeEventListener('close', onError);\n }\n }\n }\n /**\n * Sends a message to the websocket.\n *\n * @param {message} message Message to send.\n * @private\n */\n send(message) {\n if (!this.websocket || this.closed || this.closing) {\n return;\n }\n const send = () => {\n var _a;\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.send(message);\n };\n if (!this.open) {\n // This 'if' avoid sending 2 identical BBOX message on open,\n if (!this.messagesOnOpen.includes(message)) {\n this.messagesOnOpen.push(message);\n this.websocket.addEventListener('open', () => {\n this.messagesOnOpen = [];\n send();\n });\n this.websocket.addEventListener('close', () => {\n this.messagesOnOpen = [];\n });\n }\n }\n else if (!this.messagesOnOpen.includes(message)) {\n send();\n }\n }\n /**\n * Subscribe to a given channel.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @param {boolean} quiet if false, no GET or SUB requests are send, only the callback is registered.\n * @private\n */\n subscribe(params, cb, errorCb, quiet = false) {\n const { onErrorCb, onMessageCb } = this.listen(params, cb, errorCb);\n const reqStr = WebSocketAPI.getRequestString('', params);\n const index = this.subscriptions.findIndex((subcr) => {\n return params.channel === subcr.params.channel && cb === subcr.cb;\n });\n const newSubscr = { cb, errorCb, onErrorCb, onMessageCb, params, quiet };\n if (index > -1) {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions[index] = newSubscr;\n }\n else {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions.push(newSubscr);\n }\n if (!this.subscribed[reqStr]) {\n if (!newSubscr.quiet) {\n this.send(`GET ${reqStr}`);\n this.send(`SUB ${reqStr}`);\n }\n this.subscribed[reqStr] = true;\n }\n }\n /**\n * After an auto reconnection we need to re-subscribe to the channels.\n */\n subscribePreviousSubscriptions() {\n // Before to subscribe previous subscriptions we make sure they\n // are all defined as unsubscribed, because this code is asynchrone\n // and a subscription could have been added in between.\n Object.keys(this.subscribed).forEach((key) => {\n this.subscribed[key] = false;\n });\n // Subscribe all previous subscriptions.\n [...this.subscriptions].forEach((s) => {\n this.subscribe(s.params, s.cb, s.errorCb, s.quiet);\n });\n }\n /**\n * Unlisten websocket messages.\n *\n * @param {Object} params Parameters for the websocket get request.\n * @param {function} cb Callback used when listen.\n * @private\n */\n unlisten(params, cb) {\n [...(this.subscriptions || []), ...(this.requests || [])]\n .filter((s) => {\n return s.params.channel === params.channel && (!cb || s.cb === cb);\n })\n .forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n }\n /**\n * Unsubscribe from a channel.\n * @param {string} source source to unsubscribe from\n * @param {function} cb Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @private\n */\n unsubscribe(source, cb) {\n const toRemove = this.subscriptions.filter((s) => {\n return s.params.channel === source && (!cb || s.cb === cb);\n });\n toRemove.forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n this.subscriptions = this.subscriptions.filter((s) => {\n return s.params.channel !== source || (cb && s.cb !== cb);\n });\n // If there is no more subscriptions to this channel, and the removed subscriptions didn't register quietly,\n // we DEL it.\n if (source &&\n this.subscribed[source] &&\n !this.subscriptions.find((s) => {\n return s.params.channel === source;\n }) &&\n toRemove.find((subscr) => {\n return !subscr.quiet;\n })) {\n this.send(`DEL ${source}`);\n this.subscribed[source] = false;\n }\n }\n}\nexport default WebSocketAPI;\n", + "content": "/**\n * Class used to facilitate connection to a WebSocketAPI and\n * also to manage properly messages send to the WebSocketAPI.\n * This class must not contain any specific implementation.\n * @private\n */\nclass WebSocketAPI {\n constructor() {\n this.defineProperties();\n }\n /**\n * Get the websocket request string.\n *\n * @param {string} method Request mehtod {GET, SUB}.\n * @param {WebSocketParameters} params Request parameters.\n * @param {string} params.channel Channel name\n * @param {string} [params.args] Request arguments\n * @param {Number|string} [params.id] Request identifier\n * @return {string} request string\n * @private\n */\n static getRequestString(method, params = {}) {\n let reqStr = `${method} ${params.channel}`;\n reqStr += params.args ? ` ${params.args}` : '';\n reqStr += params.id ? ` ${params.id}` : '';\n return reqStr.trim();\n }\n addEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.addEventListener('message', onMessage);\n if (onError) {\n this.websocket.addEventListener('error', onError);\n this.websocket.addEventListener('close', onError);\n }\n }\n }\n /**\n * Close the websocket definitively.\n *\n * @private\n */\n close() {\n if (this.websocket && (this.open || this.connecting)) {\n this.websocket.onclose = () => { };\n this.websocket.close();\n this.messagesOnOpen = [];\n }\n }\n /**\n * (Re)connect the websocket.\n *\n * @param {string} url Websocket url.\n * @param {function} onOpen Callback called when the websocket connection is opened and before subscriptions of previous subscriptions.\n * @private\n */\n connect(url, onOpen = () => { }) {\n var _a;\n // if no url specify, close the current websocket and do nothing.\n if (!url) {\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();\n return;\n }\n // Behavior when a websocket already exists.\n if (this.websocket) {\n // If the current websocket has the same url and is open or is connecting, do nothing.\n if (this.websocket.url === url && (this.open || this.connecting)) {\n return;\n }\n // If the current websocket has not the same url and is open or is connecting, close it.\n if (this.websocket.url !== url && (this.open || this.connecting)) {\n this.websocket.close();\n }\n }\n this.websocket = new WebSocket(url);\n if (!this.open) {\n this.websocket.addEventListener('open', () => {\n onOpen();\n this.subscribePreviousSubscriptions();\n });\n }\n else {\n onOpen();\n this.subscribePreviousSubscriptions();\n }\n }\n defineProperties() {\n Object.defineProperties(this, {\n closed: {\n get: () => {\n return !!(!this.websocket ||\n this.websocket.readyState === this.websocket.CLOSED);\n },\n },\n closing: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CLOSING);\n },\n },\n connecting: {\n get: () => {\n return !!(this.websocket &&\n this.websocket.readyState === this.websocket.CONNECTING);\n },\n },\n /**\n * Array of message to send on open.\n * @type {Array}\n * @private\n */\n messagesOnOpen: {\n value: [],\n writable: true,\n },\n open: {\n get: () => {\n return !!(this.websocket && this.websocket.readyState === this.websocket.OPEN);\n },\n },\n /**\n * List of channels subscribed.\n * @type {WebSocketSubscribed}\n * @private\n */\n subscribed: {\n value: {},\n writable: true,\n },\n /**\n * Array of subscriptions.\n * @type {Array}\n * @private\n */\n subscriptions: {\n value: [],\n writable: true,\n },\n });\n }\n /**\n * Sends a get request to the websocket.\n * The callback is called only once, when the response is received or when the call returns an error.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on message event\n * @param {function} errorCb Callback on error and close event\n * @private\n */\n get(params, cb, errorCb) {\n const requestString = WebSocketAPI.getRequestString('GET', params);\n this.send(requestString);\n // We wrap the callbacks to make sure they are called only once.\n const once = (callback) => {\n return (...args) => {\n // @ts-expect-error - We know that args is an array\n callback(...args);\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n if (index === -1) {\n return;\n }\n const { onErrorCb, onMessageCb } = this.requests[index];\n this.removeEvents(onMessageCb, onErrorCb);\n this.requests.splice(index, 1);\n };\n };\n const { onErrorCb, onMessageCb } = this.listen(params, once(cb), errorCb && once(errorCb));\n // Store requests and callbacks to be able to remove them.\n if (!this.requests) {\n this.requests = [];\n }\n const index = this.requests.findIndex((request) => {\n return requestString === request.requestString && cb === request.cb;\n });\n const newReq = {\n cb,\n errorCb,\n onErrorCb,\n onMessageCb,\n params,\n requestString,\n };\n if (index > -1) {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests[index] = newReq;\n }\n else {\n // @ts-expect-error - We know that the requests is an array of WebSocketAPIRequest\n this.requests.push(newReq);\n }\n }\n /**\n * Listen to websocket messages.\n *\n * @param {WebSocketParameters} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @return {{onMessage: function, errorCb: function}} Object with onMessage and error callbacks\n * @private\n */\n listen(params, cb, errorCb) {\n // Remove the previous identical callback\n this.unlisten(params, cb);\n // We wrap the message callback to be sure we only propagate the message if it is for the right channel.\n const onMessage = (evt) => {\n let data;\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data = JSON.parse(evt.data);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('WebSocket: unable to parse JSON data', err, evt.data);\n return;\n }\n let source = params.channel;\n source += params.args ? ` ${params.args}` : '';\n // Buffer channel message return a list of other channels to propagate to proper callbacks.\n let contents;\n if (data.source === 'buffer') {\n // @ts-expect-error - We know that the data is a WebSocketAPIBufferMessageEventData\n contents = data\n .content;\n }\n else {\n contents = [data];\n }\n contents.forEach((content) => {\n // Because of backend optimization, the last content is null.\n if ((content === null || content === void 0 ? void 0 : content.source) === source &&\n (!params.id || params.id === data.client_reference)) {\n cb(content);\n }\n });\n };\n this.addEvents(onMessage, errorCb);\n return { onErrorCb: errorCb, onMessageCb: onMessage };\n }\n removeEvents(onMessage, onError) {\n if (this.websocket) {\n this.websocket.removeEventListener('message', onMessage);\n if (onError) {\n this.websocket.removeEventListener('error', onError);\n this.websocket.removeEventListener('close', onError);\n }\n }\n }\n /**\n * Sends a message to the websocket.\n *\n * @param {message} message Message to send.\n * @private\n */\n send(message) {\n if (!this.websocket || this.closed || this.closing) {\n return;\n }\n const send = () => {\n var _a;\n (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.send(message);\n };\n if (!this.open) {\n // This 'if' avoid sending 2 identical BBOX message on open,\n if (!this.messagesOnOpen.includes(message)) {\n this.messagesOnOpen.push(message);\n this.websocket.addEventListener('open', () => {\n this.messagesOnOpen = [];\n send();\n });\n this.websocket.addEventListener('close', () => {\n this.messagesOnOpen = [];\n });\n }\n }\n else if (!this.messagesOnOpen.includes(message)) {\n send();\n }\n }\n /**\n * Subscribe to a given channel.\n *\n * @param {Object} params Parameters for the websocket get request\n * @param {function} cb callback on listen\n * @param {function} errorCb Callback on error\n * @param {boolean} quiet if false, no GET or SUB requests are send, only the callback is registered.\n * @private\n */\n subscribe(params, cb, errorCb, quiet = false) {\n const { onErrorCb, onMessageCb } = this.listen(params, cb, errorCb);\n const reqStr = WebSocketAPI.getRequestString('', params);\n const index = this.subscriptions.findIndex((subcr) => {\n return params.channel === subcr.params.channel && cb === subcr.cb;\n });\n const newSubscr = { cb, errorCb, onErrorCb, onMessageCb, params, quiet };\n if (index > -1) {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions[index] = newSubscr;\n }\n else {\n // @ts-expect-error - We know that the subscriptions is an array of WebSocketAPISubscription\n this.subscriptions.push(newSubscr);\n }\n if (!this.subscribed[reqStr]) {\n if (!newSubscr.quiet) {\n this.send(`GET ${reqStr}`);\n this.send(`SUB ${reqStr}`);\n }\n this.subscribed[reqStr] = true;\n }\n }\n /**\n * After an auto reconnection we need to re-subscribe to the channels.\n */\n subscribePreviousSubscriptions() {\n // Before to subscribe previous subscriptions we make sure they\n // are all defined as unsubscribed, because this code is asynchrone\n // and a subscription could have been added in between.\n Object.keys(this.subscribed).forEach((key) => {\n this.subscribed[key] = false;\n });\n // Subscribe all previous subscriptions.\n [...this.subscriptions].forEach((s) => {\n this.subscribe(s.params, s.cb, s.errorCb, s.quiet);\n });\n }\n /**\n * Unlisten websocket messages.\n *\n * @param {Object} params Parameters for the websocket get request.\n * @param {function} cb Callback used when listen.\n * @private\n */\n unlisten(params, cb) {\n [...(this.subscriptions || []), ...(this.requests || [])]\n .filter((s) => {\n return s.params.channel === params.channel && (!cb || s.cb === cb);\n })\n .forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n }\n /**\n * Unsubscribe from a channel.\n * @param {string} source source to unsubscribe from\n * @param {function} cb Callback function to unsubscribe. If null all subscriptions for the channel will be unsubscribed.\n * @private\n */\n unsubscribe(source, cb) {\n const toRemove = this.subscriptions.filter((s) => {\n return s.params.channel === source && (!cb || s.cb === cb);\n });\n toRemove.forEach(({ onErrorCb, onMessageCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n this.subscriptions = this.subscriptions.filter((s) => {\n return s.params.channel !== source || (cb && s.cb !== cb);\n });\n // If there is no more subscriptions to this channel, and the removed subscriptions didn't register quietly,\n // we DEL it.\n if (source &&\n this.subscribed[source] &&\n !this.subscriptions.find((s) => {\n return s.params.channel === source;\n }) &&\n toRemove.find((subscr) => {\n return !subscr.quiet;\n })) {\n this.send(`DEL ${source}`);\n this.subscribed[source] = false;\n }\n }\n}\nexport default WebSocketAPI;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/WebSocketAPI.js", "access": "private", @@ -4239,7 +4239,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#requests", "access": "private", "description": null, - "lineNumber": 168, + "lineNumber": 171, "undocument": true, "type": { "types": [ @@ -4258,7 +4258,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#listen", "access": "private", "description": "Listen to websocket messages.", - "lineNumber": 199, + "lineNumber": 202, "params": [ { "nullable": null, @@ -4311,7 +4311,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#removeEvents", "access": "private", "description": null, - "lineNumber": 237, + "lineNumber": 240, "undocument": true, "params": [ { @@ -4340,7 +4340,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#send", "access": "private", "description": "Sends a message to the websocket.", - "lineNumber": 252, + "lineNumber": 255, "params": [ { "nullable": null, @@ -4366,7 +4366,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#subscribe", "access": "private", "description": "Subscribe to a given channel.", - "lineNumber": 286, + "lineNumber": 289, "params": [ { "nullable": null, @@ -4422,7 +4422,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#subscribePreviousSubscriptions", "access": "private", "description": "After an auto reconnection we need to re-subscribe to the channels.", - "lineNumber": 312, + "lineNumber": 315, "params": [], "return": null }, @@ -4437,7 +4437,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#unlisten", "access": "private", "description": "Unlisten websocket messages.", - "lineNumber": 331, + "lineNumber": 334, "params": [ { "nullable": null, @@ -4473,7 +4473,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#unsubscribe", "access": "private", "description": "Unsubscribe from a channel.", - "lineNumber": 346, + "lineNumber": 349, "params": [ { "nullable": null, @@ -4507,7 +4507,7 @@ "longname": "build/api/WebSocketAPI.js~WebSocketAPI#subscriptions", "access": "private", "description": null, - "lineNumber": 353, + "lineNumber": 356, "undocument": true, "type": { "types": [ @@ -6363,7 +6363,7 @@ "__docId__": 272, "kind": "file", "name": "build/common/utils/RealtimeEngine.js", - "content": "import debounce from 'lodash.debounce';\nimport throttle from 'lodash.throttle';\nimport { buffer, containsCoordinate, intersects } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport { fromLonLat } from 'ol/proj';\nimport { RealtimeAPI, RealtimeModes } from '../../api';\nimport realtimeStyle from '../styles/realtimeStyle';\nimport { MOTS_ONLY_RAIL, MOTS_WITHOUT_CABLE, styleOptionsForMot, } from './realtimeStyleUtils';\nimport renderTrajectories from './renderTrajectories';\n/**\n * Basic style options used by default in the RealtimeEngine.\n */\nexport const defaultStyleOptions = Object.assign({ delayDisplay: 300000, delayOutlineColor: '#000', getArrowSize: (trajectory, viewState, radius = 0) => {\n return [(radius * 3) / 4, radius];\n }, getColor: () => {\n return '#000';\n }, getDelayColor: () => {\n return '#000';\n }, getDelayFont: (traj, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getDelayText: () => {\n return '';\n }, getDelayTextColor: () => {\n return '#000';\n }, getImage: () => {\n return null;\n }, getMaxRadiusForStrokeAndDelay: () => {\n return 7;\n }, getMaxRadiusForText: () => {\n return 10;\n }, getRadius: () => {\n return 5;\n }, getText: ((traj) => {\n var _a, _b;\n return ((_b = (_a = traj === null || traj === void 0 ? void 0 : traj.properties) === null || _a === void 0 ? void 0 : _a.line) === null || _b === void 0 ? void 0 : _b.name) || 'U';\n }), getTextColor: () => {\n return '#fff';\n }, getTextFont: (trajectory, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getTextSize: () => {\n return 14;\n }, showDelayBg: true, showDelayText: true, showHeading: false, useDelayStyle: false }, styleOptionsForMot);\n/**\n * This class is responsible for drawing trajectories from a realtime API in a canvas,\n * depending on the map's view state and at a specific time.\n *\n * This class is totally agnostic from Maplibre or OpenLayers and must stay taht way.\n */\nclass RealtimeEngine {\n get mode() {\n return this._mode;\n }\n set mode(newMode) {\n var _a, _b;\n if (newMode === this._mode) {\n return;\n }\n this._mode = newMode;\n if ((_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.wsApi) === null || _b === void 0 ? void 0 : _b.open) {\n this.stop();\n this.start();\n }\n }\n get speed() {\n return this._speed;\n }\n set speed(newSpeed) {\n this._speed = newSpeed;\n this.start();\n }\n get style() {\n return this._style;\n }\n set style(newStyle) {\n this._style = newStyle;\n this.renderTrajectories();\n }\n get time() {\n return this._time;\n }\n set time(newTime) {\n this._time = (newTime === null || newTime === void 0 ? void 0 : newTime.getTime)\n ? newTime\n : new Date(newTime);\n this.renderTrajectories();\n }\n constructor(options) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;\n this.isIdle = false;\n this.getViewState = () => {\n return {};\n };\n this.shouldRender = () => {\n return true;\n };\n this._mode = options.mode || RealtimeModes.TOPOGRAPHIC;\n this._speed = (_a = options.speed) !== null && _a !== void 0 ? _a : 1; // If live property is true. The speed is ignored.\n this._style = (_b = options.style) !== null && _b !== void 0 ? _b : realtimeStyle;\n this._time = (_c = options.time) !== null && _c !== void 0 ? _c : new Date();\n this.api = (_d = options.api) !== null && _d !== void 0 ? _d : new RealtimeAPI(options);\n this.bboxParameters = options.bboxParameters;\n this.canvas =\n (_e = options.canvas) !== null && _e !== void 0 ? _e : (typeof document !== 'undefined'\n ? document.createElement('canvas')\n : undefined);\n this.debug = (_f = options.debug) !== null && _f !== void 0 ? _f : false;\n this.filter = options.filter;\n this.hoverVehicleId = options.hoverVehicleId;\n /**\n * If true. The layer will always use Date.now() on the next tick to render the trajectories.\n * When true, setting the time property has no effect.\n */\n this.live = options.live !== false;\n this.minZoomInterpolation = (_g = options.minZoomInterpolation) !== null && _g !== void 0 ? _g : 8; // Min zoom level from which trains positions are not interpolated.\n this.pixelRatio =\n (_h = options.pixelRatio) !== null && _h !== void 0 ? _h : (typeof window !== 'undefined' ? window.devicePixelRatio : 1);\n this.selectedVehicleId = options.selectedVehicleId;\n this.sort = options.sort;\n /**\n * Custom options to pass as last parameter of the style function.\n */\n this.styleOptions = Object.assign(Object.assign({}, defaultStyleOptions), ((_j = options.styleOptions) !== null && _j !== void 0 ? _j : {}));\n this.tenant = (_k = options.tenant) !== null && _k !== void 0 ? _k : ''; // sbb,sbh or sbm\n this.trajectories = {};\n this.useDebounce = (_l = options.useDebounce) !== null && _l !== void 0 ? _l : false;\n this.useRequestAnimationFrame = (_m = options.useRequestAnimationFrame) !== null && _m !== void 0 ? _m : false;\n this.useThrottle = options.useThrottle !== false; // the default behavior\n this.getViewState =\n (_o = options.getViewState) !== null && _o !== void 0 ? _o : (() => {\n return {};\n });\n this.shouldRender =\n (_p = options.shouldRender) !== null && _p !== void 0 ? _p : (() => {\n return true;\n });\n this.getRefreshTimeInMs =\n (_q = options.getRefreshTimeInMs) !== null && _q !== void 0 ? _q : this.getRefreshTimeInMs.bind(this);\n this.onRender = options.onRender;\n this.onIdle = options.onIdle;\n this.onStart = options.onStart;\n this.onStop = options.onStop;\n this.format = new GeoJSON();\n // Mots by zoom\n // Server will block non train before zoom 9\n this.motsByZoom = (_r = options.motsByZoom) !== null && _r !== void 0 ? _r : [\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_WITHOUT_CABLE,\n MOTS_WITHOUT_CABLE,\n ];\n this.getMotsByZoom = (zoom) => {\n if (options.getMotsByZoom) {\n return options.getMotsByZoom(zoom, this.motsByZoom);\n }\n if (zoom > this.motsByZoom.length - 1) {\n return this.motsByZoom[this.motsByZoom.length - 1];\n }\n return this.motsByZoom[zoom];\n };\n // Generalization levels by zoom\n this.generalizationLevelByZoom = options.generalizationLevelByZoom || [];\n this.getGeneralizationLevelByZoom = (zoom) => {\n if (options.getGeneralizationLevelByZoom) {\n return options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom);\n }\n if (zoom > this.generalizationLevelByZoom.length - 1) {\n return this.generalizationLevelByZoom[this.generalizationLevelByZoom.length - 1];\n }\n return this.generalizationLevelByZoom[zoom];\n };\n // Graph by zoom\n this.graphByZoom = (_s = options.graphByZoom) !== null && _s !== void 0 ? _s : [];\n this.getGraphByZoom = (zoom) => {\n var _a, _b;\n if (options.getGraphByZoom) {\n return options.getGraphByZoom(zoom, this.graphByZoom);\n }\n if (zoom > this.graphByZoom.length - 1) {\n return (_a = this.graphByZoom) === null || _a === void 0 ? void 0 : _a[this.graphByZoom.length - 1];\n }\n return (_b = this.graphByZoom) === null || _b === void 0 ? void 0 : _b[zoom];\n };\n // Render time interval by zoom\n this.renderTimeIntervalByZoom = options.renderTimeIntervalByZoom || [\n 100000, 50000, 40000, 30000, 20000, 15000, 10000, 5000, 2000, 1000, 400,\n 300, 250, 180, 90, 60, 50, 50, 50, 50, 50,\n ];\n this.getRenderTimeIntervalByZoom = (zoom) => {\n if (options.getRenderTimeIntervalByZoom) {\n return options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom);\n }\n return this.renderTimeIntervalByZoom[zoom];\n };\n // This property will call api.setBbox on each movend event\n this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;\n // Define throttling and debounce render function\n this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });\n this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, 50, { leading: true, maxWait: 5000, trailing: true });\n this.renderState = {\n center: [0, 0],\n rotation: 0,\n zoom: undefined,\n };\n this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);\n this.onDeleteTrajectoryMessage = this.onDeleteTrajectoryMessage.bind(this);\n this.onDocumentVisibilityChange =\n this.onDocumentVisibilityChange.bind(this);\n }\n /**\n * Add a trajectory.\n * @param {RealtimeTrajectory} trajectory The trajectory to add.\n * @private\n */\n addTrajectory(trajectory) {\n if (!this.trajectories) {\n this.trajectories = {};\n }\n const id = trajectory.properties.train_id;\n if (id !== undefined) {\n this.trajectories[id] = trajectory;\n }\n this.renderTrajectories();\n }\n attachToMap() {\n // To avoid browser hanging when the tab is not visible for a certain amount of time,\n // We stop the rendering and the websocket when hide and start again when show.\n document.addEventListener('visibilitychange', this.onDocumentVisibilityChange);\n }\n detachFromMap() {\n document.removeEventListener('visibilitychange', this.onDocumentVisibilityChange);\n this.stop();\n if (this.canvas) {\n const context = this.canvas.getContext('2d');\n if (context) {\n context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n }\n /**\n * Get the duration before the next update depending on zoom level.\n *\n * @private\n */\n getRefreshTimeInMs() {\n var _a, _b;\n const viewState = this.getViewState();\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;\n const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;\n const nextTick = Math.max(25, timeStep / (this.speed || 1));\n const nextThrottleTick = Math.min(nextTick, 500);\n // TODO: see if this should go elsewhere.\n if (this.useThrottle) {\n this.throttleRenderTrajectories = throttle(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });\n }\n else if (this.useDebounce) {\n this.debounceRenderTrajectories = debounce(this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, maxWait: 5000, trailing: true });\n }\n if ((_b = this.api) === null || _b === void 0 ? void 0 : _b.buffer) {\n const [, size] = this.api.buffer;\n this.api.buffer = [nextThrottleTick, size];\n }\n return nextTick;\n }\n /**\n * Get vehicle.\n * @param {function} filterFc A function use to filter results.\n * @return {Array} Array of vehicle.\n */\n getVehicles(filterFc) {\n return ((this.trajectories &&\n // @ts-expect-error good type must be defined\n Object.values(this.trajectories).filter(filterFc)) ||\n []);\n }\n /**\n * Request feature information for a given coordinate.\n *\n * @param {ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {Object} options Options See child classes to see which options are supported.\n * @param {number} [options.resolution=1] The resolution of the map.\n * @param {number} [options.nb=Infinity] The max number of vehicles to return.\n * @return {Promise} Promise with features, layer and coordinate.\n */\n getVehiclesAtCoordinate(coordinate, options) {\n const { resolution } = this.getViewState();\n const { hitTolerance, nb } = options || {};\n const extent = buffer([...coordinate, ...coordinate], (hitTolerance !== null && hitTolerance !== void 0 ? hitTolerance : 5) * (resolution !== null && resolution !== void 0 ? resolution : 1));\n let trajectories = Object.values(this.trajectories || {});\n if (this.sort) {\n // @ts-expect-error good type must be defined\n trajectories = trajectories.sort(this.sort);\n }\n const vehicles = [];\n // Theoretically 'for' is faster then 'for-of and it is important here\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < trajectories.length; i += 1) {\n const trajectory = trajectories[i];\n const { coordinate: trajcoord } = trajectory.properties;\n if (trajcoord && containsCoordinate(extent, trajcoord)) {\n vehicles.push(trajectory);\n }\n if (vehicles.length === nb) {\n break;\n }\n }\n return { features: vehicles, type: 'FeatureCollection' };\n }\n /**\n * Callback on websocket's deleted_vehicles channel events.\n * It removes the trajectory from the list.\n *\n * @private\n * @override\n */\n onDeleteTrajectoryMessage(data) {\n if (!data.content) {\n return;\n }\n this.removeTrajectory(data.content);\n }\n onDocumentVisibilityChange() {\n if (document.hidden) {\n this.stop();\n // Since we don't receive deleted_vehicles event when docuement\n // is hidden. We have to clean all the trajectories for a fresh\n // start when the document is visible again.\n this.trajectories = {};\n }\n else {\n const viewState = this.getViewState();\n if (!viewState.visible) {\n return;\n }\n this.start();\n }\n }\n /**\n * Callback on websocket's trajectory channel events.\n * It adds a trajectory to the list.\n *\n * @private\n */\n onTrajectoryMessage(data) {\n this.updateIdleState();\n if (!data.content) {\n return;\n }\n const trajectory = data.content;\n const { geometry, properties: { raw_coordinates: rawCoordinates, time_since_update: timeSinceUpdate, }, } = trajectory;\n // ignore old events [SBAHNM-97]\n // @ts-expect-error can be undefined\n if (timeSinceUpdate < 0) {\n return;\n }\n // console.time(`onTrajectoryMessage${data.content.properties.train_id}`);\n if (this.purgeTrajectory(trajectory)) {\n return;\n }\n if (this.debug &&\n this.mode === RealtimeModes.TOPOGRAPHIC &&\n rawCoordinates) {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry({\n coordinates: fromLonLat(rawCoordinates),\n type: 'Point',\n });\n }\n else {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry(geometry);\n }\n // TODO Make sure the timeOffset is useful. May be we can remove it.\n // @ts-expect-error missing type definition\n trajectory.properties.timeOffset = Date.now() - data.timestamp;\n this.addTrajectory(trajectory);\n }\n /**\n * On zoomend we adjust the time interval of the update of vehicles positions.\n *\n * @private\n */\n onZoomEnd() {\n this.startUpdateTime();\n }\n /**\n * Remove all trajectories that are in the past.\n */\n purgeOutOfDateTrajectories() {\n Object.entries(this.trajectories || {}).forEach(([key, trajectory]) => {\n var _a;\n const timeIntervals = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.time_intervals;\n if (this.time && (timeIntervals === null || timeIntervals === void 0 ? void 0 : timeIntervals.length)) {\n const lastTimeInterval = timeIntervals[timeIntervals.length - 1][0];\n if (lastTimeInterval < this.time.getTime()) {\n this.removeTrajectory(key);\n }\n }\n });\n }\n /**\n * Determine if the trajectory is useless and should be removed from the list or not.\n * By default, this function exclude vehicles:\n * - that have their trajectory outside the current extent and\n * - that aren't in the MOT list.\n *\n * @param {RealtimeTrajectory} trajectory\n * @return {boolean} if the trajectory must be displayed or not.\n * @private\n */\n purgeTrajectory(trajectory) {\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const { bounds, type } = trajectory.properties;\n if ((this.isUpdateBboxOnMoveEnd && extent && !intersects(extent, bounds)) ||\n (this.mots && !this.mots.includes(type))) {\n this.removeTrajectory(trajectory);\n return true;\n }\n return false;\n }\n removeTrajectory(trajectoryOrId) {\n var _a;\n let id;\n if (typeof trajectoryOrId !== 'string') {\n id = (_a = trajectoryOrId === null || trajectoryOrId === void 0 ? void 0 : trajectoryOrId.properties) === null || _a === void 0 ? void 0 : _a.train_id;\n }\n else {\n id = trajectoryOrId;\n }\n if (id !== undefined && this.trajectories) {\n delete this.trajectories[id];\n }\n }\n /**\n * Render the trajectories requesting an animation frame and cancelling the previous one.\n * This function must be overrided by children to provide the correct parameters.\n *\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectories(noInterpolate) {\n const viewState = this.getViewState();\n if (this.requestId) {\n cancelAnimationFrame(this.requestId);\n this.requestId = undefined;\n }\n if (!(viewState === null || viewState === void 0 ? void 0 : viewState.center) || !(viewState === null || viewState === void 0 ? void 0 : viewState.extent) || !(viewState === null || viewState === void 0 ? void 0 : viewState.size)) {\n return;\n }\n if (!noInterpolate && this.useRequestAnimationFrame) {\n this.requestId = requestAnimationFrame(() => {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n });\n }\n else if (!noInterpolate && this.useDebounce) {\n this.debounceRenderTrajectories(viewState, noInterpolate);\n }\n else if (!noInterpolate && this.useThrottle) {\n this.throttleRenderTrajectories(viewState, noInterpolate);\n }\n else {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n }\n }\n /**\n * Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.\n *\n * @param {object} viewState The view state of the map.\n * @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.\n * @param {number[4]} viewState.extent Extent of the map in mercator coordinates.\n * @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.\n * @param {number} [viewState.rotation = 0] Rotation of the map to render.\n * @param {number} viewState.resolution Resolution of the map to render.\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectoriesInternal(viewState, noInterpolate = false) {\n var _a;\n if (!this.trajectories || !this.shouldRender()) {\n return false;\n }\n let time = new Date();\n if (this.live) {\n // Save the time internally, to keep trace of the time rendered for purge.\n this._time = time;\n }\n else if (this.time) {\n time = this.time;\n }\n const trajectories = Object.values(this.trajectories);\n // console.time('sort');\n if (this.sort) {\n // @ts-expect-error type problem\n trajectories.sort(this.sort);\n }\n // console.timeEnd('sort');\n if (!this.canvas || !this.style) {\n return true;\n }\n this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time: time.getTime() }), Object.assign(Object.assign({}, this.styleOptions), { filter: this.filter, hoverVehicleId: this.hoverVehicleId, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation\n ? true\n : noInterpolate, selectedVehicleId: this.selectedVehicleId }));\n (_a = this.onRender) === null || _a === void 0 ? void 0 : _a.call(this, this.renderState, viewState);\n // console.timeEnd('render');\n return true;\n }\n setBbox() {\n var _a;\n this.updateIdleState();\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n if (!extent || Number.isNaN(zoom)) {\n return;\n }\n // Clean trajectories before sending the new bbox\n // Purge trajectories:\n // - which are outside the extent\n // - when it's bus and zoom level is too low for them\n if (this.trajectories && extent && zoom) {\n const keys = Object.keys(this.trajectories);\n for (let i = keys.length - 1; i >= 0; i -= 1) {\n this.purgeTrajectory(this.trajectories[keys[i]]);\n }\n }\n // The backend only supports non float value\n const zoomFloor = Math.floor(zoom);\n if (!extent || Number.isNaN(zoomFloor)) {\n return;\n }\n // The extent does not need to be precise under meter, so we round floor/ceil the values.\n const [minX, minY, maxX, maxY] = extent;\n const bbox = [\n Math.floor(minX),\n Math.floor(minY),\n Math.ceil(maxX),\n Math.ceil(maxY),\n zoomFloor,\n ];\n /* @private */\n this.generalizationLevel = this.getGeneralizationLevelByZoom(zoomFloor);\n if (this.generalizationLevel) {\n bbox.push(`gen=${this.generalizationLevel}`);\n }\n /* @private */\n this.mots = this.getMotsByZoom(zoomFloor);\n if (this.mots) {\n bbox.push(`mots=${this.mots.toString()}`);\n }\n if (this.tenant) {\n bbox.push(`tenant=${this.tenant}`);\n }\n if (this.mode !== 'topographic') {\n bbox.push(`channel_prefix=${this.mode}`);\n }\n const graph = this.getGraphByZoom(zoomFloor);\n if (graph) {\n bbox.push(`graph=${graph}`);\n }\n if (this.bboxParameters) {\n Object.entries(this.bboxParameters).forEach(([key, value]) => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n bbox.push(`${key}=${value}`);\n });\n }\n // Extent and zoom level are mandatory.\n this.api.bbox = bbox;\n }\n start() {\n this.stop();\n // Before starting to update trajectories, we remove trajectories that have\n // a time_intervals in the past, it will\n // avoid phantom train that are at the end of their route because we never\n // received the deleted_vehicle event because we have changed the browser tab.\n this.purgeOutOfDateTrajectories();\n this.renderTrajectories();\n this.startUpdateTime();\n this.api.open();\n this.api.subscribeTrajectory(this.mode, this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n this.api.subscribeDeletedVehicles(this.mode, this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n // Update the bbox on each move end\n if (this.isUpdateBboxOnMoveEnd) {\n this.setBbox();\n }\n if (this.onStart) {\n this.onStart(this);\n }\n }\n /**\n * Start the clock.\n * @private\n */\n startUpdateTime() {\n this.stopUpdateTime();\n this.updateTimeDelay = this.getRefreshTimeInMs() || 0;\n this.updateTimeInterval = window.setInterval(() => {\n // When live=true, we update the time with new Date();\n if (this.live) {\n this.time = new Date();\n }\n else if (this.time && this.updateTimeDelay && this.speed) {\n this.time = new Date(this.time.getTime() + this.updateTimeDelay * this.speed);\n }\n }, this.updateTimeDelay);\n }\n stop() {\n this.api.unsubscribeTrajectory(this.onTrajectoryMessage);\n this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);\n this.api.close();\n if (this.onStop) {\n this.onStop(this);\n }\n }\n /**\n * Stop the clock.\n * @private\n */\n stopUpdateTime() {\n if (this.updateTimeInterval) {\n clearInterval(this.updateTimeInterval);\n this.updateTimeInterval = undefined;\n }\n }\n updateIdleState() {\n this.isIdle = false;\n clearTimeout(this._idleTimeout);\n this._idleTimeout = window.setTimeout(() => {\n var _a;\n this.isIdle = true;\n (_a = this.onIdle) === null || _a === void 0 ? void 0 : _a.call(this, this);\n }, 1000);\n }\n}\nexport default RealtimeEngine;\n", + "content": "import debounce from 'lodash.debounce';\nimport throttle from 'lodash.throttle';\nimport { buffer, containsCoordinate, intersects } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport { fromLonLat } from 'ol/proj';\nimport { RealtimeAPI, RealtimeModes } from '../../api';\nimport realtimeStyle from '../styles/realtimeStyle';\nimport { MOTS_ONLY_RAIL, MOTS_WITHOUT_CABLE, styleOptionsForMot, } from './realtimeStyleUtils';\nimport renderTrajectories from './renderTrajectories';\n/**\n * Basic style options used by default in the RealtimeEngine.\n */\nexport const defaultStyleOptions = Object.assign({ delayDisplay: 300000, delayOutlineColor: '#000', getArrowSize: (trajectory, viewState, radius = 0) => {\n return [(radius * 3) / 4, radius];\n }, getColor: () => {\n return '#000';\n }, getDelayColor: () => {\n return '#000';\n }, getDelayFont: (traj, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getDelayText: () => {\n return '';\n }, getDelayTextColor: () => {\n return '#000';\n }, getImage: () => {\n return null;\n }, getMaxRadiusForStrokeAndDelay: () => {\n return 7;\n }, getMaxRadiusForText: () => {\n return 10;\n }, getRadius: () => {\n return 5;\n }, getText: ((traj) => {\n var _a, _b;\n return ((_b = (_a = traj === null || traj === void 0 ? void 0 : traj.properties) === null || _a === void 0 ? void 0 : _a.line) === null || _b === void 0 ? void 0 : _b.name) || 'U';\n }), getTextColor: () => {\n return '#fff';\n }, getTextFont: (trajectory, viewState, fontSize) => {\n return `bold ${fontSize}px arial, sans-serif`;\n }, getTextSize: () => {\n return 14;\n }, showDelayBg: true, showDelayText: true, showHeading: false, useDelayStyle: false }, styleOptionsForMot);\n/**\n * This class is responsible for drawing trajectories from a realtime API in a canvas,\n * depending on the map's view state and at a specific time.\n *\n * This class is totally agnostic from Maplibre or OpenLayers and must stay taht way.\n */\nclass RealtimeEngine {\n get mode() {\n return this._mode;\n }\n set mode(newMode) {\n var _a, _b;\n if (newMode === this._mode) {\n return;\n }\n this._mode = newMode;\n if ((_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.wsApi) === null || _b === void 0 ? void 0 : _b.open) {\n this.stop();\n this.start();\n }\n }\n get speed() {\n return this._speed;\n }\n set speed(newSpeed) {\n this._speed = newSpeed;\n this.start();\n }\n get style() {\n return this._style;\n }\n set style(newStyle) {\n this._style = newStyle;\n this.renderTrajectories();\n }\n get time() {\n return this._time;\n }\n set time(newTime) {\n this._time = (newTime === null || newTime === void 0 ? void 0 : newTime.getTime)\n ? newTime\n : new Date(newTime);\n this.renderTrajectories();\n }\n constructor(options) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;\n this.isIdle = false;\n this.getViewState = () => {\n return {};\n };\n this.shouldRender = () => {\n return true;\n };\n this._mode = options.mode || RealtimeModes.TOPOGRAPHIC;\n this._speed = (_a = options.speed) !== null && _a !== void 0 ? _a : 1; // If live property is true. The speed is ignored.\n this._style = (_b = options.style) !== null && _b !== void 0 ? _b : realtimeStyle;\n this._time = (_c = options.time) !== null && _c !== void 0 ? _c : new Date();\n this.api = (_d = options.api) !== null && _d !== void 0 ? _d : new RealtimeAPI(options);\n this.bboxParameters = options.bboxParameters;\n this.canvas =\n (_e = options.canvas) !== null && _e !== void 0 ? _e : (typeof document !== 'undefined'\n ? document.createElement('canvas')\n : undefined);\n this.debug = (_f = options.debug) !== null && _f !== void 0 ? _f : false;\n this.filter = options.filter;\n this.hoverVehicleId = options.hoverVehicleId;\n /**\n * If true. The layer will always use Date.now() on the next tick to render the trajectories.\n * When true, setting the time property has no effect.\n */\n this.live = options.live !== false;\n this.minZoomInterpolation = (_g = options.minZoomInterpolation) !== null && _g !== void 0 ? _g : 8; // Min zoom level from which trains positions are not interpolated.\n this.pixelRatio =\n (_h = options.pixelRatio) !== null && _h !== void 0 ? _h : (typeof window !== 'undefined' ? window.devicePixelRatio : 1);\n this.selectedVehicleId = options.selectedVehicleId;\n this.sort = options.sort;\n /**\n * Custom options to pass as last parameter of the style function.\n */\n this.styleOptions = Object.assign(Object.assign({}, defaultStyleOptions), ((_j = options.styleOptions) !== null && _j !== void 0 ? _j : {}));\n this.tenant = (_k = options.tenant) !== null && _k !== void 0 ? _k : ''; // sbb,sbh or sbm\n this.trajectories = {};\n this.useDebounce = (_l = options.useDebounce) !== null && _l !== void 0 ? _l : false;\n this.useRequestAnimationFrame = (_m = options.useRequestAnimationFrame) !== null && _m !== void 0 ? _m : false;\n this.useThrottle = options.useThrottle !== false; // the default behavior\n this.getViewState =\n (_o = options.getViewState) !== null && _o !== void 0 ? _o : (() => {\n return {};\n });\n this.shouldRender =\n (_p = options.shouldRender) !== null && _p !== void 0 ? _p : (() => {\n return true;\n });\n this.getRefreshTimeInMs =\n (_q = options.getRefreshTimeInMs) !== null && _q !== void 0 ? _q : this.getRefreshTimeInMs.bind(this);\n this.onRender = options.onRender;\n this.onIdle = options.onIdle;\n this.onStart = options.onStart;\n this.onStop = options.onStop;\n this.format = new GeoJSON();\n // Mots by zoom\n // Server will block non train before zoom 9\n this.motsByZoom = (_r = options.motsByZoom) !== null && _r !== void 0 ? _r : [\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_ONLY_RAIL,\n MOTS_WITHOUT_CABLE,\n MOTS_WITHOUT_CABLE,\n ];\n this.getMotsByZoom = (zoom) => {\n if (options.getMotsByZoom) {\n return options.getMotsByZoom(zoom, this.motsByZoom);\n }\n if (zoom > this.motsByZoom.length - 1) {\n return this.motsByZoom[this.motsByZoom.length - 1];\n }\n return this.motsByZoom[zoom];\n };\n // Generalization levels by zoom\n this.generalizationLevelByZoom = options.generalizationLevelByZoom || [];\n this.getGeneralizationLevelByZoom = (zoom) => {\n if (options.getGeneralizationLevelByZoom) {\n return options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom);\n }\n if (zoom > this.generalizationLevelByZoom.length - 1) {\n return this.generalizationLevelByZoom[this.generalizationLevelByZoom.length - 1];\n }\n return this.generalizationLevelByZoom[zoom];\n };\n // Graph by zoom\n this.graphByZoom = (_s = options.graphByZoom) !== null && _s !== void 0 ? _s : [];\n this.getGraphByZoom = (zoom) => {\n var _a, _b;\n if (options.getGraphByZoom) {\n return options.getGraphByZoom(zoom, this.graphByZoom);\n }\n if (zoom > this.graphByZoom.length - 1) {\n return (_a = this.graphByZoom) === null || _a === void 0 ? void 0 : _a[this.graphByZoom.length - 1];\n }\n return (_b = this.graphByZoom) === null || _b === void 0 ? void 0 : _b[zoom];\n };\n // Render time interval by zoom\n this.renderTimeIntervalByZoom = options.renderTimeIntervalByZoom || [\n 100000, 50000, 40000, 30000, 20000, 15000, 10000, 5000, 2000, 1000, 400,\n 300, 250, 180, 90, 60, 50, 50, 50, 50, 50,\n ];\n this.getRenderTimeIntervalByZoom = (zoom) => {\n if (options.getRenderTimeIntervalByZoom) {\n return options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom);\n }\n return this.renderTimeIntervalByZoom[zoom];\n };\n // This property will call api.setBbox on each movend event\n this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd !== false;\n // Define throttling and debounce render function\n this.throttleRenderTrajectories = throttle(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.renderTrajectoriesInternal, 50, { leading: false, trailing: true });\n this.debounceRenderTrajectories = debounce(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.renderTrajectoriesInternal, 50, { leading: true, maxWait: 5000, trailing: true });\n this.renderState = {\n center: [0, 0],\n rotation: 0,\n zoom: undefined,\n };\n this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);\n this.onDeleteTrajectoryMessage = this.onDeleteTrajectoryMessage.bind(this);\n this.onDocumentVisibilityChange =\n this.onDocumentVisibilityChange.bind(this);\n }\n /**\n * Add a trajectory.\n * @param {RealtimeTrajectory} trajectory The trajectory to add.\n * @private\n */\n addTrajectory(trajectory) {\n var _a;\n (_a = this.trajectories) !== null && _a !== void 0 ? _a : (this.trajectories = {});\n const id = trajectory.properties.train_id;\n if (id !== undefined) {\n this.trajectories[id] = trajectory;\n }\n this.renderTrajectories();\n }\n attachToMap() {\n // To avoid browser hanging when the tab is not visible for a certain amount of time,\n // We stop the rendering and the websocket when hide and start again when show.\n document.addEventListener('visibilitychange', \n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.onDocumentVisibilityChange);\n }\n detachFromMap() {\n document.removeEventListener('visibilitychange', \n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.onDocumentVisibilityChange);\n this.stop();\n if (this.canvas) {\n const context = this.canvas.getContext('2d');\n if (context) {\n context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n }\n /**\n * Get the duration before the next update depending on zoom level.\n *\n * @private\n */\n getRefreshTimeInMs() {\n var _a, _b;\n const viewState = this.getViewState();\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n const roundedZoom = zoom !== undefined ? Math.round(zoom) : -1;\n const timeStep = this.getRenderTimeIntervalByZoom(roundedZoom) || 25;\n const nextTick = Math.max(25, timeStep / (this.speed || 1));\n const nextThrottleTick = Math.min(nextTick, 500);\n // TODO: see if this should go elsewhere.\n if (this.useThrottle) {\n this.throttleRenderTrajectories = throttle(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true });\n }\n else if (this.useDebounce) {\n this.debounceRenderTrajectories = debounce(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, maxWait: 5000, trailing: true });\n }\n if ((_b = this.api) === null || _b === void 0 ? void 0 : _b.buffer) {\n const [, size] = this.api.buffer;\n this.api.buffer = [nextThrottleTick, size];\n }\n return nextTick;\n }\n /**\n * Get vehicle.\n * @param {function} filterFc A function use to filter results.\n * @return {Array} Array of vehicle.\n */\n getVehicles(filterFc) {\n return ((this.trajectories &&\n Object.values(this.trajectories).filter(filterFc)) ||\n []);\n }\n /**\n * Request feature information for a given coordinate.\n *\n * @param {ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {Object} options Options See child classes to see which options are supported.\n * @param {number} [options.resolution=1] The resolution of the map.\n * @param {number} [options.nb=Infinity] The max number of vehicles to return.\n * @return {Promise} Promise with features, layer and coordinate.\n */\n getVehiclesAtCoordinate(coordinate, options) {\n const { resolution } = this.getViewState();\n const { hitTolerance, nb } = options || {};\n const extent = buffer([...coordinate, ...coordinate], (hitTolerance !== null && hitTolerance !== void 0 ? hitTolerance : 5) * (resolution !== null && resolution !== void 0 ? resolution : 1));\n let trajectories = Object.values(this.trajectories || {});\n if (this.sort) {\n trajectories = trajectories.sort(this.sort);\n }\n const vehicles = [];\n // Theoretically 'for' is faster then 'for-of and it is important here\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < trajectories.length; i += 1) {\n const trajectory = trajectories[i];\n const { coordinate: trajcoord } = trajectory.properties;\n if (trajcoord && containsCoordinate(extent, trajcoord)) {\n vehicles.push(trajectory);\n }\n if (vehicles.length === nb) {\n break;\n }\n }\n return { features: vehicles, type: 'FeatureCollection' };\n }\n /**\n * Callback on websocket's deleted_vehicles channel events.\n * It removes the trajectory from the list.\n *\n * @private\n * @override\n */\n onDeleteTrajectoryMessage(data) {\n if (!data.content) {\n return;\n }\n this.removeTrajectory(data.content);\n }\n onDocumentVisibilityChange() {\n if (document.hidden) {\n this.stop();\n // Since we don't receive deleted_vehicles event when docuement\n // is hidden. We have to clean all the trajectories for a fresh\n // start when the document is visible again.\n this.trajectories = {};\n }\n else {\n const viewState = this.getViewState();\n if (!viewState.visible) {\n return;\n }\n this.start();\n }\n }\n /**\n * Callback on websocket's trajectory channel events.\n * It adds a trajectory to the list.\n *\n * @private\n */\n onTrajectoryMessage(data) {\n this.updateIdleState();\n if (!data.content) {\n return;\n }\n const trajectory = data.content;\n const { geometry, properties: { raw_coordinates: rawCoordinates, time_since_update: timeSinceUpdate, }, } = trajectory;\n // ignore old events [SBAHNM-97]\n // @ts-expect-error can be undefined\n if (timeSinceUpdate < 0) {\n return;\n }\n // console.time(`onTrajectoryMessage${data.content.properties.train_id}`);\n if (this.purgeTrajectory(trajectory)) {\n return;\n }\n if (this.debug &&\n this.mode === RealtimeModes.TOPOGRAPHIC &&\n rawCoordinates) {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry({\n coordinates: fromLonLat(rawCoordinates),\n type: 'Point',\n });\n }\n else {\n // @ts-expect-error missing type definition\n trajectory.properties.olGeometry = this.format.readGeometry(geometry);\n }\n // TODO Make sure the timeOffset is useful. May be we can remove it.\n // @ts-expect-error missing type definition\n trajectory.properties.timeOffset = Date.now() - data.timestamp;\n this.addTrajectory(trajectory);\n }\n /**\n * On zoomend we adjust the time interval of the update of vehicles positions.\n *\n * @private\n */\n onZoomEnd() {\n this.startUpdateTime();\n }\n /**\n * Remove all trajectories that are in the past.\n */\n purgeOutOfDateTrajectories() {\n Object.entries(this.trajectories || {}).forEach(([key, trajectory]) => {\n var _a;\n const timeIntervals = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.time_intervals;\n if (this.time && (timeIntervals === null || timeIntervals === void 0 ? void 0 : timeIntervals.length)) {\n const lastTimeInterval = timeIntervals[timeIntervals.length - 1][0];\n if (lastTimeInterval < this.time.getTime()) {\n this.removeTrajectory(key);\n }\n }\n });\n }\n /**\n * Determine if the trajectory is useless and should be removed from the list or not.\n * By default, this function exclude vehicles:\n * - that have their trajectory outside the current extent and\n * - that aren't in the MOT list.\n *\n * @param {RealtimeTrajectory} trajectory\n * @return {boolean} if the trajectory must be displayed or not.\n * @private\n */\n purgeTrajectory(trajectory) {\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const { bounds, type } = trajectory.properties;\n if ((this.isUpdateBboxOnMoveEnd && extent && !intersects(extent, bounds)) ||\n (this.mots && !this.mots.includes(type))) {\n this.removeTrajectory(trajectory);\n return true;\n }\n return false;\n }\n removeTrajectory(trajectoryOrId) {\n var _a;\n let id;\n if (typeof trajectoryOrId !== 'string') {\n id = (_a = trajectoryOrId === null || trajectoryOrId === void 0 ? void 0 : trajectoryOrId.properties) === null || _a === void 0 ? void 0 : _a.train_id;\n }\n else {\n id = trajectoryOrId;\n }\n if (id !== undefined && this.trajectories) {\n delete this.trajectories[id];\n }\n }\n /**\n * Render the trajectories requesting an animation frame and cancelling the previous one.\n * This function must be overrided by children to provide the correct parameters.\n *\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectories(noInterpolate) {\n const viewState = this.getViewState();\n if (this.requestId) {\n cancelAnimationFrame(this.requestId);\n this.requestId = undefined;\n }\n if (!(viewState === null || viewState === void 0 ? void 0 : viewState.center) || !(viewState === null || viewState === void 0 ? void 0 : viewState.extent) || !(viewState === null || viewState === void 0 ? void 0 : viewState.size)) {\n return;\n }\n if (!noInterpolate && this.useRequestAnimationFrame) {\n this.requestId = requestAnimationFrame(() => {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n });\n }\n else if (!noInterpolate && this.useDebounce) {\n this.debounceRenderTrajectories(viewState, noInterpolate);\n }\n else if (!noInterpolate && this.useThrottle) {\n this.throttleRenderTrajectories(viewState, noInterpolate);\n }\n else {\n this.renderTrajectoriesInternal(viewState, noInterpolate);\n }\n }\n /**\n * Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.\n *\n * @param {object} viewState The view state of the map.\n * @param {number[2]} viewState.center Center coordinate of the map in mercator coordinate.\n * @param {number[4]} viewState.extent Extent of the map in mercator coordinates.\n * @param {number[2]} viewState.size Size ([width, height]) of the canvas to render.\n * @param {number} [viewState.rotation = 0] Rotation of the map to render.\n * @param {number} viewState.resolution Resolution of the map to render.\n * @param {boolean} noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\n renderTrajectoriesInternal(viewState, noInterpolate = false) {\n var _a;\n if (!this.trajectories || !this.shouldRender()) {\n return false;\n }\n let time = new Date();\n if (this.live) {\n // Save the time internally, to keep trace of the time rendered for purge.\n this._time = time;\n }\n else if (this.time) {\n time = this.time;\n }\n const trajectories = Object.values(this.trajectories);\n // console.time('sort');\n if (this.sort) {\n trajectories.sort(this.sort);\n }\n // console.timeEnd('sort');\n if (!this.canvas || !this.style) {\n return true;\n }\n this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time: time.getTime() }), Object.assign(Object.assign({}, this.styleOptions), { filter: this.filter, hoverVehicleId: this.hoverVehicleId, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation\n ? true\n : noInterpolate, selectedVehicleId: this.selectedVehicleId }));\n (_a = this.onRender) === null || _a === void 0 ? void 0 : _a.call(this, this.renderState, viewState);\n // console.timeEnd('render');\n return true;\n }\n setBbox() {\n var _a;\n this.updateIdleState();\n const viewState = this.getViewState();\n const extent = viewState.extent;\n const zoom = (_a = viewState.zoom) !== null && _a !== void 0 ? _a : 0;\n if (!extent || Number.isNaN(zoom)) {\n return;\n }\n // Clean trajectories before sending the new bbox\n // Purge trajectories:\n // - which are outside the extent\n // - when it's bus and zoom level is too low for them\n if (this.trajectories && extent && zoom) {\n const keys = Object.keys(this.trajectories);\n for (let i = keys.length - 1; i >= 0; i -= 1) {\n this.purgeTrajectory(this.trajectories[keys[i]]);\n }\n }\n // The backend only supports non float value\n const zoomFloor = Math.floor(zoom);\n if (!extent || Number.isNaN(zoomFloor)) {\n return;\n }\n // The extent does not need to be precise under meter, so we round floor/ceil the values.\n const [minX, minY, maxX, maxY] = extent;\n const bbox = [\n Math.floor(minX),\n Math.floor(minY),\n Math.ceil(maxX),\n Math.ceil(maxY),\n zoomFloor,\n ];\n /* @private */\n this.generalizationLevel = this.getGeneralizationLevelByZoom(zoomFloor);\n if (this.generalizationLevel) {\n bbox.push(`gen=${this.generalizationLevel}`);\n }\n /* @private */\n this.mots = this.getMotsByZoom(zoomFloor);\n if (this.mots) {\n bbox.push(`mots=${this.mots.toString()}`);\n }\n if (this.tenant) {\n bbox.push(`tenant=${this.tenant}`);\n }\n if (this.mode !== 'topographic') {\n bbox.push(`channel_prefix=${this.mode}`);\n }\n const graph = this.getGraphByZoom(zoomFloor);\n if (graph) {\n bbox.push(`graph=${graph}`);\n }\n if (this.bboxParameters) {\n Object.entries(this.bboxParameters).forEach(([key, value]) => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n bbox.push(`${key}=${value}`);\n });\n }\n // Extent and zoom level are mandatory.\n this.api.bbox = bbox;\n }\n start() {\n this.stop();\n // Before starting to update trajectories, we remove trajectories that have\n // a time_intervals in the past, it will\n // avoid phantom train that are at the end of their route because we never\n // received the deleted_vehicle event because we have changed the browser tab.\n this.purgeOutOfDateTrajectories();\n this.renderTrajectories();\n this.startUpdateTime();\n this.api.open();\n this.api.subscribeTrajectory(this.mode, \n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n this.api.subscribeDeletedVehicles(this.mode, \n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd);\n // Update the bbox on each move end\n if (this.isUpdateBboxOnMoveEnd) {\n this.setBbox();\n }\n if (this.onStart) {\n this.onStart(this);\n }\n }\n /**\n * Start the clock.\n * @private\n */\n startUpdateTime() {\n this.stopUpdateTime();\n this.updateTimeDelay = this.getRefreshTimeInMs() || 0;\n this.updateTimeInterval = window.setInterval(() => {\n // When live=true, we update the time with new Date();\n if (this.live) {\n this.time = new Date();\n }\n else if (this.time && this.updateTimeDelay && this.speed) {\n this.time = new Date(this.time.getTime() + this.updateTimeDelay * this.speed);\n }\n }, this.updateTimeDelay);\n }\n stop() {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.api.unsubscribeTrajectory(this.onTrajectoryMessage);\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage);\n this.api.close();\n if (this.onStop) {\n this.onStop(this);\n }\n }\n /**\n * Stop the clock.\n * @private\n */\n stopUpdateTime() {\n if (this.updateTimeInterval) {\n clearInterval(this.updateTimeInterval);\n this.updateTimeInterval = undefined;\n }\n }\n updateIdleState() {\n this.isIdle = false;\n clearTimeout(this._idleTimeout);\n this._idleTimeout = window.setTimeout(() => {\n var _a;\n this.isIdle = true;\n (_a = this.onIdle) === null || _a === void 0 ? void 0 : _a.call(this, this);\n }, 1000);\n }\n}\nexport default RealtimeEngine;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/RealtimeEngine.js", "access": "private", @@ -7220,7 +7220,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#debounceRenderTrajectories", "access": "private", "description": null, - "lineNumber": 205, + "lineNumber": 207, "undocument": true, "type": { "types": [ @@ -7237,7 +7237,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#renderState", "access": "private", "description": null, - "lineNumber": 206, + "lineNumber": 210, "undocument": true, "type": { "types": [ @@ -7256,7 +7256,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#addTrajectory", "access": "private", "description": "Add a trajectory.", - "lineNumber": 221, + "lineNumber": 225, "params": [ { "nullable": null, @@ -7272,7 +7272,7 @@ "return": null }, { - "__docId__": 337, + "__docId__": 336, "kind": "method", "name": "attachToMap", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7282,13 +7282,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#attachToMap", "access": "private", "description": null, - "lineNumber": 231, + "lineNumber": 234, "undocument": true, "params": [], "return": null }, { - "__docId__": 338, + "__docId__": 337, "kind": "method", "name": "detachFromMap", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7298,13 +7298,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#detachFromMap", "access": "private", "description": null, - "lineNumber": 236, + "lineNumber": 241, "undocument": true, "params": [], "return": null }, { - "__docId__": 339, + "__docId__": 338, "kind": "method", "name": "getRefreshTimeInMs", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7314,7 +7314,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#getRefreshTimeInMs", "access": "private", "description": "Get the duration before the next update depending on zoom level.", - "lineNumber": 251, + "lineNumber": 258, "params": [], "return": { "types": [ @@ -7323,7 +7323,7 @@ } }, { - "__docId__": 342, + "__docId__": 341, "kind": "method", "name": "getVehicles", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7333,7 +7333,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#getVehicles", "access": "private", "description": "Get vehicle.", - "lineNumber": 277, + "lineNumber": 288, "params": [ { "nullable": null, @@ -7356,7 +7356,7 @@ } }, { - "__docId__": 343, + "__docId__": 342, "kind": "method", "name": "getVehiclesAtCoordinate", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7366,7 +7366,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#getVehiclesAtCoordinate", "access": "private", "description": "Request feature information for a given coordinate.", - "lineNumber": 292, + "lineNumber": 302, "params": [ { "nullable": null, @@ -7423,7 +7423,7 @@ } }, { - "__docId__": 344, + "__docId__": 343, "kind": "method", "name": "onDeleteTrajectoryMessage", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7433,7 +7433,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#onDeleteTrajectoryMessage", "access": "private", "description": "Callback on websocket's deleted_vehicles channel events.\nIt removes the trajectory from the list.", - "lineNumber": 323, + "lineNumber": 332, "override": true, "params": [ { @@ -7446,7 +7446,7 @@ "return": null }, { - "__docId__": 345, + "__docId__": 344, "kind": "method", "name": "onDocumentVisibilityChange", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7456,13 +7456,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#onDocumentVisibilityChange", "access": "private", "description": null, - "lineNumber": 329, + "lineNumber": 338, "undocument": true, "params": [], "return": null }, { - "__docId__": 347, + "__docId__": 346, "kind": "method", "name": "onTrajectoryMessage", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7472,7 +7472,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#onTrajectoryMessage", "access": "private", "description": "Callback on websocket's trajectory channel events.\nIt adds a trajectory to the list.", - "lineNumber": 351, + "lineNumber": 360, "params": [ { "name": "data", @@ -7484,7 +7484,7 @@ "return": null }, { - "__docId__": 348, + "__docId__": 347, "kind": "method", "name": "onZoomEnd", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7494,12 +7494,12 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#onZoomEnd", "access": "private", "description": "On zoomend we adjust the time interval of the update of vehicles positions.", - "lineNumber": 390, + "lineNumber": 399, "params": [], "return": null }, { - "__docId__": 349, + "__docId__": 348, "kind": "method", "name": "purgeOutOfDateTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7509,12 +7509,12 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#purgeOutOfDateTrajectories", "access": "private", "description": "Remove all trajectories that are in the past.", - "lineNumber": 396, + "lineNumber": 405, "params": [], "return": null }, { - "__docId__": 350, + "__docId__": 349, "kind": "method", "name": "purgeTrajectory", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7524,7 +7524,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#purgeTrajectory", "access": "private", "description": "Determine if the trajectory is useless and should be removed from the list or not.\nBy default, this function exclude vehicles:\n - that have their trajectory outside the current extent and\n - that aren't in the MOT list.", - "lineNumber": 418, + "lineNumber": 427, "params": [ { "nullable": null, @@ -7547,7 +7547,7 @@ } }, { - "__docId__": 351, + "__docId__": 350, "kind": "method", "name": "removeTrajectory", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7557,7 +7557,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#removeTrajectory", "access": "private", "description": null, - "lineNumber": 429, + "lineNumber": 438, "undocument": true, "params": [ { @@ -7570,7 +7570,7 @@ "return": null }, { - "__docId__": 352, + "__docId__": 351, "kind": "method", "name": "renderTrajectories", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7580,7 +7580,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#renderTrajectories", "access": "private", "description": "Render the trajectories requesting an animation frame and cancelling the previous one.\nThis function must be overrided by children to provide the correct parameters.", - "lineNumber": 451, + "lineNumber": 460, "params": [ { "nullable": null, @@ -7596,7 +7596,7 @@ "return": null }, { - "__docId__": 353, + "__docId__": 352, "kind": "member", "name": "requestId", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7604,7 +7604,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#requestId", "access": "private", "description": null, - "lineNumber": 455, + "lineNumber": 464, "undocument": true, "type": { "types": [ @@ -7613,7 +7613,7 @@ } }, { - "__docId__": 355, + "__docId__": 354, "kind": "method", "name": "renderTrajectoriesInternal", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7623,7 +7623,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#renderTrajectoriesInternal", "access": "private", "description": "Launch renderTrajectories. it avoids duplicating code in renderTrajectories method.", - "lineNumber": 489, + "lineNumber": 498, "params": [ { "nullable": null, @@ -7705,7 +7705,7 @@ } }, { - "__docId__": 358, + "__docId__": 357, "kind": "method", "name": "setBbox", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7715,13 +7715,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#setBbox", "access": "private", "description": null, - "lineNumber": 519, + "lineNumber": 527, "undocument": true, "params": [], "return": null }, { - "__docId__": 359, + "__docId__": 358, "kind": "member", "name": "generalizationLevel", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7729,7 +7729,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#generalizationLevel", "access": "private", "description": null, - "lineNumber": 553, + "lineNumber": 561, "undocument": true, "type": { "types": [ @@ -7738,7 +7738,7 @@ } }, { - "__docId__": 360, + "__docId__": 359, "kind": "member", "name": "mots", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7746,7 +7746,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#mots", "access": "private", "description": null, - "lineNumber": 558, + "lineNumber": 566, "undocument": true, "type": { "types": [ @@ -7755,7 +7755,7 @@ } }, { - "__docId__": 361, + "__docId__": 360, "kind": "method", "name": "start", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7765,13 +7765,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#start", "access": "private", "description": null, - "lineNumber": 581, + "lineNumber": 589, "undocument": true, "params": [], "return": null }, { - "__docId__": 362, + "__docId__": 361, "kind": "method", "name": "startUpdateTime", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7781,12 +7781,12 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#startUpdateTime", "access": "private", "description": "Start the clock.", - "lineNumber": 605, + "lineNumber": 617, "params": [], "return": null }, { - "__docId__": 363, + "__docId__": 362, "kind": "member", "name": "updateTimeDelay", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7794,7 +7794,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#updateTimeDelay", "access": "private", "description": null, - "lineNumber": 607, + "lineNumber": 619, "undocument": true, "type": { "types": [ @@ -7803,7 +7803,7 @@ } }, { - "__docId__": 364, + "__docId__": 363, "kind": "member", "name": "updateTimeInterval", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7811,7 +7811,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#updateTimeInterval", "access": "private", "description": null, - "lineNumber": 608, + "lineNumber": 620, "undocument": true, "type": { "types": [ @@ -7820,7 +7820,7 @@ } }, { - "__docId__": 367, + "__docId__": 366, "kind": "method", "name": "stop", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7830,13 +7830,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#stop", "access": "private", "description": null, - "lineNumber": 618, + "lineNumber": 630, "undocument": true, "params": [], "return": null }, { - "__docId__": 368, + "__docId__": 367, "kind": "method", "name": "stopUpdateTime", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7846,12 +7846,12 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#stopUpdateTime", "access": "private", "description": "Stop the clock.", - "lineNumber": 630, + "lineNumber": 644, "params": [], "return": null }, { - "__docId__": 370, + "__docId__": 369, "kind": "method", "name": "updateIdleState", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7861,13 +7861,13 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#updateIdleState", "access": "private", "description": null, - "lineNumber": 636, + "lineNumber": 650, "undocument": true, "params": [], "return": null }, { - "__docId__": 372, + "__docId__": 371, "kind": "member", "name": "_idleTimeout", "memberof": "build/common/utils/RealtimeEngine.js~RealtimeEngine", @@ -7875,7 +7875,7 @@ "longname": "build/common/utils/RealtimeEngine.js~RealtimeEngine#_idleTimeout", "access": "private", "description": null, - "lineNumber": 639, + "lineNumber": 653, "undocument": true, "type": { "types": [ @@ -7884,7 +7884,7 @@ } }, { - "__docId__": 374, + "__docId__": 373, "kind": "file", "name": "build/common/utils/compareDepartures.js", "content": "/**\n * Compare two given departures for sort alogithm,\n * @param {RealtimeDeparture} a First departure.\n * @param {RealtimeDeparture} b Second departure.\n * @param {boolean} [sortByMinArrivalTime=false] Sort departures by arrival time.\n * @private\n */\nconst compareDepartures = (a, b, sortByMinArrivalTime = false) => {\n // First LEAVING and HIDDEN, then BOARDING and then sorted by time.\n const topStates = ['HIDDEN', 'LEAVING', 'BOARDING'];\n const aTop = a.has_fzo && topStates.includes(a.state);\n const bTop = b.has_fzo && topStates.includes(b.state);\n if (aTop || bTop) {\n if (aTop !== bTop) {\n return aTop ? -1 : 1;\n }\n if (a.state !== b.state) {\n // one is leaving\n return topStates.indexOf(a.state) - topStates.indexOf(b.state);\n }\n }\n let aDuration = null;\n let bDuration = null;\n const now = Date.now();\n if (sortByMinArrivalTime) {\n const aTime = a.min_arrival_time || a.time;\n const bTime = b.min_arrival_time || b.time;\n if (!aTime && !bTime) {\n return 0;\n }\n if (!aTime) {\n return 1;\n }\n if (!bTime) {\n return -1;\n }\n if (aTime && bTime) {\n aDuration = new Date(aTime).getTime() - now;\n bDuration = new Date(bTime).getTime() - now;\n }\n }\n else {\n if (!a.time && !b.time) {\n return 0;\n }\n if (!a.time) {\n return 1;\n }\n if (!b.time) {\n return -1;\n }\n if (a.time && b.time) {\n aDuration = new Date(a.time).getTime() - now;\n bDuration = new Date(b.time).getTime() - now;\n }\n }\n if (!aDuration && !bDuration) {\n return 0;\n }\n if (!aDuration) {\n return 1;\n }\n if (!bDuration) {\n return -1;\n }\n return aDuration - bDuration;\n};\nexport default compareDepartures;\n", @@ -7895,7 +7895,7 @@ "lineNumber": 1 }, { - "__docId__": 375, + "__docId__": 374, "kind": "function", "name": "compareDepartures", "memberof": "build/common/utils/compareDepartures.js", @@ -7950,7 +7950,7 @@ } }, { - "__docId__": 376, + "__docId__": 375, "kind": "file", "name": "build/common/utils/constants.js", "content": "export const VECTOR_TILE_FEATURE_PROPERTY = 'vectorTileFeature';\nexport default {\n VECTOR_TILE_FEATURE_PROPERTY,\n};\n", @@ -7961,7 +7961,7 @@ "lineNumber": 1 }, { - "__docId__": 377, + "__docId__": 376, "kind": "variable", "name": "VECTOR_TILE_FEATURE_PROPERTY", "memberof": "build/common/utils/constants.js", @@ -7981,7 +7981,7 @@ } }, { - "__docId__": 378, + "__docId__": 377, "kind": "file", "name": "build/common/utils/createCanvas.js", "content": "/**\n * This function try to create a canvas element and return it.\n * it uses document.createElement('canvas') if document is available\n * or new OffscreenCanvas(width, height) if OffscreenCanvas is avalaible (for web worker)\n * or it returns null if neither is available.\n * @private\n */\nconst createCanvas = (width, height) => {\n let canvas = null;\n // Prevent SSR errors\n if (typeof window === 'undefined') {\n return null;\n }\n if (typeof document !== 'undefined' && (document === null || document === void 0 ? void 0 : document.createElement)) {\n canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n }\n else if (OffscreenCanvas) {\n canvas = new OffscreenCanvas(width, height);\n }\n else {\n // eslint-disable-next-line no-console\n console.error(\"We didn't find a way to create a canvas element, document.createElement('canvas') and new OffscrenCanvas() are not supported\");\n }\n return canvas;\n};\nexport default createCanvas;\n", @@ -7992,7 +7992,7 @@ "lineNumber": 1 }, { - "__docId__": 379, + "__docId__": 378, "kind": "function", "name": "createCanvas", "memberof": "build/common/utils/createCanvas.js", @@ -8027,7 +8027,7 @@ } }, { - "__docId__": 380, + "__docId__": 379, "kind": "file", "name": "build/common/utils/createDefaultCopyrightElt.js", "content": "/**\n * @private\n */\nconst createDefaultCopyrightElement = () => {\n const element = document.createElement('div');\n Object.assign(element.style, {\n bottom: 0,\n fontSize: '.8rem',\n padding: '0 10px',\n position: 'absolute',\n right: 0,\n });\n return element;\n};\nexport default createDefaultCopyrightElement;\n", @@ -8038,7 +8038,7 @@ "lineNumber": 1 }, { - "__docId__": 381, + "__docId__": 380, "kind": "function", "name": "createDefaultCopyrightElement", "memberof": "build/common/utils/createDefaultCopyrightElt.js", @@ -8060,7 +8060,7 @@ } }, { - "__docId__": 382, + "__docId__": 381, "kind": "file", "name": "build/common/utils/createDefaultStopFinderElt.js", "content": "/**\n * @private\n */\nconst createDefaultStopFinderElement = () => {\n const element = document.createElement('div');\n Object.assign(element.style, {\n display: 'flex',\n flexDirection: 'column',\n left: '50px',\n margin: '10px',\n maxHeight: '90%',\n position: 'absolute',\n top: 0,\n width: '320px',\n });\n return element;\n};\nexport default createDefaultStopFinderElement;\n", @@ -8071,7 +8071,7 @@ "lineNumber": 1 }, { - "__docId__": 383, + "__docId__": 382, "kind": "function", "name": "createDefaultStopFinderElement", "memberof": "build/common/utils/createDefaultStopFinderElt.js", @@ -8093,7 +8093,7 @@ } }, { - "__docId__": 384, + "__docId__": 383, "kind": "file", "name": "build/common/utils/createRealtimeFilters.js", "content": "/**\n * Return a filter functions based on some parameters of a vehicle.\n *\n * @param {string|Array} line - A list of vehicle's name to filter. Names can be separated by a comma. Ex: 'S1,S2,S3'\n * @param {string|Array {\n const filterList = [];\n if (!line && !route && !operator && !regexLine) {\n return null;\n }\n if (regexLine) {\n const regexLineList = typeof regexLine === 'string' ? [regexLine] : regexLine;\n const lineFilter = (item) => {\n var _a;\n const name = item.properties.name || ((_a = item.properties.line) === null || _a === void 0 ? void 0 : _a.name) || '';\n if (!name) {\n return false;\n }\n return regexLineList.some((regexStr) => {\n return new RegExp(regexStr, 'i').test(name);\n });\n };\n filterList.push(lineFilter);\n }\n if (line) {\n const lineFiltersList = typeof line === 'string' ? line.split(',') : line;\n const lineList = lineFiltersList.map((l) => {\n return l.replace(/\\s+/g, '').toUpperCase();\n });\n const lineFilter = (item) => {\n const { line: linee, name } = item.properties;\n const lineName = (name || (linee === null || linee === void 0 ? void 0 : linee.name) || '').toUpperCase();\n if (!lineName) {\n return false;\n }\n return lineList.includes(lineName);\n };\n filterList.push(lineFilter);\n }\n if (route) {\n const routes = typeof route === 'string' ? route.split(',') : route;\n const routeList = routes.map((item) => {\n return parseInt(item, 10);\n });\n const routeFilter = (item) => {\n const routeIdentifier = item.properties.route_identifier || '';\n const routeId = parseInt(routeIdentifier.split('.')[0], 10);\n return routeList.includes(routeId);\n };\n filterList.push(routeFilter);\n }\n if (operator) {\n const operatorList = typeof operator === 'string' ? [operator] : operator;\n const operatorFilter = (item) => {\n return operatorList.some((op) => {\n // operaotr is the old property tenant is the new one\n const tenant = item.properties.operator || item.properties.tenant || '';\n return new RegExp(op, 'i').test(tenant);\n });\n };\n filterList.push(operatorFilter);\n }\n if (!filterList.length) {\n return null;\n }\n return (item) => {\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < filterList.length; i += 1) {\n if (!filterList[i](item)) {\n return false;\n }\n }\n return true;\n };\n};\nexport default createRealtimeFilters;\n", @@ -8104,7 +8104,7 @@ "lineNumber": 1 }, { - "__docId__": 385, + "__docId__": 384, "kind": "function", "name": "createRealtimeFilters", "memberof": "build/common/utils/createRealtimeFilters.js", @@ -8170,7 +8170,7 @@ } }, { - "__docId__": 386, + "__docId__": 385, "kind": "file", "name": "build/common/utils/debounceDeparturesMessages.js", "content": "import sortAndFilterDepartures from './sortAndFilterDepartures';\n/**\n * This function returns a WebSocket api callback, and call the onDeparturesUpdate function with the list of current departures to display.\n * @param {function(departures: RealtimeDeparture[])} onDeparturesUpdate callback when list of departures changes, called after 100 ms\n * @param {boolean} [sortByMinArrivalTime = true] Sort departures by arrival time\n * @param {number} [maxDepartureAge = 30] max departure age of departures in minutes\n * @param {number} [timeout = 100] debounce timeout in ms\n * @private\n */\nconst debounceDeparturesMessages = (onDeparturesUpdate, sortByMinArrivalTime = false, maxDepartureAge = 30, timeout = 100) => {\n const departureUpdateTimeout = {};\n const departureObject = {};\n return (data) => {\n const { content: departure, source } = data;\n if (departureUpdateTimeout[source]) {\n window.clearTimeout(departureUpdateTimeout[source]);\n }\n if (!departure) {\n return;\n }\n departureObject[departure.call_id] = departure;\n departureUpdateTimeout[source] = window.setTimeout(() => {\n const departures = sortAndFilterDepartures(departureObject, sortByMinArrivalTime || false, maxDepartureAge);\n onDeparturesUpdate(departures);\n }, timeout);\n };\n};\nexport default debounceDeparturesMessages;\n", @@ -8181,7 +8181,7 @@ "lineNumber": 1 }, { - "__docId__": 387, + "__docId__": 386, "kind": "function", "name": "debounceDeparturesMessages", "memberof": "build/common/utils/debounceDeparturesMessages.js", @@ -8250,7 +8250,7 @@ } }, { - "__docId__": 388, + "__docId__": 387, "kind": "file", "name": "build/common/utils/debounceWebsocketMessages.js", "content": "/**\n * This function returns a WebSocket api callback, and call the onUpdate function with the list of of subscribed objects changes.\n *\n * @param {function(objects: any[])} onUpdate callback when list of subscribed objects changes, called after 100 ms\n * @param {function(object: any)} [getObjectId = true] function returning the id of an object\n * @param {number} [timeout = 100] debounce timeout in ms\n * @private\n */\nconst debounceWebsocketMessages = (onUpdate, getObjectId, timeout = 100) => {\n const updateTimeout = {};\n const objectsById = {};\n const objects = [];\n return (data) => {\n const { content, source } = data;\n if (updateTimeout[source]) {\n window.clearTimeout(updateTimeout[source]);\n }\n if (getObjectId) {\n objectsById[getObjectId(content)] = content;\n }\n else {\n objects.push(content);\n }\n updateTimeout[source] = window.setTimeout(() => {\n const objectToReturn = getObjectId ? Object.values(objectsById) : objects;\n onUpdate(objectToReturn);\n }, timeout);\n };\n};\nexport default debounceWebsocketMessages;\n", @@ -8261,7 +8261,7 @@ "lineNumber": 1 }, { - "__docId__": 389, + "__docId__": 388, "kind": "function", "name": "debounceWebsocketMessages", "memberof": "build/common/utils/debounceWebsocketMessages.js", @@ -8318,7 +8318,7 @@ } }, { - "__docId__": 390, + "__docId__": 389, "kind": "file", "name": "build/common/utils/getLayersAsFlatArray.js", "content": "const getLayersAsFlatArray = (layersOrLayer) => {\n let layers = layersOrLayer;\n if (!Array.isArray(layers)) {\n layers = [layersOrLayer];\n }\n let flatLayers = [];\n layers.forEach((layer) => {\n var _a, _b, _c;\n flatLayers.push(layer);\n // Handle children property and ol.layer.Group\n const children = \n // @ts-expect-error children is deprecated\n layer.children ||\n layer.get('children') ||\n ((_c = (_b = (_a = layer).getLayers) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.getArray());\n flatLayers = flatLayers.concat(getLayersAsFlatArray(children || []));\n });\n return flatLayers;\n};\nexport default getLayersAsFlatArray;\n", @@ -8329,7 +8329,7 @@ "lineNumber": 1 }, { - "__docId__": 391, + "__docId__": 390, "kind": "function", "name": "getLayersAsFlatArray", "memberof": "build/common/utils/getLayersAsFlatArray.js", @@ -8359,7 +8359,7 @@ } }, { - "__docId__": 392, + "__docId__": 391, "kind": "file", "name": "build/common/utils/getMapGlCopyrights.js", "content": "import removeDuplicate from './removeDuplicate';\n/**\n * Return the copyright a Maplibre map.\n * @param {maplibregl.Map} map A Maplibre map\n * @private\n */\nconst getMapGlCopyrights = (map) => {\n if (!map) {\n return [];\n }\n const { style } = map;\n if (!style) {\n return [];\n }\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n const { sourceCaches, tileManagers } = style;\n let copyrights = [];\n const sourceCacheObj = tileManagers || sourceCaches || {};\n Object.values(sourceCacheObj).forEach((value) => {\n var _a;\n if (value.used) {\n const source = value.getSource();\n const attribution = (source === null || source === void 0 ? void 0 : source.attribution) ||\n ((_a = source.options) === null || _a === void 0 ? void 0 : _a.attribution);\n if (attribution) {\n copyrights = copyrights.concat(attribution.replace(/©/g, '©').split(/()/));\n }\n }\n });\n return removeDuplicate(copyrights);\n};\nexport default getMapGlCopyrights;\n", @@ -8370,7 +8370,7 @@ "lineNumber": 1 }, { - "__docId__": 393, + "__docId__": 392, "kind": "function", "name": "getMapGlCopyrights", "memberof": "build/common/utils/getMapGlCopyrights.js", @@ -8403,7 +8403,7 @@ } }, { - "__docId__": 394, + "__docId__": 393, "kind": "file", "name": "build/common/utils/getRealtimeModeSuffix.js", "content": "/**\n * Get the websocket channel suffix, depending on the current mode.\n * @param {String} mode Mode 'topographic' ou 'schematic'.\n * @param {String[]} modes List of modes\n * @private\n */\nconst getModeSuffix = (mode, modes) => {\n return mode === modes.SCHEMATIC ? '_schematic' : '';\n};\nexport default getModeSuffix;\n", @@ -8414,7 +8414,7 @@ "lineNumber": 1 }, { - "__docId__": 395, + "__docId__": 394, "kind": "function", "name": "getModeSuffix", "memberof": "build/common/utils/getRealtimeModeSuffix.js", @@ -8457,7 +8457,7 @@ } }, { - "__docId__": 396, + "__docId__": 395, "kind": "file", "name": "build/common/utils/getUrlWithParams.js", "content": "/**\n * Return the styleUrl with apiKey parameters set.\n * @param {string} url a url.\n * @param {Object} params a list of key/value pair to add to the url.\n * @private\n */\nconst getUrlWithParams = (url, params) => {\n // Clean requets parameters, removing undefined and null values.\n const newUrl = new URL(url);\n const searchParams = params || {};\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n newUrl.searchParams.set(key, value);\n }\n });\n return newUrl;\n};\nexport default getUrlWithParams;\n", @@ -8468,7 +8468,7 @@ "lineNumber": 1 }, { - "__docId__": 397, + "__docId__": 396, "kind": "function", "name": "getUrlWithParams", "memberof": "build/common/utils/getUrlWithParams.js", @@ -8511,7 +8511,7 @@ } }, { - "__docId__": 398, + "__docId__": 397, "kind": "file", "name": "build/common/utils/getUrlWithPath.js", "content": "/**\n * Concatenate an url with a path to avoid double slash.\n * @param {string} url a url.\n * @param {string} path a path.\n * @param {Object} params a list of key/value pair to add to the url.\n * @private\n */\nconst getUrlWithPath = (url, path) => {\n const urlObj = new URL(url);\n let newUrl = url;\n let newPath = path;\n if (urlObj.searchParams.size > 0) {\n newUrl = url.split('?')[0];\n }\n if (!newUrl.endsWith('/')) {\n newUrl = `${newUrl}/`;\n }\n if (newPath === null || newPath === void 0 ? void 0 : newPath.startsWith('/')) {\n newPath = newPath.substring(1);\n }\n return newUrl + (newPath !== null && newPath !== void 0 ? newPath : '');\n};\nexport default getUrlWithPath;\n", @@ -8522,7 +8522,7 @@ "lineNumber": 1 }, { - "__docId__": 399, + "__docId__": 398, "kind": "function", "name": "getUrlWithPath", "memberof": "build/common/utils/getUrlWithPath.js", @@ -8575,7 +8575,7 @@ } }, { - "__docId__": 400, + "__docId__": 399, "kind": "file", "name": "build/common/utils/getVehiclePosition.js", "content": "import { LineString } from 'ol/geom';\n/**\n * Interpolate or not the vehicle position from a trajectory at a specific date.\n *\n * @param {number} now Current date to interpolate a position with. In ms.\n * @param {RealtimeTrajectory} trajectory The trajectory to interpolate.\n * @param {boolean} noInterpolate If true, the vehicle position is not interpolated on each render but only once.\n * @returns {VehiclePosition}\n * @private\n */\nconst getVehiclePosition = (now, trajectory, noInterpolate) => {\n var _a;\n const { coordinate, olGeometry, rotation: oldRotation, time_intervals: timeIntervals, } = trajectory.properties;\n let { coordinates, type } = trajectory.geometry;\n let geometry = olGeometry;\n let coord;\n let rotation = oldRotation;\n // If an olGeometry exists we use it. It avoids to create one each time.\n if (geometry) {\n // @ts-expect-error improve types\n type = geometry.getType();\n coordinates = (_a = geometry.getCoordinates()) !== null && _a !== void 0 ? _a : [];\n }\n if (noInterpolate && coordinate) {\n coord = coordinate;\n }\n else if (type === 'Point') {\n coord = coordinates;\n }\n else if (type === 'LineString') {\n geometry !== null && geometry !== void 0 ? geometry : (geometry = new LineString(coordinates));\n const intervals = timeIntervals || [[]];\n const firstInterval = intervals[0];\n const lastInterval = intervals[intervals.length - 1];\n // Between the last time interval of a trajectory event and the beginning\n // of the new trajectory event, there is few seconds, can be 6 to 30\n // seconds (that's why the vehicle jumps sometimes).\n // So we make the choice here to display the last (or the first) position\n // of an trajectory event instead of removing them, if the current date is\n // outside the time intervals we display the vehicle at the last (or first) position known.\n if (now < firstInterval[0]) {\n // Display first position known.\n [, , rotation] = firstInterval;\n coord = geometry.getFirstCoordinate();\n }\n else if (now > lastInterval[0]) {\n // Display last position known.\n [, , rotation] = lastInterval;\n coord = geometry.getLastCoordinate();\n }\n else {\n // Interpolate position using time intervals.\n for (let j = 0; j < intervals.length - 1; j += 1) {\n // Rotation only available in realtime layer.\n const [start, startFrac] = intervals[j];\n const [end, endFrac] = intervals[j + 1];\n if (start <= now && now <= end) {\n // interpolate position inside the time interval.\n const timeFrac = Math.min((now - start) / (end - start), 1);\n const geomFrac = timeFrac * (endFrac - startFrac) + startFrac;\n coord = geometry === null || geometry === void 0 ? void 0 : geometry.getCoordinateAt(geomFrac);\n [, , rotation] = intervals[j];\n break;\n }\n }\n }\n }\n else {\n // eslint-disable-next-line no-console\n console.error('This geometry type is not supported. Only Point or LineString are. Current geometry: ', geometry);\n }\n return { coord, rotation };\n};\nexport default getVehiclePosition;\n", @@ -8586,7 +8586,7 @@ "lineNumber": 1 }, { - "__docId__": 401, + "__docId__": 400, "kind": "function", "name": "getVehiclePosition", "memberof": "build/common/utils/getVehiclePosition.js", @@ -8648,7 +8648,7 @@ } }, { - "__docId__": 402, + "__docId__": 401, "kind": "file", "name": "build/common/utils/index.js", "content": "export { default as compareDepartures } from './compareDepartures';\nexport * from './constants';\nexport { default as createCanvas } from './createCanvas';\nexport { default as createRealtimeFilters } from './createRealtimeFilters';\nexport { default as debounceDeparturesMessages } from './debounceDeparturesMessages';\nexport { default as debounceWebsocketMessages } from './debounceWebsocketMessages';\nexport { default as getLayersAsFlatArray } from './getLayersAsFlatArray';\nexport { default as getMapGlCopyrights } from './getMapGlCopyrights';\nexport { default as getUrlWithParams } from './getUrlWithParams';\nexport { default as getVehiclePosition } from './getVehiclePosition';\nexport * from './mocoUtils';\nimport * as realtimeConfig_1 from './realtimeStyleUtils';\nexport { realtimeConfig_1 as realtimeConfig };\nimport * as realtimeStyleUtils_1 from './realtimeStyleUtils';\nexport { realtimeStyleUtils_1 as realtimeStyleUtils };\nexport { default as removeDuplicate } from './removeDuplicate';\nexport { default as renderTrajectories } from './renderTrajectories';\nexport { default as sortAndFilterDepartures } from './sortAndFilterDepartures';\nexport { default as sortByDelay } from './sortByDelay';\nexport * from './timeUtils';\n", @@ -8659,7 +8659,7 @@ "lineNumber": 1 }, { - "__docId__": 403, + "__docId__": 402, "kind": "file", "name": "build/common/utils/mocoUtils.js", "content": "import { getCenter } from 'ol/extent';\nimport GeoJSONFormat from 'ol/format/GeoJSON';\nimport { v4 as uuid } from 'uuid';\nexport const getTime = (str) => {\n return parseInt(str === null || str === void 0 ? void 0 : str.substr(0, 8).replace(/:/g, ''), 10);\n};\nconst geojson = new GeoJSONFormat();\n/**\n * Determines if the current date is within an affected time intervals of a situation.\n */\nexport const isMocoSituationAffected = (situation, now = new Date()) => {\n var _a;\n return !!((_a = situation.affectedTimeIntervals) === null || _a === void 0 ? void 0 : _a.some((affectedTimeInterval) => {\n const { dailyEndTime = '', dailyStartTime = '', endTime, startTime, } = affectedTimeInterval;\n const nowTime = getTime(now.toTimeString());\n const dailyStart = getTime(dailyStartTime);\n const dailyEnd = getTime(dailyEndTime);\n const inRange = new Date(startTime) <= now && now <= new Date(endTime);\n return dailyStart && dailyEnd\n ? inRange && dailyStart <= nowTime && nowTime <= dailyEnd\n : inRange;\n }));\n};\n/**\n * Determines if the current date is within a publication windows of a situation.\n */\nexport const isMocoSituationPublished = (situation, now = new Date()) => {\n var _a, _b, _c;\n const publicationWindows = (_c = (_a = situation.publicationWindows) !== null && _a !== void 0 ? _a : (_b = situation.publications) === null || _b === void 0 ? void 0 : _b.flatMap((publication) => {\n var _a;\n return (_a = publication.publicationWindows) !== null && _a !== void 0 ? _a : [];\n })) !== null && _c !== void 0 ? _c : [];\n if (!publicationWindows.length) {\n // If there are no publication windows, use the time intervals\n return !!isMocoSituationAffected(situation, now);\n }\n return !!publicationWindows.some(({ endTime, startTime }) => {\n return new Date(startTime) <= now && now <= new Date(endTime);\n });\n};\n// export const getMocoStartsString = (\n// notificationProperties: MocoNotificationProperties,\n// now: Date,\n// ) => {\n// const next = notificationProperties.affected_time_intervals.reduce(\n// (\n// a: MocoDefinitions['AffectedTimeIntervals'],\n// b: MocoDefinitions['AffectedTimeIntervals'],\n// ) => {\n// const aEnd = new Date(a.end);\n// const aStart = new Date(a.start);\n// const bStart = new Date(b.start);\n// return now < aEnd && aStart < bStart ? a : b;\n// },\n// {} as MocoDefinitions['AffectedTimeIntervals'],\n// );\n// const nextStartDate = new Date(next.start);\n// let starts;\n// if (\n// now.toDateString() === nextStartDate.toDateString() ||\n// now.getTime() - nextStartDate.getTime() > 0\n// ) {\n// if (next.time_of_day_start) {\n// starts = `ab ${next.time_of_day_start.substr(0, 5)}`;\n// } else {\n// starts = `ab ${nextStartDate.toLocaleTimeString(['de'], {\n// hour: '2-digit',\n// hour12: false,\n// minute: '2-digit',\n// })}`;\n// }\n// } else {\n// starts = `ab ${nextStartDate.toLocaleDateString(['de-DE'], {\n// day: 'numeric',\n// month: 'short',\n// })}`;\n// }\n// return starts;\n// };\nexport const getMocoIconRefFeature = (publicationLineFeature) => {\n const geometry = geojson.readGeometry(publicationLineFeature.geometry);\n const center = getCenter(geometry.getExtent());\n const icon = {\n geometry: {\n coordinates: geometry.getClosestPoint(center),\n type: 'Point',\n },\n id: uuid(),\n properties: Object.assign(Object.assign({}, publicationLineFeature.properties), { geometry: undefined }),\n type: 'Feature',\n };\n return icon;\n};\nconst to4326 = (geometry3857) => {\n return geojson.writeGeometryObject(geojson.readGeometry(geometry3857, {\n dataProjection: 'EPSG:3857',\n featureProjection: 'EPSG:4326',\n }));\n};\nexport const getMocoReasonCategoryImageName = (categoryName = 'undefiniert') => {\n return categoryName\n .toLowerCase()\n .replace(/\\s/g, '_')\n .replace(/ü/g, 'ue')\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ß/g, 'ss');\n};\n/**\n * This function return a FeatureCollection representing a Situation,\n * This feature collection contains a feature for each affectd lines and stops.\n * This also creates an icon for each affected line if hasIcon property is true.\n */\nexport const getFeatureCollectionToRenderFromSituation = (situation, date = new Date()) => {\n var _a, _b, _c;\n const features = [];\n const reasonCategoryImageName = getMocoReasonCategoryImageName((_b = (_a = situation.reasons) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.categoryName);\n const situationRenderProps = {\n reasonCategoryImageName,\n reasons: situation.reasons,\n // for backward compatibility\n reasons_category: reasonCategoryImageName,\n };\n (_c = situation === null || situation === void 0 ? void 0 : situation.publications) === null || _c === void 0 ? void 0 : _c.forEach((publication) => {\n var _a, _b, _c;\n const isAffected = isMocoSituationAffected(situation, date);\n const isPublished = isMocoSituationPublished(situation, date);\n const publicationRenderProps = {\n // for backward compatibility with v1\n condition_group: publication.serviceConditionGroup.toLowerCase(),\n // for backward compatibility with v1\n isActive: isAffected,\n isAffected,\n isPublished,\n serviceCondition: publication.serviceCondition,\n serviceConditionGroup: publication.serviceConditionGroup,\n severity: publication.severity,\n // for backward compatibility with v1\n severity_group: (_a = publication.severityGroup) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase(),\n severityGroup: publication.severityGroup,\n };\n (_b = publication.publicationLines) === null || _b === void 0 ? void 0 : _b.forEach((publicationLine) => {\n publicationLine.lines.forEach((line) => {\n line.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, hasIcon: publicationLine.hasIcon, line, mot: publicationLine.mot, \n // We pass the ids to be able to identify the publication and the situation related to\n publicationId: publication.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n features.push(feature);\n if (publicationLine.hasIcon) {\n const iconFeature = getMocoIconRefFeature(feature);\n iconFeature.properties.situationId = situation.id; // make the sure the situation is passed\n features.push(iconFeature);\n }\n });\n });\n });\n (_c = publication.publicationStops) === null || _c === void 0 ? void 0 : _c.forEach((publicationStop) => {\n publicationStop.geometry.forEach(({ geom, graph, }) => {\n const feature = {\n geometry: to4326(geom),\n id: uuid(),\n properties: Object.assign(Object.assign(Object.assign({ graph, name: publicationStop.name, publicationId: publication.id, publicationStopId: publicationStop.id, situationId: situation.id }, situationRenderProps), publicationRenderProps), { geometry: undefined }),\n type: 'Feature',\n };\n features.push(feature);\n });\n });\n });\n return {\n features,\n type: 'FeatureCollection',\n };\n};\n// export const getMocoSituationsAsFeatureCollection = (\n// situations: MocoSituationToRender[],\n// ): MocoNotificationAsFeatureCollection => {\n// situations.forEach((situation) => {});\n// // Merge all features into a single GeoJSON feature collection\n// // and add the notification properties to each feature.\n// const features = notifications.flatMap((notification) => {\n// return (notification.features || []).map((feature) => {\n// const feat: MocoNotificationFeature = {\n// ...feature,\n// properties: {\n// ...notification.properties,\n// ...feature.properties,\n// },\n// };\n// const reasonCategoryName =\n// notification.properties.reasons?.[0]?.category_name;\n// // reasons_category is used to choose the proper icon in the style\n// // @ts-expect-error the value is a string in the style\n// feat.properties.reasons_category =\n// MOCO_IMAGE_BY_CATEGORY[\n// reasonCategoryName || MOCO_REASONS_CATEGORY.UNDEFINIERT\n// ] || MOCO_IMAGE_BY_CATEGORY[MOCO_REASONS_CATEGORY.UNDEFINIERT];\n// return feat;\n// });\n// });\n// return {\n// // @ts-expect-error conflict between geometry types\n// features,\n// type: 'FeatureCollection',\n// };\n// };\n", @@ -8670,7 +8670,7 @@ "lineNumber": 1 }, { - "__docId__": 404, + "__docId__": 403, "kind": "function", "name": "getTime", "memberof": "build/common/utils/mocoUtils.js", @@ -8700,7 +8700,7 @@ } }, { - "__docId__": 405, + "__docId__": 404, "kind": "variable", "name": "geojson", "memberof": "build/common/utils/mocoUtils.js", @@ -8721,7 +8721,7 @@ "ignore": true }, { - "__docId__": 406, + "__docId__": 405, "kind": "function", "name": "isMocoSituationAffected", "memberof": "build/common/utils/mocoUtils.js", @@ -8757,7 +8757,7 @@ } }, { - "__docId__": 407, + "__docId__": 406, "kind": "function", "name": "isMocoSituationPublished", "memberof": "build/common/utils/mocoUtils.js", @@ -8793,7 +8793,7 @@ } }, { - "__docId__": 408, + "__docId__": 407, "kind": "function", "name": "getMocoIconRefFeature", "memberof": "build/common/utils/mocoUtils.js", @@ -8823,7 +8823,7 @@ } }, { - "__docId__": 409, + "__docId__": 408, "kind": "function", "name": "to4326", "memberof": "build/common/utils/mocoUtils.js", @@ -8854,7 +8854,7 @@ "ignore": true }, { - "__docId__": 410, + "__docId__": 409, "kind": "function", "name": "getMocoReasonCategoryImageName", "memberof": "build/common/utils/mocoUtils.js", @@ -8887,7 +8887,7 @@ } }, { - "__docId__": 411, + "__docId__": 410, "kind": "function", "name": "getFeatureCollectionToRenderFromSituation", "memberof": "build/common/utils/mocoUtils.js", @@ -8923,7 +8923,7 @@ } }, { - "__docId__": 412, + "__docId__": 411, "kind": "file", "name": "build/common/utils/realtimeStyleUtils.js", "content": "const radiusMapping = [\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],\n [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],\n];\nexport const MOTS_ONLY_RAIL = ['rail'];\nexport const MOTS_WITH_CABLE = [\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\nexport const MOTS_WITHOUT_CABLE = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n];\nexport const MOTS_ALL = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n 'ferry',\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n];\n/**\n * Trajserv value: 'Tram', 'Subway / Metro / S-Bahn', 'Train', 'Bus', 'Ferry', 'Cable Car', 'Gondola', 'Funicular', 'Long distance bus', 'Rail',\n * New endpoint use Rail instead of Train.\n * New tracker values: null, \"tram\", \"subway\", \"rail\", \"bus\", \"ferry\", \"cablecar\", \"gondola\", \"funicular\", \"coach\".\n */\nexport const types = [\n /^Tram/i,\n /^Subway( \\/ Metro \\/ S-Bahn)?/i,\n /^Train/i,\n /^Bus/i,\n /^Ferry/i,\n /^Cable ?Car/i,\n /^Gondola/i,\n /^Funicular/i,\n /^(Long distance bus|coach)/i,\n /^Rail/i, // New endpoint use Rail instead of Train.\n /^unknown/i, // in case the type is not defined\n];\nexport const bgColors = [\n '#ffb400',\n '#ff5400',\n '#ff8080',\n '#ea0000',\n '#3000ff',\n '#ffb400',\n '#41a27b',\n '#00d237',\n '#b5b5b5',\n '#ff8080',\n '#ffb400',\n];\nexport const textColors = [\n '#000000',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#ffffff',\n '#000000',\n '#ffffff',\n '#000000',\n '#000000',\n '#000000',\n];\nexport const DEFAULT_TYPE = 'unknown';\nexport const findDefaultIndexType = () => {\n return types.findIndex((r) => {\n return r.test(DEFAULT_TYPE);\n });\n};\nexport const getTypeIndex = (type) => {\n const t = type;\n if (t === undefined || t === null) {\n return findDefaultIndexType();\n }\n if (typeof t === 'string') {\n const index = types.findIndex((r) => {\n return r.test(t);\n });\n if (index === -1) {\n return findDefaultIndexType();\n }\n return index;\n }\n return t;\n};\nexport const getRadiusForTypeAndZoom = (type, zoom) => {\n const z = Math.min(Math.floor(zoom !== null && zoom !== void 0 ? zoom : 1), 16);\n try {\n const typeIdx = getTypeIndex(type);\n return radiusMapping[typeIdx][z];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (e) {\n return 1;\n }\n};\n/**\n * @deprecated use getRadiusForTypeAndZoom\n */\nexport const getRadius = getRadiusForTypeAndZoom;\nexport const getColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return bgColors[typeIdx];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n }\n catch (error) {\n return '#000';\n }\n};\n/**\n * @deprecated use getColorForType\n */\nexport const getBgColor = getColorForType;\nexport const getTextColorForType = (type) => {\n try {\n const typeIdx = getTypeIndex(type);\n return textColors[typeIdx];\n }\n catch (e) {\n return '#ffffff';\n }\n};\nexport const getTextColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.text_color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * @deprecated use getTextColorForType\n */\nexport const getTextColor = getTextColorForType;\nexport const getTextSize = (ctx, markerSize, text, fontSize, font) => {\n if (!ctx || !font || !markerSize || !text || !fontSize) {\n return 0;\n }\n ctx.font = font;\n let newText = ctx.measureText(text);\n const maxiter = 25;\n let i = 0;\n while (newText.width > markerSize && i < maxiter) {\n const previousFontSize = fontSize;\n // eslint-disable-next-line no-param-reassign\n fontSize -= 0.5;\n ctx.font = ctx.font.replace(`${previousFontSize}px`, `${fontSize}px`);\n newText = ctx.measureText(text);\n i += 1;\n }\n return fontSize;\n};\nexport const getDelayColor = (delayInMs, cancelled, isDelayText) => {\n if (cancelled) {\n return isDelayText ? '#ff0000' : '#a0a0a0'; // red or gray\n }\n if (delayInMs === null || delayInMs === undefined) {\n return ''; // grey { r: 160, g: 160, b: 160, s: '160,160,160' };\n }\n if (delayInMs >= 3600000) {\n return '#ed004c'; // pink { r: 237, g: 0, b: 76, s: '237,0,76' };\n }\n if (delayInMs >= 500000) {\n return '#e80000'; // red { r: 232, g: 0, b: 0, s: '232,0,0' };\n }\n if (delayInMs >= 300000) {\n return '#ff4a00'; // orange { r: 255, g: 74, b: 0, s: '255,74,0' };\n }\n if (delayInMs >= 180000) {\n return '#f7bf00'; // yellow { r: 247, g: 191, b: 0, s: '247,191,0' };\n }\n return '#00a00c'; // green { r: 0, g: 160, b: 12, s: '0,160,12' };\n};\nexport const getDelayText = (delay, cancelled) => {\n if (cancelled) {\n return String.fromCodePoint(0x00d7);\n }\n if (!delay) {\n return '';\n }\n if (delay >= 3600000) {\n const rounded = Math.round(delay / 3600000);\n return `+${rounded}h`;\n }\n if (delay >= 60000) {\n const rounded = Math.round(delay / 60000);\n return `+${rounded}m`;\n }\n if (delay >= 1000) {\n const rounded = Math.round(delay / 1000);\n return `+${rounded}s`;\n }\n if (delay > 0) {\n return `+${delay}ms`;\n }\n return '';\n};\nexport const getColorForLine = (line) => {\n let color = line === null || line === void 0 ? void 0 : line.color;\n if (color && !color.startsWith('#')) {\n color = `#${color}`;\n }\n return color;\n};\n/**\n * This object is the default style options for the realtime layer.\n * The colors are defined depending of the trajectory`s line, and if it does\n * not exist, depending of the mot type of the trajectory.\n */\nexport const styleOptionsForMot = {\n getColor: (trajectory) => {\n var _a, _b;\n return (getColorForLine((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.line) ||\n getColorForType((_b = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _b === void 0 ? void 0 : _b.type) ||\n '#000');\n },\n getDelayColor: (trajectory, viewState, delayInMs, cancelled, isDelayText) => {\n return getDelayColor(delayInMs, cancelled, isDelayText) || 'transparent';\n },\n getDelayText: (trajectory, viewState, delay, cancelled) => {\n return getDelayText(delay, cancelled) || '';\n },\n getRadius: (trajectory, viewState) => {\n var _a;\n return (getRadiusForTypeAndZoom((_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.properties) === null || _a === void 0 ? void 0 : _a.type, viewState === null || viewState === void 0 ? void 0 : viewState.zoom) ||\n 1);\n },\n getTextColor: (trajectory) => {\n return (getTextColorForLine(trajectory.properties.line) ||\n getTextColorForType(trajectory.properties.type));\n },\n getTextSize: (trajectory, viewState, ctx, markerSize, text, fontSize, font) => {\n return getTextSize(ctx, markerSize, text, fontSize, font) || 12;\n },\n};\n", @@ -8934,7 +8934,7 @@ "lineNumber": 1 }, { - "__docId__": 413, + "__docId__": 412, "kind": "variable", "name": "radiusMapping", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8955,7 +8955,7 @@ "ignore": true }, { - "__docId__": 414, + "__docId__": 413, "kind": "variable", "name": "MOTS_ONLY_RAIL", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8975,7 +8975,7 @@ } }, { - "__docId__": 415, + "__docId__": 414, "kind": "variable", "name": "MOTS_WITH_CABLE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -8995,7 +8995,7 @@ } }, { - "__docId__": 416, + "__docId__": 415, "kind": "variable", "name": "MOTS_WITHOUT_CABLE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9015,7 +9015,7 @@ } }, { - "__docId__": 417, + "__docId__": 416, "kind": "variable", "name": "MOTS_ALL", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9035,7 +9035,7 @@ } }, { - "__docId__": 418, + "__docId__": 417, "kind": "variable", "name": "types", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9054,7 +9054,7 @@ } }, { - "__docId__": 419, + "__docId__": 418, "kind": "variable", "name": "bgColors", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9074,7 +9074,7 @@ } }, { - "__docId__": 420, + "__docId__": 419, "kind": "variable", "name": "textColors", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9094,7 +9094,7 @@ } }, { - "__docId__": 421, + "__docId__": 420, "kind": "variable", "name": "DEFAULT_TYPE", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9114,7 +9114,7 @@ } }, { - "__docId__": 422, + "__docId__": 421, "kind": "function", "name": "findDefaultIndexType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9137,7 +9137,7 @@ } }, { - "__docId__": 423, + "__docId__": 422, "kind": "function", "name": "getTypeIndex", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9167,7 +9167,7 @@ } }, { - "__docId__": 424, + "__docId__": 423, "kind": "function", "name": "getRadiusForTypeAndZoom", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9203,7 +9203,7 @@ } }, { - "__docId__": 425, + "__docId__": 424, "kind": "variable", "name": "getRadius", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9223,7 +9223,7 @@ } }, { - "__docId__": 426, + "__docId__": 425, "kind": "function", "name": "getColorForType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9253,7 +9253,7 @@ } }, { - "__docId__": 427, + "__docId__": 426, "kind": "variable", "name": "getBgColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9273,7 +9273,7 @@ } }, { - "__docId__": 428, + "__docId__": 427, "kind": "function", "name": "getTextColorForType", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9303,7 +9303,7 @@ } }, { - "__docId__": 429, + "__docId__": 428, "kind": "function", "name": "getTextColorForLine", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9333,7 +9333,7 @@ } }, { - "__docId__": 430, + "__docId__": 429, "kind": "variable", "name": "getTextColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9353,7 +9353,7 @@ } }, { - "__docId__": 431, + "__docId__": 430, "kind": "function", "name": "getTextSize", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9407,7 +9407,7 @@ } }, { - "__docId__": 432, + "__docId__": 431, "kind": "function", "name": "getDelayColor", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9449,7 +9449,7 @@ } }, { - "__docId__": 433, + "__docId__": 432, "kind": "function", "name": "getDelayText", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9485,7 +9485,7 @@ } }, { - "__docId__": 434, + "__docId__": 433, "kind": "function", "name": "getColorForLine", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9515,7 +9515,7 @@ } }, { - "__docId__": 435, + "__docId__": 434, "kind": "variable", "name": "styleOptionsForMot", "memberof": "build/common/utils/realtimeStyleUtils.js", @@ -9534,7 +9534,7 @@ } }, { - "__docId__": 436, + "__docId__": 435, "kind": "file", "name": "build/common/utils/removeDuplicate.js", "content": "/**\n * This function remove duplicates lower case string value of an array.\n * It removes also null, undefined or non string values.\n *\n * @param {array} array Array of values.\n * @private\n */\nfunction removeDuplicate(array) {\n const arrWithoutEmptyValues = array.filter((val) => {\n var _a;\n return (_a = val === null || val === void 0 ? void 0 : val.trim) === null || _a === void 0 ? void 0 : _a.call(val);\n });\n const lowerCasesValues = arrWithoutEmptyValues.map((str) => {\n return str.toLowerCase();\n });\n const uniqueLowerCaseValues = [...new Set(lowerCasesValues)];\n const uniqueValues = uniqueLowerCaseValues.map((uniqueStr) => {\n return arrWithoutEmptyValues.find((str) => {\n return str.toLowerCase() === uniqueStr;\n });\n });\n return uniqueValues;\n}\nexport default removeDuplicate;\n", @@ -9545,7 +9545,7 @@ "lineNumber": 1 }, { - "__docId__": 437, + "__docId__": 436, "kind": "function", "name": "removeDuplicate", "memberof": "build/common/utils/removeDuplicate.js", @@ -9578,10 +9578,10 @@ } }, { - "__docId__": 438, + "__docId__": 437, "kind": "file", "name": "build/common/utils/renderTrajectories.js", - "content": "import { apply, compose, create } from 'ol/transform';\nimport getVehiclePosition from './getVehiclePosition';\n/**\n * Draw all the trajectories available in a canvas.\n * @param {HTMLCanvas|HTMLOffscreenCanvas} canvas The canvas where to draw the trajectories.\n * @param {ViewState} trajectories An array of trajectories.\n * @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.\n * @param {ViewState} viewState The view state of the map.\n * @param {Object} options The options.\n * @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.\n * @param {boolean} options.selectedVehicleId The id of the vehicle to select.\n * @param {boolean} options.noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\nconst renderTrajectories = (canvas, trajectories, style, viewState, options) => {\n if (!canvas) {\n return { renderedTrajectories: [] };\n }\n const { center, pixelRatio = 1, resolution, rotation = 0, size = [], time = Date.now(), } = viewState;\n if (!resolution || !center) {\n return { renderedTrajectories: [] };\n }\n const { filter, getScreenPixel = (pixel, viewStat) => {\n return (viewStat.zoom || 0) < 12\n ? pixel.map((coord) => {\n return Math.floor(coord);\n })\n : pixel;\n }, hoverVehicleId, noInterpolate = false, selectedVehicleId, } = options;\n const context = canvas.getContext('2d');\n context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);\n const [width, height] = size;\n if (width &&\n height &&\n (canvas.width !== width * pixelRatio ||\n canvas.height !== height * pixelRatio)) {\n [canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];\n }\n const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);\n // Offscreen canvas has not style attribute\n if (canvas.style) {\n canvas.style.width = `${canvas.width / pixelRatio}px`;\n canvas.style.height = `${canvas.height / pixelRatio}px`;\n }\n let hoverVehicleImg;\n let hoverVehiclePx;\n let selectedVehicleImg;\n let selectedVehiclePx;\n const renderedTrajectories = [];\n const cachePixel = {};\n const cacheNbTrainAtPixel = {};\n const cacheDistanceOffset = {};\n for (let i = trajectories.length - 1; i >= 0; i -= 1) {\n const trajectory = trajectories[i];\n // Filter out trajectories\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n if (filter && !filter(trajectory)) {\n continue;\n }\n // We simplify the trajectory object\n // @ts-expect-error improve types\n const { timeOffset, train_id: id } = trajectory.properties;\n // We set the rotation and the timeFraction of the trajectory (used by tralis).\n // if rotation === null that seems there is no rotation available.\n const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);\n // We store the current vehicle position to the trajectory.\n trajectories[i].properties.coordinate = coord;\n trajectories[i].properties.rotation = rotationIcon;\n if (!coord) {\n continue;\n }\n let px = apply(coordinateToPixelTransform, [...coord]);\n if (!px) {\n continue;\n }\n px = px.map((p) => {\n return p * pixelRatio;\n });\n if (px[0] < 0 ||\n px[0] > canvas.width ||\n px[1] < 0 ||\n px[1] > canvas.height) {\n continue;\n }\n const vehicleImg = style(trajectory, viewState, options);\n if (!vehicleImg) {\n continue;\n }\n if (resolution < 1) {\n const roundedPX = px.map((p) => {\n return Math.round(p);\n });\n const key = `${roundedPX.toString()}`;\n if (!cachePixel[key]) {\n cachePixel[key] = px;\n cacheNbTrainAtPixel[key] = 1;\n cacheDistanceOffset[key] = 40 * resolution;\n }\n else {\n // if (!hoverVehicleId) {\n px[0] += 40 * cacheNbTrainAtPixel[key];\n // // }\n trajectories[i].properties.coordinate = [\n coord[0] + cacheDistanceOffset[key],\n coord[1],\n ];\n cacheNbTrainAtPixel[key]++;\n cacheDistanceOffset[key] += 40 * resolution;\n }\n }\n if (hoverVehicleId !== id && selectedVehicleId !== id) {\n // To optimize the performance we use integer as pixel coordinate\n // to avoid an additional work by the browser on zoom level < 12.\n // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead\n const [x, y] = getScreenPixel([px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState);\n context === null || context === void 0 ? void 0 : context.drawImage(vehicleImg, x, y);\n }\n if (hoverVehicleId && hoverVehicleId === id) {\n // Store the canvas to draw it at the end\n hoverVehicleImg = vehicleImg;\n hoverVehiclePx = px;\n // console.log(resolution);\n }\n if (selectedVehicleId && selectedVehicleId === id) {\n // Store the canvas to draw it at the end\n selectedVehicleImg = vehicleImg;\n selectedVehiclePx = px;\n }\n renderedTrajectories.push(trajectory);\n }\n if (selectedVehicleImg && selectedVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(selectedVehicleImg, Math.floor(selectedVehiclePx[0] - selectedVehicleImg.width / 2), Math.floor(selectedVehiclePx[1] - selectedVehicleImg.height / 2));\n }\n if (hoverVehicleImg && hoverVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(hoverVehicleImg, Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2));\n }\n return {\n // isReady: true,\n renderedTrajectories,\n };\n};\nexport default renderTrajectories;\n", + "content": "import { apply, compose, create } from 'ol/transform';\nimport getVehiclePosition from './getVehiclePosition';\n/**\n * Draw all the trajectories available in a canvas.\n * @param {HTMLCanvas|HTMLOffscreenCanvas} canvas The canvas where to draw the trajectories.\n * @param {ViewState} trajectories An array of trajectories.\n * @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.\n * @param {ViewState} viewState The view state of the map.\n * @param {Object} options The options.\n * @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.\n * @param {boolean} options.selectedVehicleId The id of the vehicle to select.\n * @param {boolean} options.noInterpolate If true trajectories are not interpolated but\n * drawn at the last known coordinate. Use this for performance optimization\n * during map navigation.\n * @private\n */\nconst renderTrajectories = (canvas, trajectories, style, viewState, options) => {\n if (!canvas) {\n return { renderedTrajectories: [] };\n }\n const { center, pixelRatio = 1, resolution, rotation = 0, size = [], time = Date.now(), } = viewState;\n if (!resolution || !center) {\n return { renderedTrajectories: [] };\n }\n const { filter, getScreenPixel = (pixel, viewStat) => {\n return (viewStat.zoom || 0) < 12\n ? pixel.map((coord) => {\n return Math.floor(coord);\n })\n : pixel;\n }, hoverVehicleId, noInterpolate = false, selectedVehicleId, } = options;\n const context = canvas.getContext('2d');\n context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);\n const [width, height] = size;\n if (width &&\n height &&\n (canvas.width !== width * pixelRatio ||\n canvas.height !== height * pixelRatio)) {\n [canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];\n }\n const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);\n // Offscreen canvas has not style attribute\n if (canvas.style) {\n canvas.style.width = `${canvas.width / pixelRatio}px`;\n canvas.style.height = `${canvas.height / pixelRatio}px`;\n }\n let hoverVehicleImg;\n let hoverVehiclePx;\n let selectedVehicleImg;\n let selectedVehiclePx;\n const renderedTrajectories = [];\n const cacheStyle = {};\n const cachePixel = {};\n const cacheNbTrainAtPixel = {};\n const cacheDistanceOffset = {};\n for (let i = trajectories.length - 1; i >= 0; i -= 1) {\n const trajectory = trajectories[i];\n delete cacheStyle[trajectory.properties.train_id];\n // Filter out trajectories\n if (filter && !filter(trajectory)) {\n continue;\n }\n // We simplify the trajectory object\n // @ts-expect-error improve types\n const { timeOffset, train_id: id } = trajectory.properties;\n // We set the rotation and the timeFraction of the trajectory (used by tralis).\n // if rotation === null that seems there is no rotation available.\n const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);\n // We store the current vehicle position to the trajectory.\n trajectories[i].properties.coordinate = coord;\n trajectories[i].properties.rotation = rotationIcon;\n if (!coord) {\n continue;\n }\n let px = apply(coordinateToPixelTransform, [...coord]);\n if (!px) {\n continue;\n }\n px = px.map((p) => {\n return p * pixelRatio;\n });\n if (px[0] < 0 ||\n px[0] > canvas.width ||\n px[1] < 0 ||\n px[1] > canvas.height) {\n continue;\n }\n const vehicleImg = style(trajectory, viewState, options);\n if (!vehicleImg) {\n continue;\n }\n cacheStyle[trajectory.properties.train_id] = vehicleImg;\n if (resolution < 1) {\n const roundedPX = px.map((p) => {\n return Math.round(p / 40) * 40;\n });\n const key = `${roundedPX.toString()}`;\n if (!cachePixel[key]) {\n cachePixel[key] = px;\n cacheNbTrainAtPixel[key] = 1;\n cacheDistanceOffset[key] = 40 * resolution;\n }\n else {\n // console.log(\n // 'Collision detected for train id',\n // id,\n // 'at pixel',\n // roundedPX,\n // );\n // if (!hoverVehicleId) {\n px[0] += 40 * cacheNbTrainAtPixel[key];\n // // }\n trajectories[i].properties.coordinate = [\n coord[0] + cacheDistanceOffset[key],\n coord[1],\n ];\n cacheNbTrainAtPixel[key]++;\n cacheDistanceOffset[key] += 40 * resolution;\n }\n }\n if (hoverVehicleId !== id && selectedVehicleId !== id) {\n // To optimize the performance we use integer as pixel coordinate\n // to avoid an additional work by the browser on zoom level < 12.\n // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead\n const [x, y] = getScreenPixel([px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState);\n context === null || context === void 0 ? void 0 : context.drawImage(vehicleImg, x, y);\n }\n if (hoverVehicleId && hoverVehicleId === id) {\n // Store the canvas to draw it at the end\n hoverVehicleImg = vehicleImg;\n hoverVehiclePx = px;\n // console.log(resolution);\n }\n if (selectedVehicleId && selectedVehicleId === id) {\n // Store the canvas to draw it at the end\n selectedVehicleImg = vehicleImg;\n selectedVehiclePx = px;\n }\n renderedTrajectories.push(trajectory);\n }\n if (selectedVehicleImg && selectedVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(selectedVehicleImg, Math.floor(selectedVehiclePx[0] - selectedVehicleImg.width / 2), Math.floor(selectedVehiclePx[1] - selectedVehicleImg.height / 2));\n }\n if (hoverVehicleImg && hoverVehiclePx) {\n context === null || context === void 0 ? void 0 : context.drawImage(hoverVehicleImg, Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2));\n }\n return {\n // isReady: true,\n renderedTrajectories,\n styleCacheByTrajectoryId: cacheStyle,\n };\n};\nexport default renderTrajectories;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/utils/renderTrajectories.js", "access": "private", @@ -9589,7 +9589,7 @@ "lineNumber": 1 }, { - "__docId__": 439, + "__docId__": 438, "kind": "function", "name": "renderTrajectories", "memberof": "build/common/utils/renderTrajectories.js", @@ -9688,12 +9688,12 @@ ], "return": { "types": [ - "{\"renderedTrajectories\": *}" + "{\"renderedTrajectories\": *, \"styleCacheByTrajectoryId\": *}" ] } }, { - "__docId__": 440, + "__docId__": 439, "kind": "file", "name": "build/common/utils/sortAndFilterDepartures.js", "content": "import compareDepartures from './compareDepartures';\n/**\n * This function sort Departures by arrival time and filter out unwanted departures:\n * - when dparture time is in the past\n * - when departure are duplicated\n * - when departure is not in the next 30 min\n *\n * @param {Object} depObject The object containing departures by id.\n * @param {boolean} [sortByMinArrivalTime=false] If true sort departures by arrival time.\n * @param {number} [maxDepartureAge=30] The maximum departure age in minutes.\n * @return {RealtimeDeparture[]} Return departures array.\n * @private\n */\nconst sortAndfilterDepartures = (depObject, sortByMinArrivalTime = false, maxDepartureAge = 30) => {\n const departures = Object.keys(depObject).map((k) => {\n return depObject[k];\n });\n departures.sort((a, b) => {\n return compareDepartures(a, b, sortByMinArrivalTime);\n });\n const futureDate = new Date();\n futureDate.setMinutes(futureDate.getMinutes() + maxDepartureAge);\n const future = futureDate.getTime();\n const pastDate = new Date();\n pastDate.setMinutes(pastDate.getMinutes() - maxDepartureAge);\n const past = pastDate.getTime();\n const departureArray = [];\n const platformsBoarding = [];\n let previousDeparture = null;\n for (let i = departures.length - 1; i >= 0; i -= 1) {\n const departure = Object.assign({}, departures[i]);\n if (!departure.time) {\n // eslint-disable-next-line no-console\n console.warn('Departure without time found, skipping it.', departure);\n continue;\n }\n const time = new Date(departure.time).getTime();\n // Only show departures within the next 30 minutes\n if (time > past && time < future) {\n // If 2 trains are boarding at the same platform,\n // remove the older one.\n if (departure.state === 'BOARDING') {\n if (departure.platform &&\n !platformsBoarding.includes(departure.platform)) {\n platformsBoarding.push(departure.platform);\n }\n else {\n departure.state = 'HIDDEN';\n }\n }\n // If two trains with the same line number and destinatin\n // and a departure difference < 1 minute, hide the second one.\n if (previousDeparture &&\n departure.to[0] === previousDeparture.to[0] &&\n Math.abs(time - (previousDeparture.time || 0)) < 1000 &&\n departure.line.name === previousDeparture.line.name) {\n departure.state = 'HIDDEN';\n }\n if (/(STOP_CANCELLED|JOURNEY_CANCELLED)/.test(departure.state)) {\n departure.cancelled = true;\n }\n previousDeparture = departure;\n previousDeparture.time = time;\n departureArray.unshift(departure);\n }\n }\n return departureArray;\n};\nexport default sortAndfilterDepartures;\n", @@ -9704,7 +9704,7 @@ "lineNumber": 1 }, { - "__docId__": 441, + "__docId__": 440, "kind": "function", "name": "sortAndfilterDepartures", "memberof": "build/common/utils/sortAndFilterDepartures.js", @@ -9764,7 +9764,7 @@ } }, { - "__docId__": 442, + "__docId__": 441, "kind": "file", "name": "build/common/utils/sortByDelay.js", "content": "const sortByDelay = (traj1, traj2) => {\n const props1 = traj1.properties;\n const props2 = traj2.properties;\n if (props1.delay === null && props2.delay !== null) {\n return 1;\n }\n if (props2.delay === null && props1.delay !== null) {\n return -1;\n }\n // We put cancelled train inbetween green and yellow trains\n // >=180000ms corresponds to yellow train\n // @ts-expect-error Verify that this property exists\n if (props1.cancelled && !props2.cancelled) {\n return props2.delay < 180000 ? -1 : 1;\n }\n // @ts-expect-error Verify that this property exists\n if (props2.cancelled && !props1.cancelled) {\n return props1.delay < 180000 ? 1 : -1;\n }\n return props2.delay - props1.delay;\n};\nexport default sortByDelay;\n", @@ -9775,7 +9775,7 @@ "lineNumber": 1 }, { - "__docId__": 443, + "__docId__": 442, "kind": "function", "name": "sortByDelay", "memberof": "build/common/utils/sortByDelay.js", @@ -9811,7 +9811,7 @@ } }, { - "__docId__": 444, + "__docId__": 443, "kind": "file", "name": "build/common/utils/timeUtils.js", "content": "/**\n * Get a Date object as UTC date string .\n * ex: 2019 09 01\n * @private\n */\nexport const getUTCDateString = (now = new Date()) => {\n let month = (now.getUTCMonth() + 1).toString();\n month = month.length === 1 ? `0${month}` : month;\n let day = now.getUTCDate().toString();\n day = day.length === 1 ? `0${day}` : day;\n return [now.getUTCFullYear(), month, day].join('');\n};\n/**\n * Get the UTC time string of Date object.\n * ex: 09:05:01.123\n * @private\n */\nexport const getUTCTimeString = (date) => {\n return [\n date.getUTCHours(),\n date.getUTCMinutes(),\n `${date.getUTCSeconds()}.${date.getUTCMilliseconds()}`,\n ].join(':');\n};\n/**\n * Returns a string representation of a number, with a zero if the number is lower than 10.\n * @private\n */\nexport const pad = (integer) => {\n return integer < 10 ? `0${integer}` : `${integer}`;\n};\n/**\n * Returns a 'hh:mm' string from a time in ms.\n * @param {Number} timeInMs Time in milliseconds.\n * @private\n */\nexport const getHoursAndMinutes = (timeInMs) => {\n if (!timeInMs || timeInMs <= 0) {\n return '';\n }\n const date = new Date(timeInMs);\n return `${pad(date.getHours())}:${pad(date.getMinutes())}`;\n};\n", @@ -9822,7 +9822,7 @@ "lineNumber": 1 }, { - "__docId__": 445, + "__docId__": 444, "kind": "function", "name": "getUTCDateString", "memberof": "build/common/utils/timeUtils.js", @@ -9852,7 +9852,7 @@ } }, { - "__docId__": 446, + "__docId__": 445, "kind": "function", "name": "getUTCTimeString", "memberof": "build/common/utils/timeUtils.js", @@ -9881,7 +9881,7 @@ } }, { - "__docId__": 447, + "__docId__": 446, "kind": "function", "name": "pad", "memberof": "build/common/utils/timeUtils.js", @@ -9910,7 +9910,7 @@ } }, { - "__docId__": 448, + "__docId__": 447, "kind": "function", "name": "getHoursAndMinutes", "memberof": "build/common/utils/timeUtils.js", @@ -9943,7 +9943,7 @@ } }, { - "__docId__": 449, + "__docId__": 448, "kind": "file", "name": "build/common/utils/toMercatorExtent.js", "content": "import { transformExtent } from 'ol/proj';\n/**\n * @private\n */\nconst toMercatorExtent = (bounds) => {\n return transformExtent(bounds.toArray().flat(), 'EPSG:4326', 'EPSG:3857');\n};\nexport default toMercatorExtent;\n", @@ -9954,7 +9954,7 @@ "lineNumber": 1 }, { - "__docId__": 450, + "__docId__": 449, "kind": "function", "name": "toMercatorExtent", "memberof": "build/common/utils/toMercatorExtent.js", @@ -9983,7 +9983,7 @@ } }, { - "__docId__": 451, + "__docId__": 450, "kind": "file", "name": "build/index.js", "content": "import * as maplibre from './maplibre';\nimport * as ol from './ol';\nimport * as maplibre_1 from './maplibre';\nexport { maplibre_1 as maplibre };\nimport * as ol_1 from './ol';\nexport { ol_1 as ol };\nexport default {\n maplibre,\n ol,\n};\n", @@ -9994,7 +9994,7 @@ "lineNumber": 1 }, { - "__docId__": 452, + "__docId__": 451, "kind": "file", "name": "build/maplibre/controls/CopyrightControl.js", "content": "import { getMapGlCopyrights } from '../../common/utils';\n/**\n * @private\n */\nconst DEFAULT_SEPARATOR = ' | ';\n/**\n * Display layer's attributions trying to remove duplicated ones.\n *\n * @example\n * import { Map } from 'maplibre-gl';\n * import { CopyrightControl } from 'mobility-toolbox-js/maplibre';\n *\n * const map = new Map({\n * container: 'map',\n * style: `https://maps.geops.io/styles/travic_v2/style.json?key=${window.apiKey}`,\n * });\n *\n * const control = new CopyrightControl();\n * map.addControl(control);\n *\n *\n * @see MapLibre Realtime layer example\n *\n * @implements {maplibregl.IControl}\n *\n * @public\n */\nclass CopyrightControl {\n constructor(options = {}) {\n this.options = options;\n }\n getDefaultPosition() {\n return 'bottom-right';\n }\n onAdd(map) {\n this.map = map;\n if (!this.container) {\n this.container = document.createElement('div');\n }\n this.render = this.render.bind(this);\n this.map.on('idle', this.render);\n this.map.on('sourcedata', this.render);\n this.map.on('styledata', this.render);\n this.render();\n return this.container;\n }\n onRemove() {\n var _a, _b;\n if ((_a = this.container) === null || _a === void 0 ? void 0 : _a.parentElement) {\n (_b = this.container.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(this.container);\n }\n if (this.map) {\n this.map.off('sourcedata', this.render);\n this.map.off('styledata', this.render);\n this.map.off('idle', this.render);\n }\n this.map = undefined;\n return this.container;\n }\n render() {\n var _a, _b;\n if (this.map && this.container) {\n const separator = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.separator) || DEFAULT_SEPARATOR;\n const attribs = ((_b = this.options) === null || _b === void 0 ? void 0 : _b.customAttribution) || getMapGlCopyrights(this.map);\n const content = (Array.isArray(attribs) ? attribs : [attribs]).join(separator);\n if (this.container.innerHTML !== content) {\n this.content = content;\n this.container.innerHTML = this.content;\n }\n }\n }\n}\nexport default CopyrightControl;\n", @@ -10005,7 +10005,7 @@ "lineNumber": 1 }, { - "__docId__": 453, + "__docId__": 452, "kind": "variable", "name": "DEFAULT_SEPARATOR", "memberof": "build/maplibre/controls/CopyrightControl.js", @@ -10025,7 +10025,7 @@ "ignore": true }, { - "__docId__": 454, + "__docId__": 453, "kind": "class", "name": "CopyrightControl", "memberof": "build/maplibre/controls/CopyrightControl.js", @@ -10049,7 +10049,7 @@ ] }, { - "__docId__": 455, + "__docId__": 454, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10063,7 +10063,7 @@ "undocument": true }, { - "__docId__": 456, + "__docId__": 455, "kind": "member", "name": "options", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10080,7 +10080,7 @@ } }, { - "__docId__": 457, + "__docId__": 456, "kind": "method", "name": "getDefaultPosition", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10100,7 +10100,7 @@ } }, { - "__docId__": 458, + "__docId__": 457, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10127,7 +10127,7 @@ } }, { - "__docId__": 459, + "__docId__": 458, "kind": "member", "name": "map", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10144,7 +10144,7 @@ } }, { - "__docId__": 460, + "__docId__": 459, "kind": "member", "name": "container", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10161,7 +10161,7 @@ } }, { - "__docId__": 462, + "__docId__": 461, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10181,7 +10181,7 @@ } }, { - "__docId__": 464, + "__docId__": 463, "kind": "method", "name": "render", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10197,7 +10197,7 @@ "return": null }, { - "__docId__": 465, + "__docId__": 464, "kind": "member", "name": "content", "memberof": "build/maplibre/controls/CopyrightControl.js~CopyrightControl", @@ -10214,7 +10214,7 @@ } }, { - "__docId__": 466, + "__docId__": 465, "kind": "file", "name": "build/maplibre/controls/index.js", "content": "// eslint-disable-next-line import/prefer-default-export\nexport { default as CopyrightControl } from './CopyrightControl';\n", @@ -10225,7 +10225,7 @@ "lineNumber": 1 }, { - "__docId__": 467, + "__docId__": 466, "kind": "file", "name": "build/maplibre/index.js", "content": "export * from '../api';\nexport * from '../common';\nexport * from './controls';\nexport * from './layers';\nexport * from './utils';\n", @@ -10236,7 +10236,7 @@ "lineNumber": 1 }, { - "__docId__": 468, + "__docId__": 467, "kind": "file", "name": "build/maplibre/layers/Layer.js", "content": "import { Evented } from 'maplibre-gl';\nimport { v4 as uuid } from 'uuid';\n/**\n * A class representing a layer to display on an Maplibre map.\n *\n * @example\n * import { Layer } from 'mobility-toolbox-js/Maplibre';\n *\n * const layer = new Layer({ id:'MyLayer' });\n *\n * @implements {maplibregl.CustomLayerInterface}\n * @extends {maplibregl.Evented}\n * @private\n */\nclass Layer extends Evented {\n constructor(options = {}) {\n super();\n this.options = {};\n this.type = 'custom';\n this.options = options;\n this.id = options.id || uuid();\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onAdd(map, gl) {\n this.map = map;\n }\n onRemove(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n map, \n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n gl) {\n this.map = undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n render(gl) { }\n}\nexport default Layer;\n", @@ -10247,7 +10247,7 @@ "lineNumber": 1 }, { - "__docId__": 469, + "__docId__": 468, "kind": "class", "name": "Layer", "memberof": "build/maplibre/layers/Layer.js", @@ -10271,7 +10271,7 @@ ] }, { - "__docId__": 470, + "__docId__": 469, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10285,7 +10285,7 @@ "undocument": true }, { - "__docId__": 471, + "__docId__": 470, "kind": "member", "name": "options", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10302,7 +10302,7 @@ } }, { - "__docId__": 472, + "__docId__": 471, "kind": "member", "name": "type", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10319,7 +10319,7 @@ } }, { - "__docId__": 474, + "__docId__": 473, "kind": "member", "name": "id", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10336,7 +10336,7 @@ } }, { - "__docId__": 475, + "__docId__": 474, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10365,7 +10365,7 @@ "return": null }, { - "__docId__": 476, + "__docId__": 475, "kind": "member", "name": "map", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10382,7 +10382,7 @@ } }, { - "__docId__": 477, + "__docId__": 476, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10411,7 +10411,7 @@ "return": null }, { - "__docId__": 479, + "__docId__": 478, "kind": "method", "name": "render", "memberof": "build/maplibre/layers/Layer.js~Layer", @@ -10434,7 +10434,7 @@ "return": null }, { - "__docId__": 480, + "__docId__": 479, "kind": "file", "name": "build/maplibre/layers/RealtimeLayer.js", "content": "var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _RealtimeLayer_internalId;\nimport { point } from '@turf/helpers';\nimport transformRotate from '@turf/transform-rotate';\nimport { getHeight, getWidth } from 'ol/extent';\nimport { fromLonLat } from 'ol/proj';\nimport RealtimeEngine from '../../common/utils/RealtimeEngine';\nimport { getSourceCoordinates } from '../utils';\nimport Layer from './Layer';\n/**\n * A Maplibre layer able to display data from the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { Map } from 'maplibre-gl';\n * import { RealtimeLayer } from 'mobility-toolbox-js/maplibre';\n *\n * // Define the map\n * const map = new Map({ ... });\n *\n * // Define your layer map\n * const layer = new RealtimeLayer({\n * apiKey: \"yourApiKey\"\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n * // Add the layer to your map *\n * map.on('load', () => {\n * map.addLayer(layer);\n * });\n *\n *\n * @see RealtimeAPI\n * @see MapLibre Realtime layer example\n *\n * @implements {maplibregl.CustomLayerInterface}\n * @extends {maplibregl.Evented}\n * @classproperty {function} filter - Filter out a train. This function must be fast, it is executed for every trajectory on every render frame.\n * @classproperty {RealtimeMode} mode - The realtime mode to use.\n * @classproperty {RealtimeMot[]} mots - Filter trains by its mode of transportation. It filters trains on backend side.\n * @classproperty {RealtimeTenant} tenant - Filter trains by its tenant. It filters trains on backend side.\n * @classproperty {function} sort - Sort trains. This function must be fast, it is executed on every render frame.\n * @classproperty {function} style - Function to style the vehicles.\n s\n * @public\n */\nclass RealtimeLayer extends Layer {\n get canvas() {\n return this.engine.canvas;\n }\n get pixelRatio() {\n return this.engine.pixelRatio || 1;\n }\n set pixelRatio(pixelRatio) {\n this.engine.pixelRatio = pixelRatio || 1;\n }\n /**\n * Constructor.\n *\n * @param {RealtimeLayerOptions} options\n * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).\n * @param {FilterFunction} options.filter Filter out a train. This function must be fast, it is executed for every trajectory on every render frame.\n * @param {getMotsByZoomFunction} options.getMotsByZoom Returns for each zoom level the list of MOTs to display. It filters trains on backend side.\n * @param {number} [options.minZoomInterpolation=8] Minimal zoom level where to start to interpolate train positions.\n * @param {RealtimeMode} [options.mode='topographic'] The realtime mode to use.\n * @param {SortFunction} options.sort Sort trains. This function must be fast, it is executed on every render frame.\n * @param {RealtimeStyleFunction} options.style Function to style the vehicles.\n * @param {RealtimeTenant} options.tenant Filter trains by its tenant. It filters trains on backend side.\n * @param {string} [options.url=\"wss://api.geops.io/tracker-ws/v1/\"] The geOps Realtime API url.\n */\n constructor(options = {}) {\n var _a;\n const id = (options === null || options === void 0 ? void 0 : options.id) || 'realtime';\n super(Object.assign(Object.assign({}, options), { id: `realtime-custom-${id}` }));\n _RealtimeLayer_internalId.set(this, void 0);\n __classPrivateFieldSet(this, _RealtimeLayer_internalId, id, \"f\");\n this.engine = new RealtimeEngine(Object.assign({ getViewState: this.getViewState.bind(this), onRender: this.onRealtimeEngineRender.bind(this) }, options));\n this.sourceId = __classPrivateFieldGet(this, _RealtimeLayer_internalId, \"f\");\n this.source = {\n // Set to true if the canvas source is animated. If the canvas is static, animate should be set to false to improve performance.\n animate: true,\n // @ts-expect-error bad type definition\n attribution: (_a = options.attribution) === null || _a === void 0 ? void 0 : _a.join(', '),\n canvas: this.canvas,\n // Set a default coordinates, it will be overrides on next data update\n coordinates: [\n [0, 0],\n [1, 1],\n [2, 2],\n [0, 0],\n ],\n loaded: true,\n type: 'canvas',\n };\n this.layer = {\n id: __classPrivateFieldGet(this, _RealtimeLayer_internalId, \"f\"),\n layout: {\n visibility: 'visible',\n },\n paint: {\n 'raster-fade-duration': 0,\n 'raster-opacity': 1,\n 'raster-resampling': 'nearest', // important otherwise it looks blurry\n },\n source: this.sourceId,\n type: 'raster',\n };\n this.onLoad = this.onLoad.bind(this);\n this.onMove = this.onMove.bind(this);\n this.onMoveEnd = this.onMoveEnd.bind(this);\n this.onZoomEnd = this.onZoomEnd.bind(this);\n }\n /**\n * Return the current view state. Used by the RealtimeEngine.\n * @private\n */\n getViewState() {\n if (!this.map) {\n return {};\n }\n if (!this.pixelRatio) {\n this.pixelRatio = 1;\n }\n const { height, width } = this.map.getCanvas();\n const center = this.map.getCenter();\n // We use turf here to have good transform.\n // @ts-expect-error bad type definition\n const leftBottom = this.map.unproject({\n x: 0,\n y: height / this.pixelRatio,\n }); // southWest\n // @ts-expect-error bad type definition\n const rightTop = this.map.unproject({\n x: width / this.pixelRatio,\n y: 0,\n }); // north east\n const coord0 = transformRotate(point([leftBottom.lng, leftBottom.lat]), -this.map.getBearing(), {\n pivot: [center.lng, center.lat],\n }).geometry.coordinates;\n const coord1 = transformRotate(point([rightTop.lng, rightTop.lat]), -this.map.getBearing(), {\n pivot: [center.lng, center.lat],\n }).geometry.coordinates;\n const bounds = [...fromLonLat(coord0), ...fromLonLat(coord1)];\n const xResolution = getWidth(bounds) / (width / this.pixelRatio);\n const yResolution = getHeight(bounds) / (height / this.pixelRatio);\n const res = Math.max(xResolution, yResolution);\n // Coordinate of trajectories are in mercator so we have to pass the proper resolution and center in mercator.\n return {\n center: fromLonLat([center.lng, center.lat]),\n extent: bounds,\n pixelRatio: this.pixelRatio,\n resolution: res,\n rotation: -(this.map.getBearing() * Math.PI) / 180,\n size: [width / this.pixelRatio, height / this.pixelRatio],\n visible: true,\n zoom: this.map.getZoom() - 1,\n };\n }\n /**\n * Add sources, layers and listeners to the map.\n */\n onAdd(map, gl) {\n super.onAdd(map, gl);\n this.engine.attachToMap();\n if (map.isStyleLoaded()) {\n this.onLoad();\n }\n map.on('load', this.onLoad);\n }\n onLoad() {\n var _a, _b, _c, _d;\n if (!((_a = this.map) === null || _a === void 0 ? void 0 : _a.getSource(this.sourceId))) {\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.addSource(this.sourceId, this.source);\n }\n if (!((_c = this.map) === null || _c === void 0 ? void 0 : _c.getLayer(this.layer.id))) {\n (_d = this.map) === null || _d === void 0 ? void 0 : _d.addLayer(this.layer, this.id);\n }\n this.start();\n }\n /**\n * Callback on 'move' event.\n */\n onMove() {\n this.engine.renderTrajectories();\n }\n /**\n * Callback on 'moveend' event.\n */\n onMoveEnd() {\n this.engine.renderTrajectories();\n if (this.engine.isUpdateBboxOnMoveEnd) {\n this.engine.setBbox();\n }\n }\n /**\n * Callback when the RealtimeEngine has rendered successfully.\n */\n onRealtimeEngineRender() {\n var _a;\n if ((_a = this.map) === null || _a === void 0 ? void 0 : _a.style) {\n const extent = getSourceCoordinates(this.map, this.pixelRatio);\n const source = this.map.getSource(this.sourceId);\n if (source) {\n // @ts-expect-error bad type definition\n source.setCoordinates(extent);\n }\n }\n }\n /**\n * Remove source, layers and listeners from the map.\n */\n onRemove(map, gl) {\n this.engine.detachFromMap();\n this.stop();\n map.off('load', this.onLoad);\n if (map.getLayer(this.layer.id)) {\n map.removeLayer(this.layer.id);\n }\n if (map.getSource(this.sourceId)) {\n map.removeSource(this.sourceId);\n }\n super.onRemove(map, gl);\n }\n onZoomEnd() {\n this.engine.onZoomEnd();\n }\n /**\n * Start updating vehicles position.\n *\n * @public\n */\n start() {\n var _a, _b, _c;\n this.engine.start();\n (_a = this.map) === null || _a === void 0 ? void 0 : _a.on('move', this.onMove);\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.on('moveend', this.onMoveEnd);\n (_c = this.map) === null || _c === void 0 ? void 0 : _c.on('zoomend', this.onZoomEnd);\n }\n /**\n * Stop updating vehicles position.\n *\n * @public\n */\n stop() {\n var _a, _b, _c;\n this.engine.stop();\n (_a = this.map) === null || _a === void 0 ? void 0 : _a.off('move', this.onMove);\n (_b = this.map) === null || _b === void 0 ? void 0 : _b.off('moveend', this.onMoveEnd);\n (_c = this.map) === null || _c === void 0 ? void 0 : _c.off('zoomend', this.onZoomEnd);\n }\n}\n_RealtimeLayer_internalId = new WeakMap();\nexport default RealtimeLayer;\n", @@ -10445,7 +10445,7 @@ "lineNumber": 1 }, { - "__docId__": 481, + "__docId__": 480, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10466,7 +10466,7 @@ "ignore": true }, { - "__docId__": 482, + "__docId__": 481, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10487,7 +10487,7 @@ "ignore": true }, { - "__docId__": 483, + "__docId__": 482, "kind": "class", "name": "RealtimeLayer", "memberof": "build/maplibre/layers/RealtimeLayer.js", @@ -10541,7 +10541,7 @@ ] }, { - "__docId__": 484, + "__docId__": 483, "kind": "get", "name": "canvas", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10560,7 +10560,7 @@ } }, { - "__docId__": 485, + "__docId__": 484, "kind": "get", "name": "pixelRatio", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10579,7 +10579,7 @@ } }, { - "__docId__": 486, + "__docId__": 485, "kind": "set", "name": "pixelRatio", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10593,7 +10593,7 @@ "undocument": true }, { - "__docId__": 487, + "__docId__": 486, "kind": "constructor", "name": "constructor", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10714,7 +10714,7 @@ ] }, { - "__docId__": 488, + "__docId__": 487, "kind": "member", "name": "engine", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10731,7 +10731,7 @@ } }, { - "__docId__": 489, + "__docId__": 488, "kind": "member", "name": "sourceId", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10748,7 +10748,7 @@ } }, { - "__docId__": 490, + "__docId__": 489, "kind": "member", "name": "source", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10765,7 +10765,7 @@ } }, { - "__docId__": 491, + "__docId__": 490, "kind": "member", "name": "layer", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10782,7 +10782,7 @@ } }, { - "__docId__": 496, + "__docId__": 495, "kind": "method", "name": "getViewState", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10801,7 +10801,7 @@ } }, { - "__docId__": 498, + "__docId__": 497, "kind": "method", "name": "onAdd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10829,7 +10829,7 @@ "return": null }, { - "__docId__": 499, + "__docId__": 498, "kind": "method", "name": "onLoad", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10845,7 +10845,7 @@ "return": null }, { - "__docId__": 500, + "__docId__": 499, "kind": "method", "name": "onMove", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10860,7 +10860,7 @@ "return": null }, { - "__docId__": 501, + "__docId__": 500, "kind": "method", "name": "onMoveEnd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10875,7 +10875,7 @@ "return": null }, { - "__docId__": 502, + "__docId__": 501, "kind": "method", "name": "onRealtimeEngineRender", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10890,7 +10890,7 @@ "return": null }, { - "__docId__": 503, + "__docId__": 502, "kind": "method", "name": "onRemove", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10918,7 +10918,7 @@ "return": null }, { - "__docId__": 504, + "__docId__": 503, "kind": "method", "name": "onZoomEnd", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10934,7 +10934,7 @@ "return": null }, { - "__docId__": 505, + "__docId__": 504, "kind": "method", "name": "start", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10949,7 +10949,7 @@ "return": null }, { - "__docId__": 506, + "__docId__": 505, "kind": "method", "name": "stop", "memberof": "build/maplibre/layers/RealtimeLayer.js~RealtimeLayer", @@ -10964,7 +10964,7 @@ "return": null }, { - "__docId__": 507, + "__docId__": 506, "kind": "file", "name": "build/maplibre/layers/index.js", "content": "export { default as Layer } from './Layer';\nexport { default as RealtimeLayer } from './RealtimeLayer';\n", @@ -10975,7 +10975,7 @@ "lineNumber": 1 }, { - "__docId__": 508, + "__docId__": 507, "kind": "file", "name": "build/maplibre/utils/getMercatorResolution.js", "content": "import { getHeight, getWidth } from 'ol/extent';\nimport { fromLonLat } from 'ol/proj';\n/**\n * Get the current resolution of a Maplibre map.\n * @param {maplibregl.Map} map A map object.\n */\nconst getMercatorResolution = (map) => {\n const bounds = map.getBounds().toArray();\n const a = fromLonLat(bounds[0]);\n const b = fromLonLat(bounds[1]);\n const extent = [...a, ...b];\n const { height, width } = map.getCanvas();\n const xResolution = getWidth(extent) / width;\n const yResolution = getHeight(extent) / height;\n return Math.max(xResolution, yResolution);\n};\nexport default getMercatorResolution;\n", @@ -10986,7 +10986,7 @@ "lineNumber": 1 }, { - "__docId__": 509, + "__docId__": 508, "kind": "function", "name": "getMercatorResolution", "memberof": "build/maplibre/utils/getMercatorResolution.js", @@ -11019,7 +11019,7 @@ } }, { - "__docId__": 510, + "__docId__": 509, "kind": "file", "name": "build/maplibre/utils/getSourceCoordinates.js", "content": "/**\n * Get the canvas source coordinates of the current map's extent.\n * @param {maplibregl.Map} map A map object.\n * @param {number} [pixelRatio=1] The pixel ratio.\n */\nexport const getSourceCoordinates = (map, pixelRatio = 1) => {\n // Requesting getBounds is not enough when we rotate the map, so we request manually each corner.\n const { height, width } = map.getCanvas();\n // @ts-expect-error - to fix\n const leftTop = map.unproject({ x: 0, y: 0 });\n // @ts-expect-error - to fix\n const leftBottom = map.unproject({ x: 0, y: height / pixelRatio }); // southWest\n // @ts-expect-error - to fix\n const rightBottom = map.unproject({\n x: width / pixelRatio,\n y: height / pixelRatio,\n });\n // @ts-expect-error - to fix\n const rightTop = map.unproject({ x: width / pixelRatio, y: 0 }); // north east\n return [\n [leftTop.lng, leftTop.lat],\n [rightTop.lng, rightTop.lat],\n [rightBottom.lng, rightBottom.lat],\n [leftBottom.lng, leftBottom.lat],\n ];\n};\nexport default getSourceCoordinates;\n", @@ -11030,7 +11030,7 @@ "lineNumber": 1 }, { - "__docId__": 511, + "__docId__": 510, "kind": "function", "name": "getSourceCoordinates", "memberof": "build/maplibre/utils/getSourceCoordinates.js", @@ -11075,7 +11075,7 @@ } }, { - "__docId__": 512, + "__docId__": 511, "kind": "file", "name": "build/maplibre/utils/index.js", "content": "export { default as getMercatorResolution } from './getMercatorResolution';\nexport { default as getSourceCoordinates } from './getSourceCoordinates';\n", @@ -11086,7 +11086,7 @@ "lineNumber": 1 }, { - "__docId__": 513, + "__docId__": 512, "kind": "file", "name": "build/ol/controls/CopyrightControl.js", "content": "import Control from 'ol/control/Control';\nimport { inView } from 'ol/layer/Layer';\nimport createDefaultCopyrightElement from '../../common/utils/createDefaultCopyrightElt';\nimport removeDuplicate from '../../common/utils/removeDuplicate';\n/**\n * Display layer's copyrights. Adding the possibility to format them as you wish.\n *\n * @example\n * import { Map } from 'ol';\n * import { CopyrightControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map',\n * });\n *\n * const control = new CopyrightControl();\n * map.addControl(control);\n *\n *\n * @see OpenLayers Realtime layer example\n *\n * @extends {ol/control/Control~Control}\n *\n */\nclass CopyrightControl extends Control {\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {Function} format Function used to format the list of copyrights available to a single string. By default join all the copyrights with a |.\n * @public\n */\n constructor(options = {}) {\n const element = createDefaultCopyrightElement();\n element.className = options.className || 'mbt-copyright';\n super(Object.assign({ element }, options));\n this.format =\n options.format ||\n ((copyrights) => {\n return copyrights === null || copyrights === void 0 ? void 0 : copyrights.join(' | ');\n });\n }\n render({ frameState }) {\n if (!frameState) {\n this.element.innerHTML = '';\n return;\n }\n let copyrights = [];\n // This code loop comes mainly from ol.\n frameState === null || frameState === void 0 ? void 0 : frameState.layerStatesArray.forEach((layerState) => {\n var _a;\n const { layer } = layerState;\n if (frameState && inView(layerState, frameState.viewState)) {\n const attribFunc = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getAttributions();\n if (attribFunc) {\n copyrights = copyrights.concat(attribFunc(frameState));\n }\n if (layer === null || layer === void 0 ? void 0 : layer.get('copyrights')) {\n let copyProp = layer.get('copyrights');\n copyProp = !Array.isArray(copyProp) ? [copyProp] : copyProp;\n if (copyProp === null || copyProp === void 0 ? void 0 : copyProp.length) {\n copyrights.push(...copyProp);\n }\n }\n }\n });\n const unique = removeDuplicate(copyrights) || [];\n this.element.innerHTML = this.format(unique);\n }\n}\nexport default CopyrightControl;\n", @@ -11097,7 +11097,7 @@ "lineNumber": 1 }, { - "__docId__": 514, + "__docId__": 513, "kind": "class", "name": "CopyrightControl", "memberof": "build/ol/controls/CopyrightControl.js", @@ -11121,7 +11121,7 @@ ] }, { - "__docId__": 515, + "__docId__": 514, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -11156,7 +11156,7 @@ ] }, { - "__docId__": 516, + "__docId__": 515, "kind": "member", "name": "format", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -11173,7 +11173,7 @@ } }, { - "__docId__": 517, + "__docId__": 516, "kind": "method", "name": "render", "memberof": "build/ol/controls/CopyrightControl.js~CopyrightControl", @@ -11200,7 +11200,7 @@ "return": null }, { - "__docId__": 518, + "__docId__": 517, "kind": "file", "name": "build/ol/controls/RoutingControl.js", "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport { Feature } from 'ol';\nimport Control from 'ol/control/Control';\nimport { click } from 'ol/events/condition';\nimport BaseEvent from 'ol/events/Event';\nimport { buffer } from 'ol/extent';\nimport { GeoJSON } from 'ol/format';\nimport { LineString, Point } from 'ol/geom';\nimport { Modify } from 'ol/interaction';\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { fromLonLat, toLonLat } from 'ol/proj';\nimport VectorSource from 'ol/source/Vector';\nimport { RoutingAPI } from '../../api';\n// Examples for a single hop:\n// basel sbb a station named \"basel sbb\"\n// ZUE, station \"Zürich HB\" by its common abbreviation\n// Zürich Hauptbahnhof or HBF Zürich are all valid synonyms für \"Zürich HB\"\n// @47.37811,8.53935 a station at position 47.37811, 8.53935\n// @47.37811,8.53935$4 track 4 in a station at position 47.37811, 8.53935\n// zürich hb@47.37811,8.53935$8 track 8 in station \"Zürich HB\" at position 47.37811, 8.53935\nconst REGEX_VIA_POINT = /^([^@$!\\n]*)(@?([\\d.]+),([\\d.]+))?(\\$?([a-zA-Z0-9]{0,2}))$/;\n// Examples for a single hop:\n//\n// 47.37811,8.53935 a position 47.37811, 8.53935\nconst REGEX_VIA_POINT_COORD = /^([\\d.]+),([\\d.]+)$/;\n// Examples for a single hop:\n//\n// !8596126 a station with id 8596126\n// !8596126$4 a station with id 8596126\nconst REGEX_VIA_POINT_STATION_ID = /^!([^$]*)(\\$?([a-zA-Z0-9]{0,2}))$/;\nconst STOP_FETCH_ABORT_CONTROLLER_KEY = 'stop-fetch';\nconst getFlatCoordinatesFromSegments = (segmentArray) => {\n const coords = [];\n segmentArray.forEach((seg) => {\n var _a;\n const coordArr = (_a = seg.getGeometry()) === null || _a === void 0 ? void 0 : _a.getCoordinates();\n if (coordArr === null || coordArr === void 0 ? void 0 : coordArr.length) {\n coords.push(...coordArr);\n }\n });\n return coords;\n};\n/**\n * This OpenLayers control allows the user to add and modifiy via points to\n * a map and request a route from the [geOps Routing API](https://developer.geops.io/apis/routing/).\n *\n * @example\n * import { Map } from 'ol';\n * import { RoutingControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map'\n * });\n *\n * const control = new RoutingControl();\n *\n * map.addControl(control);\n *\n * @classproperty {string} mot - Mean of transport to be used for routing.\n * @classproperty {VectorLayer} routingLayer - Layer for adding route features.\n * @classproperty {boolean} loading - True if the control is requesting the backend.\n *\n * @see Openlayers routing example\n *\n * @extends {ol/control/Control~Control}\n *\n * @public\n */\nclass RoutingControl extends Control {\n get active() {\n return this.get('active');\n }\n set active(newValue) {\n this.set('active', newValue);\n }\n get loading() {\n return this.get('loading');\n }\n set loading(newValue) {\n this.set('loading', newValue);\n }\n get modify() {\n return this.get('modify');\n }\n set modify(newValue) {\n this.set('modify', newValue);\n }\n get mot() {\n return this.get('mot');\n }\n set mot(newValue) {\n this.set('mot', newValue);\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {Object} options.apiParams Request parameters. See [geOps Routing API documentation](https://developer.geops.io/apis/routing/).\n * @param {Array.>} [options.graphs=[['osm', 0, 99]]] - Array of routing graphs and min/max zoom levels. If you use the control in combination with the [geOps Maps API](https://developer.geops.io/apis/maps/), you may want to use the optimal level of generalizations: \"[['gen4', 0, 8], ['gen3', 8, 9], ['gen2', 9, 11], ['gen1', 11, 13], ['osm', 13, 99]]\".\n * @param {string} [options.mot=\"bus\"] Mean of transport to be used for routing.\n * @param {function} options.onRouteError Callback on request errors.\n * @param {VectorLayer} [options.routingLayer=new VectorLayer()] Vector layer for adding route features.\n * @param {boolean} [options.snapToClosestStation=false] If true, the routing will snap the coordinate to the closest station. Default to false.\n * @param {StyleLike} options.style Style of the default vector layer.\n * @param {boolean} [options.useRawViaPoints=fale] Experimental property. If true, it allows the user to add via points using different kind of string. See \"via\" parameter defined by the [geOps Routing API](https://developer.geops.io/apis/routing/). Default to false, only array of coordinates and station's id are supported as via points.\n * @param {string} [options.url='https://api.geops.io/routing/v1/'] [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.\n * @public\n */\n constructor(options = {}) {\n var _a;\n super(options);\n this.abortControllers = {};\n this.cacheStationData = {};\n this.format = new GeoJSON({ featureProjection: 'EPSG:3857' });\n this.graphs = [];\n this.initialRouteDrag = {};\n this.segments = [];\n this.snapToClosestStation = false;\n this.useRawViaPoints = false;\n this.viaPoints = [];\n if (!this.element) {\n this.createDefaultElement();\n }\n /** True if the control is requesting the backend. */\n this.loading = false;\n this.active = options.active || true;\n this.graphs = (_a = options.graphs) !== null && _a !== void 0 ? _a : [['osm', 0, 99]];\n this.mot = options.mot || 'bus';\n this.modify = options.modify !== false;\n this.apiParams = options.apiParams;\n this.useRawViaPoints = options.useRawViaPoints || false;\n this.snapToClosestStation = options.snapToClosestStation || false;\n this.apiKey = options.apiKey;\n this.stopsApiKey = options.stopsApiKey || this.apiKey;\n this.stopsApiUrl = options.stopsApiUrl || 'https://api.geops.io/stops/v1/';\n this.api = new RoutingAPI(Object.assign({}, options));\n this.routingLayer =\n options.routingLayer ||\n new VectorLayer({\n source: new VectorSource(),\n style: options.style,\n });\n this.onRouteError =\n options.onRouteError ||\n ((error) => {\n this.dispatchEvent(new BaseEvent('change:route'));\n this.reset();\n console.error(error);\n });\n this.onMapClick = this.onMapClick.bind(this);\n this.onModifyEnd = this.onModifyEnd.bind(this);\n this.onModifyStart = this.onModifyStart.bind(this);\n this.createModifyInteraction();\n this.on('propertychange', (evt) => {\n if (evt.key === 'active') {\n this.onActiveChange();\n }\n if (evt.key === 'mot') {\n if (this.viaPoints) {\n void this.drawRoute();\n }\n }\n });\n }\n /**\n * Calculate at which resolutions corresponds each generalizations.\n *\n * @private\n */\n static getGraphsResolutions(graphs, map) {\n const view = map.getView();\n return graphs.map(([, minZoom, maxZoom]) => {\n return [\n view.getResolutionForZoom(minZoom),\n view.getResolutionForZoom(maxZoom || minZoom + 1),\n ];\n });\n }\n /**\n * Aborts viapoint and route requests\n * @private\n */\n abortRequests() {\n var _a;\n // Abort Routing API requests\n this.graphs.forEach((graph) => {\n const graphName = graph[0] || '';\n if (this.abortControllers[graphName]) {\n this.abortControllers[graphName].abort();\n }\n this.abortControllers[graphName] = new AbortController();\n });\n // Abort Stops API requests\n (_a = this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]) === null || _a === void 0 ? void 0 : _a.abort();\n this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY] =\n new AbortController();\n this.loading = false;\n }\n activate() {\n var _a;\n const map = this.getMap();\n if (map) {\n this.format = new GeoJSON({\n featureProjection: map.getView().getProjection(),\n });\n this.graphsResolutions = RoutingControl.getGraphsResolutions(this.graphs, map);\n // Clean the modifyInteraction if present\n if (this.modifyInteraction) {\n map.removeInteraction(this.modifyInteraction);\n }\n // Add modify interaction, RoutingLayer and listeners\n // this.routingLayer?.attachToMap(this.getMap());\n if (this.modifyInteraction) {\n map.addInteraction(this.modifyInteraction);\n }\n (_a = this.modifyInteraction) === null || _a === void 0 ? void 0 : _a.setActive(this.modify);\n this.addListeners();\n }\n }\n /**\n * Add click listener to map.\n * @private\n */\n addListeners() {\n var _a;\n if (!this.modify) {\n return;\n }\n this.removeListeners();\n // @ts-expect-error improve ts types\n this.onMapClickKey = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.on('singleclick', this.onMapClick);\n }\n /**\n * Adds/Replaces a viaPoint to the viaPoints array and redraws route:\n * Adds a viaPoint at end of array by default.\n * If an index is passed a viaPoint is added at the specified index.\n * If an index is passed and overwrite x is > 0, x viaPoints at the specified\n * index are replaced with a single new viaPoint.\n * @param {string | Coordinate} coordinatesOrString Array of coordinates or a string representing a station\n * @param {number} [index=-1] Integer representing the index of the added viaPoint. If not specified, the viaPoint is added at the end of the array.\n * @param {number} [overwrite=0] Marks the number of viaPoints that are removed at the specified index on add.\n * @public\n */\n addViaPoint(coordinatesOrString, index = -1, overwrite = 0) {\n /* Add/Insert/Overwrite viapoint and redraw route */\n this.viaPoints.splice(index === -1 ? this.viaPoints.length : index, overwrite, coordinatesOrString);\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n /**\n * Define a default element.\n *\n * @private\n */\n createDefaultElement() {\n this.element = document.createElement('button');\n this.element.id = 'ol-toggle-routing';\n this.element.innerHTML = 'Toggle Route Control';\n this.element.onclick = () => {\n return this.active ? this.deactivate() : this.activate();\n };\n Object.assign(this.element.style, {\n position: 'absolute',\n right: '10px',\n top: '10px',\n });\n }\n /**\n * Create the interaction used to modify vertexes of features.\n * @private\n */\n createModifyInteraction() {\n var _a;\n /**\n * @type {ol.interaction.Modify}\n * @private\n */\n // Define and add modify interaction\n this.modifyInteraction = new Modify({\n // hitDetection: this.routingLayer, // TODO: wait for ol, fixed in https://github.com/openlayers/openlayers/pull/16393\n deleteCondition: (e) => {\n var _a;\n const feats = \n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n ((_a = e.target) === null || _a === void 0 ? void 0 : _a.getFeaturesAtPixel(e.pixel, {\n hitTolerance: 5,\n })) || [];\n const viaPoint = feats.find((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' && feat.get('index');\n });\n if (click(e) && viaPoint) {\n // Remove node & viaPoint if an existing viaPoint was clicked\n this.removeViaPoint(viaPoint.get('index'));\n return true;\n }\n return false;\n },\n pixelTolerance: 6,\n source: ((_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) || undefined,\n });\n this.modifyInteraction.on('modifystart', this.onModifyStart);\n this.modifyInteraction.on('modifyend', this.onModifyEnd);\n this.modifyInteraction.setActive(false);\n }\n deactivate() {\n const map = this.getMap();\n if (map) {\n // Remove modify interaction, RoutingLayer, listeners and viaPoints\n // this.routingLayer?.detachFromMap();\n if (this.modifyInteraction) {\n map.removeInteraction(this.modifyInteraction);\n }\n this.removeListeners();\n this.reset();\n }\n }\n /**\n * Draws route on map using an array of coordinates:\n * If a single coordinate is passed a single point feature is added to map.\n * If two or more coordinates are passed a request to the RoutingAPI fetches\n * the route using the passed coordinates and the current mot.\n * @private\n */\n drawRoute() {\n var _a, _b;\n /* Calls RoutingAPI to draw a route using the viaPoints array */\n this.abortRequests();\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n if (!this.viaPoints.length) {\n return null;\n }\n if (this.viaPoints.length === 1) {\n // Add point for first node\n return this.drawViaPoint(this.viaPoints[0], 0, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]);\n }\n const formattedViaPoints = this.viaPoints.map((viaPoint) => {\n var _a;\n if (Array.isArray(viaPoint)) {\n const projection = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.getView().getProjection();\n // viaPoint is a coordinate\n // Coordinates need to be reversed as required by the backend RoutingAPI\n const [lon, lat] = toLonLat(viaPoint, projection);\n return this.snapToClosestStation ? [`@${lat}`, lon] : [lat, lon];\n }\n // viaPoint is a string to use as it is\n return this.useRawViaPoints ? viaPoint : `!${viaPoint}`;\n });\n this.loading = true;\n // Create point features for the viaPoints\n this.viaPoints.forEach((viaPoint, idx) => {\n void this.drawViaPoint(viaPoint, idx, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]);\n });\n return Promise.all(this.graphs.map(([graph], index) => {\n const { signal } = this.abortControllers[graph || ''];\n if (!this.api) {\n return Promise.resolve([]);\n }\n return this.api\n .route(Object.assign({ 'coord-punish': 1000.0, 'coord-radius': 100.0, elevation: false, \n // @ts-expect-error improve type graph must include osm in the enum\n graph, mot: this.mot, 'resolve-hops': false, via: `${formattedViaPoints.join('|')}` }, (this.apiParams || {})), { signal })\n .then((featureCollection) => {\n var _a, _b, _c;\n this.segments = this.format.readFeatures(featureCollection);\n if (this.mot === 'foot') {\n // Extract unique values from viaPoint target value\n const uniqueVias = this.segments.reduce((resultVias, currentFeat) => {\n const segTrg = currentFeat.get('trg');\n return resultVias.find((via) => {\n return via[0] === segTrg[0] && via[1] === segTrg[1];\n })\n ? resultVias\n : [...resultVias, segTrg];\n }, []);\n // Create LineString features from segments with same unique value\n this.segments = uniqueVias.map((via) => {\n const viaSegments = this.segments.filter((seg) => {\n const segTrg = seg.get('trg');\n return segTrg[0] === via[0] && segTrg[1] === via[1];\n });\n const coords = getFlatCoordinatesFromSegments(viaSegments);\n return new Feature({\n geometry: new LineString(coords),\n });\n });\n }\n // Create the new route. This route will be modifiable by the Modifiy interaction.\n const coords = getFlatCoordinatesFromSegments(this.segments);\n const routeFeature = new Feature({\n geometry: new LineString(coords),\n });\n routeFeature.set('graph', graph);\n routeFeature.set('mot', this.mot);\n if (this.graphsResolutions &&\n ((_a = this.graphsResolutions[index]) === null || _a === void 0 ? void 0 : _a.length) >= 2) {\n routeFeature.set('minResolution', this.graphsResolutions[index][0]);\n routeFeature.set('maxResolution', this.graphsResolutions[index][1]);\n }\n (_c = (_b = this.routingLayer) === null || _b === void 0 ? void 0 : _b.getSource()) === null || _c === void 0 ? void 0 : _c.addFeature(routeFeature);\n this.loading = false;\n })\n .catch((error) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access\n if (/AbortError/.test(error === null || error === void 0 ? void 0 : error.name)) {\n // Ignore abort error\n return;\n }\n this.segments = [];\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n this.loading = false;\n });\n }));\n }\n /**\n * Draw a via point. This function can parse all the possibilitiies\n *\n * @private\n */\n drawViaPoint(viaPoint, idx, abortController) {\n var _a, _b, _c, _d, _e, _f, _g, _h;\n const pointFeature = new Feature();\n pointFeature.set('viaPointIdx', idx);\n // The via point is a coordinate using the current map's projection\n if (Array.isArray(viaPoint)) {\n pointFeature.setGeometry(new Point(viaPoint));\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n // Possibility to parse:\n //\n // !8596126 a station with id 8596126\n // !8596126$4 a station with id 8596126\n if (!this.useRawViaPoints || REGEX_VIA_POINT_STATION_ID.test(viaPoint)) {\n let stationId;\n let track;\n if (this.useRawViaPoints) {\n [, stationId, , track] =\n REGEX_VIA_POINT_STATION_ID.exec(viaPoint) || [];\n }\n else {\n [stationId, track] = viaPoint.split('$');\n }\n return fetch(`${this.stopsApiUrl}lookup/${stationId}?key=${this.stopsApiKey}`, { signal: abortController.signal })\n .then((res) => {\n return res.json();\n })\n .then((stationData) => {\n var _a, _b, _c, _d;\n const { coordinates } = ((_b = (_a = stationData === null || stationData === void 0 ? void 0 : stationData.features) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.geometry) || {};\n if (!coordinates) {\n console.log(`No coordinates found for station ${stationId}`, stationData);\n }\n this.cacheStationData[viaPoint] = fromLonLat(coordinates);\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(fromLonLat(coordinates)));\n (_d = (_c = this.routingLayer) === null || _c === void 0 ? void 0 : _c.getSource()) === null || _d === void 0 ? void 0 : _d.addFeature(pointFeature);\n return pointFeature;\n })\n .catch((error) => {\n var _a, _b;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access\n if (/AbortError/.test(error.message)) {\n // Ignore abort error\n return;\n }\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n this.loading = false;\n });\n }\n // Only when this.useRawViaPoints is true.\n // Possibility to parse:\n //\n // 47.37811,8.53935 a position 47.37811, 8.53935\n if (this.useRawViaPoints && REGEX_VIA_POINT_COORD.test(viaPoint)) {\n const [lat, lon] = REGEX_VIA_POINT_COORD.exec(viaPoint) || [];\n if (lon && lat) {\n const floatLon = parseFloat(lon);\n const floatLat = parseFloat(lat);\n const coordinates = fromLonLat([floatLon, floatLat], (_c = this.getMap()) === null || _c === void 0 ? void 0 : _c.getView().getProjection());\n pointFeature.setGeometry(new Point(coordinates));\n (_e = (_d = this.routingLayer) === null || _d === void 0 ? void 0 : _d.getSource()) === null || _e === void 0 ? void 0 : _e.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n }\n // Only when this.useRawViaPoints is true.\n // It will parse the via point to find some name, id, track coordinates.\n //\n // Possibility to parse:\n //\n // @47.37811,8.53935 a station at position 47.37811, 8.53935\n // @47.37811,8.53935$4 track 4 in a station at position 47.37811, 8.53935\n // zürich hb@47.37811,8.53935$8 track 8 in station \"Zürich HB\" at position 47.37811, 8.53935\n const [, stationName, , lat, lon, , track] = REGEX_VIA_POINT.exec(viaPoint) || [];\n if (lon && lat) {\n const coordinates = fromLonLat([parseFloat(lon), parseFloat(lat)], (_f = this.getMap()) === null || _f === void 0 ? void 0 : _f.getView().getProjection());\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(coordinates));\n (_h = (_g = this.routingLayer) === null || _g === void 0 ? void 0 : _g.getSource()) === null || _h === void 0 ? void 0 : _h.addFeature(pointFeature);\n return Promise.resolve(pointFeature);\n }\n if (stationName) {\n return fetch(`${this.stopsApiUrl}?key=${this.stopsApiKey}&q=${stationName}&limit=1`, { signal: abortController.signal })\n .then((res) => {\n return res.json();\n })\n .then((stationData) => {\n var _a, _b, _c;\n const { coordinates } = ((_a = stationData === null || stationData === void 0 ? void 0 : stationData.features) === null || _a === void 0 ? void 0 : _a[0].geometry) || {};\n if (!coordinates) {\n throw new Error(`No coordinates found for station ${stationName}`);\n }\n this.cacheStationData[viaPoint] = fromLonLat(coordinates);\n pointFeature.set('viaPointTrack', track);\n pointFeature.setGeometry(new Point(fromLonLat(coordinates)));\n (_c = (_b = this.routingLayer) === null || _b === void 0 ? void 0 : _b.getSource()) === null || _c === void 0 ? void 0 : _c.addFeature(pointFeature);\n return pointFeature;\n })\n .catch((error) => {\n // Dispatch error event and execute error function\n this.dispatchEvent(new BaseEvent('error'));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.onRouteError(error, this);\n this.loading = false;\n return null;\n });\n }\n return Promise.resolve(null);\n }\n /**\n * Activet7deactivate the control when activ eproperty changes\n * @private\n */\n onActiveChange() {\n if (this.get('active')) {\n this.activate();\n }\n else {\n this.deactivate();\n }\n this.render();\n }\n /**\n * Used on click on map while control is active:\n * By default adds a viaPoint to the end of array.\n * If an existing viaPoint is clicked removes the clicked viaPoint.\n * @private\n */\n onMapClick(evt) {\n const feats = evt.target.getFeaturesAtPixel(evt.pixel, {\n hitTolerance: 5,\n layerFilter: (layer) => {\n return layer === this.routingLayer;\n },\n });\n const viaPoint = feats.find((feat) => {\n var _a;\n return (((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' &&\n feat.get('viaPointIdx') !== undefined);\n });\n if (viaPoint) {\n // Remove existing viaPoint on click and abort viaPoint add\n this.removeViaPoint(viaPoint.get('viaPointIdx'));\n return;\n }\n this.addViaPoint(evt.coordinate);\n }\n /**\n * Used on end of the modify interaction. Resolves feature modification:\n * Line drag creates new viaPoint at the final coordinate of drag.\n * Point drag replaces old viaPoint.\n * @private\n */\n onModifyEnd(evt) {\n const coord = evt.mapBrowserEvent.coordinate;\n const { oldRoute, segmentIndex, viaPoint } = this.initialRouteDrag || {};\n // If viaPoint is being relocated overwrite the old viaPoint\n if (viaPoint) {\n return this.addViaPoint(coord, viaPoint.get('viaPointIdx'), 1);\n }\n // In case there is no route overwrite first coordinate\n if (!oldRoute) {\n return this.addViaPoint(coord, 0, 1);\n }\n // We can't add a via point because we haven't found which segment has been modified.\n if (segmentIndex === -1) {\n return Promise.reject(new Error('No segment found'));\n }\n // Insert new viaPoint at the modified segment index + 1\n return this.addViaPoint(coord, (segmentIndex || 0) + 1);\n }\n /**\n * Used on start of the modify interaction. Stores relevant data\n * in this.initialRouteDrag object\n * @private\n */\n onModifyStart(evt) {\n var _a;\n // When modify start, we search the index of the segment that is modifying.\n let segmentIndex = -1;\n const route = evt.features.getArray().find((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'LineString';\n });\n // Find the segment index that is being modified\n if ((route === null || route === void 0 ? void 0 : route.getGeometry()) && evt.mapBrowserEvent.coordinate) {\n // We use a buff extent to fix floating issues , see https://github.com/openlayers/openlayers/issues/7130#issuecomment-535856422\n const closestExtent = buffer(new Point(\n // @ts-expect-error bad def\n (_a = route.getGeometry()) === null || _a === void 0 ? void 0 : _a.getClosestPoint(evt.mapBrowserEvent.coordinate)).getExtent(), 0.001);\n segmentIndex = this.segments.findIndex((segment) => {\n var _a;\n return (_a = segment.getGeometry()) === null || _a === void 0 ? void 0 : _a.intersectsExtent(closestExtent);\n });\n }\n // Find the viaPoint that is being modified\n const viaPoint = (evt.features.getArray().filter((feat) => {\n var _a;\n return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point';\n }) || [])[0];\n // Write object with modify info\n this.initialRouteDrag = {\n oldRoute: route === null || route === void 0 ? void 0 : route.clone(),\n segmentIndex,\n viaPoint,\n };\n }\n /**\n * Remove click listener from map.\n * @private\n */\n removeListeners() {\n if (this.onMapClickKey) {\n unByKey(this.onMapClickKey);\n }\n }\n /**\n * Removes a viaPoint at the passed array index and redraws route\n * By default the last viaPoint is removed.\n * @param {number} index Integer representing the index of the viaPoint to delete.\n * @public\n */\n removeViaPoint(index = (this.viaPoints || []).length - 1) {\n /* Remove viapoint and redraw route */\n if (this.viaPoints.length && this.viaPoints[index]) {\n this.viaPoints.splice(index, 1);\n }\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n render() { }\n /**\n * Removes all viaPoints, clears the source and triggers a change event\n * @public\n */\n reset() {\n var _a, _b;\n // Clear viaPoints and source\n this.abortRequests();\n this.viaPoints = [];\n (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n setMap(map) {\n super.setMap(map);\n if (map && this.active) {\n this.activate();\n }\n else if (!map) {\n this.active = false;\n }\n }\n /**\n * Replaces the current viaPoints with a new coordinate array.\n * @param {Array>} coordinateArray Array of nested coordinates\n * @public\n */\n setViaPoints(coordinateArray) {\n this.viaPoints = [...coordinateArray];\n void this.drawRoute();\n this.dispatchEvent(new BaseEvent('change:route'));\n }\n}\nexport default RoutingControl;\n", @@ -11211,7 +11211,7 @@ "lineNumber": 1 }, { - "__docId__": 519, + "__docId__": 518, "kind": "variable", "name": "REGEX_VIA_POINT", "memberof": "build/ol/controls/RoutingControl.js", @@ -11232,7 +11232,7 @@ "ignore": true }, { - "__docId__": 520, + "__docId__": 519, "kind": "variable", "name": "REGEX_VIA_POINT_COORD", "memberof": "build/ol/controls/RoutingControl.js", @@ -11253,7 +11253,7 @@ "ignore": true }, { - "__docId__": 521, + "__docId__": 520, "kind": "variable", "name": "REGEX_VIA_POINT_STATION_ID", "memberof": "build/ol/controls/RoutingControl.js", @@ -11274,7 +11274,7 @@ "ignore": true }, { - "__docId__": 522, + "__docId__": 521, "kind": "variable", "name": "STOP_FETCH_ABORT_CONTROLLER_KEY", "memberof": "build/ol/controls/RoutingControl.js", @@ -11295,7 +11295,7 @@ "ignore": true }, { - "__docId__": 523, + "__docId__": 522, "kind": "function", "name": "getFlatCoordinatesFromSegments", "memberof": "build/ol/controls/RoutingControl.js", @@ -11326,7 +11326,7 @@ "ignore": true }, { - "__docId__": 524, + "__docId__": 523, "kind": "class", "name": "RoutingControl", "memberof": "build/ol/controls/RoutingControl.js", @@ -11364,7 +11364,7 @@ ] }, { - "__docId__": 525, + "__docId__": 524, "kind": "get", "name": "active", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11383,7 +11383,7 @@ } }, { - "__docId__": 526, + "__docId__": 525, "kind": "set", "name": "active", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11397,7 +11397,7 @@ "undocument": true }, { - "__docId__": 527, + "__docId__": 526, "kind": "get", "name": "loading", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11416,7 +11416,7 @@ } }, { - "__docId__": 528, + "__docId__": 527, "kind": "set", "name": "loading", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11430,7 +11430,7 @@ "undocument": true }, { - "__docId__": 529, + "__docId__": 528, "kind": "get", "name": "modify", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11449,7 +11449,7 @@ } }, { - "__docId__": 530, + "__docId__": 529, "kind": "set", "name": "modify", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11463,7 +11463,7 @@ "undocument": true }, { - "__docId__": 531, + "__docId__": 530, "kind": "get", "name": "mot", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11482,7 +11482,7 @@ } }, { - "__docId__": 532, + "__docId__": 531, "kind": "set", "name": "mot", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11496,7 +11496,7 @@ "undocument": true }, { - "__docId__": 533, + "__docId__": 532, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11633,7 +11633,7 @@ ] }, { - "__docId__": 534, + "__docId__": 533, "kind": "member", "name": "abortControllers", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11650,7 +11650,7 @@ } }, { - "__docId__": 535, + "__docId__": 534, "kind": "member", "name": "cacheStationData", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11667,7 +11667,7 @@ } }, { - "__docId__": 536, + "__docId__": 535, "kind": "member", "name": "format", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11684,7 +11684,7 @@ } }, { - "__docId__": 537, + "__docId__": 536, "kind": "member", "name": "graphs", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11701,7 +11701,7 @@ } }, { - "__docId__": 538, + "__docId__": 537, "kind": "member", "name": "initialRouteDrag", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11718,7 +11718,7 @@ } }, { - "__docId__": 539, + "__docId__": 538, "kind": "member", "name": "segments", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11735,7 +11735,7 @@ } }, { - "__docId__": 540, + "__docId__": 539, "kind": "member", "name": "snapToClosestStation", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11752,7 +11752,7 @@ } }, { - "__docId__": 541, + "__docId__": 540, "kind": "member", "name": "useRawViaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11769,7 +11769,7 @@ } }, { - "__docId__": 542, + "__docId__": 541, "kind": "member", "name": "viaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11786,7 +11786,7 @@ } }, { - "__docId__": 548, + "__docId__": 547, "kind": "member", "name": "apiParams", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11803,7 +11803,7 @@ } }, { - "__docId__": 551, + "__docId__": 550, "kind": "member", "name": "apiKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11820,7 +11820,7 @@ } }, { - "__docId__": 552, + "__docId__": 551, "kind": "member", "name": "stopsApiKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11837,7 +11837,7 @@ } }, { - "__docId__": 553, + "__docId__": 552, "kind": "member", "name": "stopsApiUrl", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11854,7 +11854,7 @@ } }, { - "__docId__": 554, + "__docId__": 553, "kind": "member", "name": "api", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11871,7 +11871,7 @@ } }, { - "__docId__": 555, + "__docId__": 554, "kind": "member", "name": "routingLayer", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11888,7 +11888,7 @@ } }, { - "__docId__": 556, + "__docId__": 555, "kind": "member", "name": "onRouteError", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11905,7 +11905,7 @@ } }, { - "__docId__": 560, + "__docId__": 559, "kind": "method", "name": "getGraphsResolutions", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11937,7 +11937,7 @@ } }, { - "__docId__": 561, + "__docId__": 560, "kind": "method", "name": "abortRequests", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11952,7 +11952,7 @@ "return": null }, { - "__docId__": 563, + "__docId__": 562, "kind": "method", "name": "activate", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11968,7 +11968,7 @@ "return": null }, { - "__docId__": 565, + "__docId__": 564, "kind": "member", "name": "graphsResolutions", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -11985,7 +11985,7 @@ } }, { - "__docId__": 566, + "__docId__": 565, "kind": "method", "name": "addListeners", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12000,7 +12000,7 @@ "return": null }, { - "__docId__": 567, + "__docId__": 566, "kind": "member", "name": "onMapClickKey", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12017,7 +12017,7 @@ } }, { - "__docId__": 568, + "__docId__": 567, "kind": "method", "name": "addViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12068,7 +12068,7 @@ "return": null }, { - "__docId__": 569, + "__docId__": 568, "kind": "method", "name": "createDefaultElement", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12083,7 +12083,7 @@ "return": null }, { - "__docId__": 570, + "__docId__": 569, "kind": "member", "name": "element", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12100,7 +12100,7 @@ } }, { - "__docId__": 571, + "__docId__": 570, "kind": "method", "name": "createModifyInteraction", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12115,7 +12115,7 @@ "return": null }, { - "__docId__": 572, + "__docId__": 571, "kind": "member", "name": "modifyInteraction", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12134,7 +12134,7 @@ } }, { - "__docId__": 573, + "__docId__": 572, "kind": "method", "name": "deactivate", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12150,7 +12150,7 @@ "return": null }, { - "__docId__": 574, + "__docId__": 573, "kind": "method", "name": "drawRoute", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12169,7 +12169,7 @@ } }, { - "__docId__": 581, + "__docId__": 580, "kind": "method", "name": "drawViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12207,7 +12207,7 @@ } }, { - "__docId__": 584, + "__docId__": 583, "kind": "method", "name": "onActiveChange", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12222,7 +12222,7 @@ "return": null }, { - "__docId__": 585, + "__docId__": 584, "kind": "method", "name": "onMapClick", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12244,7 +12244,7 @@ "return": null }, { - "__docId__": 586, + "__docId__": 585, "kind": "method", "name": "onModifyEnd", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12270,7 +12270,7 @@ } }, { - "__docId__": 587, + "__docId__": 586, "kind": "method", "name": "onModifyStart", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12292,7 +12292,7 @@ "return": null }, { - "__docId__": 589, + "__docId__": 588, "kind": "method", "name": "removeListeners", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12307,7 +12307,7 @@ "return": null }, { - "__docId__": 590, + "__docId__": 589, "kind": "method", "name": "removeViaPoint", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12333,7 +12333,7 @@ "return": null }, { - "__docId__": 591, + "__docId__": 590, "kind": "method", "name": "render", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12349,7 +12349,7 @@ "return": null }, { - "__docId__": 592, + "__docId__": 591, "kind": "method", "name": "reset", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12364,7 +12364,7 @@ "return": null }, { - "__docId__": 594, + "__docId__": 593, "kind": "method", "name": "setMap", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12387,7 +12387,7 @@ "return": null }, { - "__docId__": 596, + "__docId__": 595, "kind": "method", "name": "setViaPoints", "memberof": "build/ol/controls/RoutingControl.js~RoutingControl", @@ -12413,7 +12413,7 @@ "return": null }, { - "__docId__": 598, + "__docId__": 597, "kind": "file", "name": "build/ol/controls/StopFinderControl.js", "content": "import Control from 'ol/control/Control';\nimport { fromLonLat } from 'ol/proj';\nimport StopFinderControlCommon from '../../common/controls/StopFinderControlCommon';\nimport createDefaultStopFinderElement from '../../common/utils/createDefaultStopFinderElt';\n/**\n * This OpenLayers control allows to search stations from the [geOps Stops API](https://developer.geops.io/apis/stops/).\n *\n * @example\n * import { Map } from 'ol';\n * import { StopFinderControl } from 'mobility-toolbox-js/ol';\n *\n * const map = new Map({\n * target: 'map',\n * });\n *\n * const control = new StopFinderControl({\n * apiKey: [yourApiKey]\n * });\n *\n * map.addControl(control);\n *\n *\n * @see Openlayers search example\n *\n * @extends {ol/control/Control~Control}\n *\n * @public\n */\nclass StopFinderControl extends Control {\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {HTMLElement} options.element HTML element where to attach input and suggestions.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {StopsSearchParams} [options.apiParams={ limit: 20 }] Request parameters. See [geOps Stops API documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).\n * @param {string} [options.placeholder='Search for a stop...'] Input field placeholder.\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] [geOps Stops API](https://developer.geops.io/apis/stops/) url.\n * @public\n */\n constructor(options) {\n const element = createDefaultStopFinderElement();\n element.className = (options === null || options === void 0 ? void 0 : options.className) || 'mbt-stop-finder';\n const opt = Object.assign({ element }, (options || {}));\n super(opt);\n this.controller = new StopFinderControlCommon(Object.assign({ onSuggestionClick: this.onSuggestionClick.bind(this) }, opt));\n }\n onSuggestionClick(suggestion) {\n var _a;\n const coord = fromLonLat(suggestion.geometry.coordinates);\n (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.getView().setCenter(coord);\n }\n /**\n * Search for stations using a query.\n *\n * @param {string} q Query used to search stops.\n * @param {AbortController} abortController Abort controller used to abort requests.\n * @returns {Promise>}\n * @public\n */\n search(q, abortController) {\n return this.controller.search(q, abortController);\n }\n}\nexport default StopFinderControl;\n", @@ -12424,7 +12424,7 @@ "lineNumber": 1 }, { - "__docId__": 599, + "__docId__": 598, "kind": "class", "name": "StopFinderControl", "memberof": "build/ol/controls/StopFinderControl.js", @@ -12448,7 +12448,7 @@ ] }, { - "__docId__": 600, + "__docId__": 599, "kind": "constructor", "name": "constructor", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12529,7 +12529,7 @@ ] }, { - "__docId__": 601, + "__docId__": 600, "kind": "member", "name": "controller", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12546,7 +12546,7 @@ } }, { - "__docId__": 602, + "__docId__": 601, "kind": "method", "name": "onSuggestionClick", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12569,7 +12569,7 @@ "return": null }, { - "__docId__": 603, + "__docId__": 602, "kind": "method", "name": "search", "memberof": "build/ol/controls/StopFinderControl.js~StopFinderControl", @@ -12618,7 +12618,7 @@ } }, { - "__docId__": 604, + "__docId__": 603, "kind": "file", "name": "build/ol/controls/index.js", "content": "export { default as CopyrightControl } from './CopyrightControl';\nexport { default as RoutingControl } from './RoutingControl';\nexport { default as StopFinderControl } from './StopFinderControl';\n", @@ -12629,7 +12629,7 @@ "lineNumber": 1 }, { - "__docId__": 605, + "__docId__": 604, "kind": "file", "name": "build/ol/index.js", "content": "export * from '../api';\nexport * from '../common';\nexport * from './controls';\nexport * from './layers';\nexport * from './styles';\nexport * from './utils';\n", @@ -12640,7 +12640,7 @@ "lineNumber": 1 }, { - "__docId__": 606, + "__docId__": 605, "kind": "file", "name": "build/ol/layers/Layer.js", "content": "import debounce from 'lodash.debounce';\nimport OLLayer from 'ol/layer/Layer';\nimport { unByKey } from 'ol/Observable';\nimport LayerRenderer from 'ol/renderer/Layer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n // eslint-disable-next-line no-console\n console.warn(message);\n }, 1000);\n}\nclass EmptyLayerRenderer extends LayerRenderer {\n prepareFrame() {\n return true;\n }\n renderFrame() {\n // Return an empty div as a placeholder HTMLElement\n return document.createElement('div');\n }\n}\n/**\n * An OpenLayers layer here only for backward compatibility v2.\n * @deprecated Use an OpenLayers Layer instead.\n */\nclass Layer extends OLLayer {\n constructor(options = {}) {\n super(options);\n this.olEventsKeys = [];\n defineDeprecatedProperties(this, options);\n deprecated('Layer is deprecated. Use an OpenLayers Layer instead.');\n // Backward compatibility\n this.olEventsKeys = [];\n }\n clone(newOptions) {\n return new Layer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n // ol does not like when it returns null.\n createRenderer() {\n return new EmptyLayerRenderer(this);\n }\n detachFromMap() {\n // Backward compatibility\n unByKey(this.olEventsKeys);\n }\n}\nexport default Layer;\n", @@ -12651,7 +12651,7 @@ "lineNumber": 1 }, { - "__docId__": 607, + "__docId__": 606, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/Layer.js", @@ -12671,7 +12671,7 @@ "ignore": true }, { - "__docId__": 608, + "__docId__": 607, "kind": "class", "name": "EmptyLayerRenderer", "memberof": "build/ol/layers/Layer.js", @@ -12691,7 +12691,7 @@ "ignore": true }, { - "__docId__": 609, + "__docId__": 608, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/layers/Layer.js~EmptyLayerRenderer", @@ -12711,7 +12711,7 @@ } }, { - "__docId__": 610, + "__docId__": 609, "kind": "method", "name": "renderFrame", "memberof": "build/ol/layers/Layer.js~EmptyLayerRenderer", @@ -12731,7 +12731,7 @@ } }, { - "__docId__": 611, + "__docId__": 610, "kind": "class", "name": "Layer", "memberof": "build/ol/layers/Layer.js", @@ -12750,7 +12750,7 @@ ] }, { - "__docId__": 612, + "__docId__": 611, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12764,7 +12764,7 @@ "undocument": true }, { - "__docId__": 613, + "__docId__": 612, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12781,7 +12781,7 @@ } }, { - "__docId__": 615, + "__docId__": 614, "kind": "method", "name": "clone", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12808,7 +12808,7 @@ } }, { - "__docId__": 616, + "__docId__": 615, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12828,7 +12828,7 @@ } }, { - "__docId__": 617, + "__docId__": 616, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/Layer.js~Layer", @@ -12844,7 +12844,7 @@ "return": null }, { - "__docId__": 618, + "__docId__": 617, "kind": "file", "name": "build/ol/layers/MaplibreLayer.js", "content": "import { getMapLibreAttributions, MapLibreLayer, } from '@geoblocks/ol-maplibre-layer/lib';\nimport debounce from 'lodash.debounce';\nimport { unByKey } from 'ol/Observable';\nimport { Source } from 'ol/source';\nimport { getUrlWithParams } from '../../common/utils';\nimport getUrlWithPath from '../../common/utils/getUrlWithPath';\nimport MaplibreLayerRenderer from '../renderers/MaplibreLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nconst buildStyleUrl = (url, style, apiKey, apiKeyName) => {\n return getUrlWithParams(getUrlWithPath(url, `/styles/${style}/style.json`), {\n [apiKeyName]: apiKey,\n }).toString();\n};\nexport let deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((message) => {\n console.warn(message);\n }, 1000);\n}\n/**\n * An OpenLayers layer able to display data from the [geOps Maps API](https://developer.geops.io/apis/maps).\n *\n * @example\n * import { MaplibreLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * // apiKeyName: 'key',\n * // mapLibreOptions: {\n * // interactive: false,\n * // trackResize: false,\n * // attributionControl: false,\n * // }\n * // queryRenderedFeaturesOptions: {\n * // layers: ['waters_lakes'], // map.getFeaturesAtPixel will only return lakes.\n * // },\n * // style: 'travic_v2',\n * // url: 'https://maps.geops.io',\n * });\n *\n * @classproperty {maplibregl.Map} mapLibreMap - The Maplibre map object. Readonly.\n * @classproperty {string} style - The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n *\n *\n * @see OpenLayers Maplibre layer example\n *\n * @extends {geoblocks/ol-maplibre-layer/MapLibreLayer}\n * @public\n */\nclass MaplibreLayer extends MapLibreLayer {\n set apiKey(newValue) {\n this.set('apiKey', newValue);\n }\n get apiKey() {\n return this.get('apiKey');\n }\n set apiKeyName(newValue) {\n this.set('apiKeyName', newValue);\n }\n get apiKeyName() {\n return this.get('apiKeyName');\n }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get maplibreMap() {\n deprecated('MaplibreLayer.maplibreMap is deprecated. Use layer.mapLibreMap.');\n return this.mapLibreMap;\n }\n // get queryRenderedFeaturesOptions(): maplibregl.QueryRenderedFeaturesOptions {\n // return this.get('queryRenderedFeaturesOptions');\n // }\n // set queryRenderedFeaturesOptions(\n // newValue: maplibregl.QueryRenderedFeaturesOptions,\n // ) {\n // this.set('queryRenderedFeaturesOptions', newValue);\n // }\n /**\n * @deprecated Use layer.mapLibreMap.\n */\n get mbMap() {\n deprecated('MaplibreLayer.mbMap is deprecated. Use layer.maplibreMap.');\n return this.maplibreMap;\n }\n get style() {\n return this.get('style');\n }\n set style(newValue) {\n this.set('style', newValue);\n }\n get url() {\n return this.get('url');\n }\n set url(newValue) {\n this.set('url', newValue);\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Accesss key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiKeyName=\"key\"] The [geOps Maps API](https://developer.geops.io/apis/maps) key name.\n * @param {maplibregl.MapOptions} [options.mapLibreOptions={ interactive: false, trackResize: false, attributionControl: false }] MapLibre map options.\n * @param {string} [options.style=\"travic_v2\"] The [geOps Maps API](https://developer.geops.io/apis/maps) style.\n * @param {string} [options.url=\"https://maps.geops.io\"] The [geOps Maps API](https://developer.geops.io/apis/maps) url.\n */\n constructor(options) {\n var _a, _b;\n // Backward compatibility\n if (options.mapOptions && !options.mapLibreOptions) {\n deprecated('MaplibreLayer.mapOptions is deprecated. Use mapLibreOptions instead.');\n options.mapLibreOptions = options.mapOptions;\n }\n const newOptions = Object.assign(Object.assign({ apiKeyName: 'key', style: 'travic_v2', url: 'https://maps.geops.io' }, (options || {})), { mapLibreOptions: Object.assign({ fadeDuration: 10 }, (options.mapLibreOptions || {})), source: (_a = options.source) !== null && _a !== void 0 ? _a : new Source({\n // We define a default source until https://github.com/geoblocks/ol-maplibre-layer/pull/274/files\n // is merged and published\n attributions: () => {\n var _a, _b;\n const style = (_a = this.mapLibreMap) === null || _a === void 0 ? void 0 : _a.style;\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n if (!!this.mapLibreMap && !!style && !style.sourceCaches) {\n // @ts-expect-error - sourceCaches exists in maplibre-gl < 5.11.0\n this.mapLibreMap.style.sourceCaches =\n (_b = this.mapLibreMap.style.tileManagers) !== null && _b !== void 0 ? _b : {};\n }\n return getMapLibreAttributions(this.mapLibreMap);\n },\n }) });\n if (!newOptions.mapLibreOptions.style &&\n ((_b = newOptions.url) === null || _b === void 0 ? void 0 : _b.includes('style.json'))) {\n newOptions.mapLibreOptions.style = newOptions.url;\n }\n else if (!newOptions.mapLibreOptions.style &&\n newOptions.apiKey &&\n newOptions.style &&\n typeof newOptions.style === 'string') {\n newOptions.mapLibreOptions.style = buildStyleUrl(newOptions.url, newOptions.style, newOptions.apiKey, newOptions.apiKeyName);\n }\n super(newOptions);\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // We save the options to be able to clone the layer.\n // and to see if the style is defined by the maplibreOptions given by the user.\n this.set('options', options);\n }\n /**\n * Initialize the layer and listen to feature clicks.\n */\n attachToMap() {\n const updateMaplibreMapDebounced = debounce(this.updateMaplibreMap.bind(this), 150);\n this.olEventsKeys.push(this.on('propertychange', (evt) => {\n if (/(url|style|apiKey|apiKeyName)/.test(evt.key)) {\n updateMaplibreMapDebounced();\n }\n }));\n }\n /**\n * Create a copy of the MaplibreLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MaplibreLayer} A MaplibreLayer layer\n * @public\n */\n clone(newOptions) {\n return new MaplibreLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreLayerRenderer(this);\n }\n detachFromMap() {\n unByKey(this.olEventsKeys);\n }\n disposeInternal() {\n const source = this.getSource();\n super.disposeInternal();\n // At this point mapLibreMap.style is undefined, so to avoid errors on layers removed after this one,\n // we set the mapLibreMap to null\n this.mapLibreMap = undefined;\n // We don't want the source removed\n this.setSource(source);\n }\n getStyle() {\n var _a;\n // If the style is a complete style object, use it directly.\n if (this.style &&\n typeof this.style === 'object' &&\n this.style.name &&\n this.style.version) {\n return this.style;\n }\n // If the url set is already a complete style url, use it directly.\n if (this.url.includes('style.json')) {\n return this.url;\n }\n // If the user has defined the style by the maplibreOptions, we use it directly.\n const opts = this.get('options');\n if ((_a = opts === null || opts === void 0 ? void 0 : opts.mapLibreOptions) === null || _a === void 0 ? void 0 : _a.style) {\n return opts.mapLibreOptions.style;\n }\n /// Otherwise build the complete style url.\n return buildStyleUrl(this.url, this.style, this.apiKey, this.apiKeyName);\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n updateMaplibreMap() {\n var _a;\n try {\n (_a = this.mapLibreMap) === null || _a === void 0 ? void 0 : _a.setStyle(this.getStyle(), { diff: false });\n }\n catch (e) {\n console.error('Error while updating MaplibreMap', e);\n }\n }\n}\nexport default MaplibreLayer;\n", @@ -12855,7 +12855,7 @@ "lineNumber": 1 }, { - "__docId__": 619, + "__docId__": 618, "kind": "function", "name": "buildStyleUrl", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12904,7 +12904,7 @@ "ignore": true }, { - "__docId__": 620, + "__docId__": 619, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12923,7 +12923,7 @@ "return": null }, { - "__docId__": 621, + "__docId__": 620, "kind": "class", "name": "MaplibreLayer", "memberof": "build/ol/layers/MaplibreLayer.js", @@ -12957,7 +12957,7 @@ ] }, { - "__docId__": 622, + "__docId__": 621, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12971,7 +12971,7 @@ "undocument": true }, { - "__docId__": 623, + "__docId__": 622, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -12990,7 +12990,7 @@ } }, { - "__docId__": 624, + "__docId__": 623, "kind": "set", "name": "apiKeyName", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13004,7 +13004,7 @@ "undocument": true }, { - "__docId__": 625, + "__docId__": 624, "kind": "get", "name": "apiKeyName", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13023,7 +13023,7 @@ } }, { - "__docId__": 626, + "__docId__": 625, "kind": "get", "name": "maplibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13042,7 +13042,7 @@ } }, { - "__docId__": 627, + "__docId__": 626, "kind": "get", "name": "mbMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13061,7 +13061,7 @@ } }, { - "__docId__": 628, + "__docId__": 627, "kind": "get", "name": "style", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13080,7 +13080,7 @@ } }, { - "__docId__": 629, + "__docId__": 628, "kind": "set", "name": "style", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13094,7 +13094,7 @@ "undocument": true }, { - "__docId__": 630, + "__docId__": 629, "kind": "get", "name": "url", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13113,7 +13113,7 @@ } }, { - "__docId__": 631, + "__docId__": 630, "kind": "set", "name": "url", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13127,7 +13127,7 @@ "undocument": true }, { - "__docId__": 632, + "__docId__": 631, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13210,7 +13210,7 @@ ] }, { - "__docId__": 633, + "__docId__": 632, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13227,7 +13227,7 @@ } }, { - "__docId__": 634, + "__docId__": 633, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13242,7 +13242,7 @@ "return": null }, { - "__docId__": 635, + "__docId__": 634, "kind": "method", "name": "clone", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13275,7 +13275,7 @@ } }, { - "__docId__": 636, + "__docId__": 635, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13295,7 +13295,7 @@ } }, { - "__docId__": 637, + "__docId__": 636, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13311,7 +13311,7 @@ "return": null }, { - "__docId__": 638, + "__docId__": 637, "kind": "method", "name": "disposeInternal", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13327,7 +13327,7 @@ "return": null }, { - "__docId__": 639, + "__docId__": 638, "kind": "member", "name": "mapLibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13344,7 +13344,7 @@ } }, { - "__docId__": 640, + "__docId__": 639, "kind": "method", "name": "getStyle", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13364,7 +13364,7 @@ } }, { - "__docId__": 641, + "__docId__": 640, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13387,7 +13387,7 @@ "return": null }, { - "__docId__": 642, + "__docId__": 641, "kind": "method", "name": "updateMaplibreMap", "memberof": "build/ol/layers/MaplibreLayer.js~MaplibreLayer", @@ -13403,7 +13403,7 @@ "return": null }, { - "__docId__": 643, + "__docId__": 642, "kind": "file", "name": "build/ol/layers/MaplibreStyleLayer.js", "content": "import debounce from 'lodash.debounce';\nimport { Layer } from 'ol/layer';\nimport { unByKey } from 'ol/Observable';\nimport { Source } from 'ol/source';\nimport { VECTOR_TILE_FEATURE_PROPERTY } from '../../common';\nimport MaplibreStyleLayerRenderer from '../renderers/MaplibreStyleLayerRenderer';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nlet deprecated = () => { };\nif (typeof window !== 'undefined' &&\n new URLSearchParams(window.location.search).get('deprecated')) {\n deprecated = debounce((...messages) => {\n // eslint-disable-next-line no-console\n console.warn(...messages);\n }, 1000);\n}\n/**\n * Layer that helps show/hide a specific subset of style layers of a [MaplibreLayer](./MaplibreLayer.js~MaplibreLayer.html).\n *\n * @example\n * import { MaplibreLayer, MocoLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * maplibreLayer: maplibreLayer,\n * layersFilter: (layer) => {\n * // show/hide only style layers related to stations\n * return /station/.test(layer.id);\n * },\n * });\n *\n * @extends {ol/layer/Layer~Layer}\n * @public\n */\nclass MaplibreStyleLayer extends Layer {\n get beforeId() {\n return this.get('beforeId');\n }\n set beforeId(newValue) {\n this.set('beforeId', newValue);\n }\n get layers() {\n return this.get('layers') || [];\n }\n set layers(newValue) {\n this.set('layers', newValue);\n }\n get layersFilter() {\n return this.get('layersFilter');\n }\n set layersFilter(newValue) {\n this.set('layersFilter', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.maplibreLayer instead.\n */\n get mapboxLayer() {\n deprecated('Deprecated. Use maplibreLayer instead.');\n return this.get('maplibreLayer');\n }\n get maplibreLayer() {\n return this.get('maplibreLayer');\n }\n set maplibreLayer(newValue) {\n this.set('maplibreLayer', newValue);\n }\n get queryRenderedLayersFilter() {\n return this.get('queryRenderedLayersFilter');\n }\n set queryRenderedLayersFilter(newValue) {\n this.set('queryRenderedLayersFilter', newValue);\n }\n get sources() {\n return this.get('sources');\n }\n set sources(newValue) {\n this.set('sources', newValue);\n }\n /**\n * @deprecated Use MaplibreStyleLayer.layer instead.\n */\n get styleLayer() {\n deprecated('Deprecated. Use MaplibreStyleLayer.layer instead.');\n return this.layers[0];\n }\n /**\n * @deprecated\n */\n set styleLayer(newValue) {\n deprecated('MaplibreStyleLayer.styleLayer is deprecated. Use MaplibreStyleLayer.layer instead.');\n this.layers = [newValue];\n }\n /**\n * Apply visibility to style layers that fits the styleLayersFilter function.\n */\n /**\n * @deprecated\n */\n get styleLayers() {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n return this.layers;\n }\n /**\n * @deprecated\n */\n set styleLayers(newValue) {\n deprecated('MaplibreStyleLayer.styleLayers is deprecated. Use MaplibreStyleLayer.layers instead.');\n this.layers = newValue;\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} [options.beforeId] The style layer id to use when the options.layers property is defined, unsused otherwise.\n * @param {maplibregl.AddLayerObject[]} [options.layers] The layers to add to the style on load.\n * @param {FilterFunction} [options.layersFilter] Filter function to decide which style layer to apply visiblity on. If not provided, the 'layers' property is used.\n * @param {MaplibreLayer} [options.maplibreLayer] The MaplibreLayer to use.\n * @param {FilterFunction} [options.queryRenderedLayersFilter] Filter function to decide which style layer are available for query.\n * @param {{[id: string]:maplibregl.SourceSpecification}} [options.sources] The sources to add to the style on load.\n * @public\n */\n constructor(options = {\n mapLibreOptions: { style: { layers: [], sources: {}, version: 8 } },\n }) {\n /** Manage renamed property for backward compatibility with v2 */\n if (options.mapboxLayer) {\n deprecated('options.mapboxLayer is deprecated. Use options.maplibreLayer instead.');\n // @ts-expect-error - mapboxLayer is deprecated\n options.maplibreLayer = options.mapboxLayer;\n delete options.mapboxLayer;\n }\n if (options.styleLayer) {\n deprecated('options.styleLayer is deprecated. Use options.layers instead.');\n options.layers = [options.styleLayer];\n delete options.styleLayer;\n }\n if (options.styleLayers) {\n deprecated('options.styleLayers is deprecated. Use options.layers instead.');\n options.layers = options.styleLayers;\n delete options.styleLayers;\n }\n if (options.styleLayersFilter) {\n deprecated('options.styleLayersFilter is deprecated. Use options.layersFilter instead.');\n options.layersFilter = options.styleLayersFilter;\n delete options.styleLayersFilter;\n }\n super(Object.assign({ source: new Source({}) }, options));\n this.highlightedFeatures = [];\n this.olEventsKeys = [];\n this.selectedFeatures = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n // For cloning\n this.set('options', options);\n this.beforeId = options.beforeId;\n this.onLoad = this.onLoad.bind(this);\n if (!this.layersFilter && this.layers) {\n this.layersFilter = (layer) => {\n return !!this.layers.find((l) => {\n return layer.id === l.id;\n });\n };\n }\n }\n addLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((layer) => {\n // @ts-expect-error source is optional but exists in TS definition\n const { id, source } = layer;\n if ((!source || (source && mapLibreMap.getSource(source))) &&\n id &&\n !mapLibreMap.getLayer(id)) {\n mapLibreMap.addLayer(layer, this.beforeId);\n }\n });\n this.applyLayoutVisibility();\n }\n }\n addSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.entries(this.sources).forEach(([id, source]) => {\n if (!mapLibreMap.getSource(id)) {\n mapLibreMap.addSource(id, source);\n }\n });\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n applyLayoutVisibility(evt) {\n var _a, _b, _c, _d, _e, _f;\n if (!((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()) || !this.layersFilter) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n const visibilityValue = this.getVisible() ? 'visible' : 'none';\n const layers = style.layers || [];\n // OL sets -Infinity, Infinity for minZoom and maxZoom.\n const isFiniteMinZoom = Number.isFinite(this.getMinZoom());\n const isFiniteMaxZoom = Number.isFinite(this.getMaxZoom());\n // Maplibre zoom = ol zoom - 1\n const minZoom = isFiniteMinZoom ? this.getMinZoom() - 1 : 0;\n const maxZoom = isFiniteMaxZoom ? this.getMaxZoom() - 1 : 24;\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < layers.length; i += 1) {\n const layer = layers[i];\n if (this.layersFilter(layer)) {\n const { id } = layer;\n if (mapLibreMap.getLayer(id)) {\n mapLibreMap.setLayoutProperty(id, 'visibility', visibilityValue);\n if (isFiniteMinZoom || isFiniteMaxZoom) {\n const currentMinZoom = (_d = (_c = mapLibreMap.getLayer(id)) === null || _c === void 0 ? void 0 : _c.minzoom) !== null && _d !== void 0 ? _d : 0;\n const currentMaxZoom = (_f = (_e = mapLibreMap.getLayer(id)) === null || _e === void 0 ? void 0 : _e.maxzoom) !== null && _f !== void 0 ? _f : 24;\n mapLibreMap.setLayerZoomRange(id, currentMinZoom < minZoom ? minZoom : currentMinZoom, currentMaxZoom > maxZoom ? maxZoom : currentMaxZoom);\n }\n }\n }\n }\n }\n /**\n * Initialize the layer.\n * @param {ol/Map~Map} map the Maplibre map.\n * @override\n */\n attachToMap(map) {\n const mapInternal = this.getMapInternal();\n if (!mapInternal || !this.maplibreLayer) {\n return;\n }\n // Apply the initial visibility if possible otherwise we wait for the load event of the layer\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n // mapLibreMap.loaded() and mapLibreMap.isStyleLoaded() are reliable only on the first call of init.\n // On the next call (when a topic change for example), these functions returns false because\n // the style is being modified.\n // That's why we rely on a property instead for the next calls.\n if (mapLibreMap.loaded()) {\n this.onLoad();\n }\n else {\n if (mapLibreMap.isStyleLoaded()) {\n this.onLoad();\n }\n else {\n void mapLibreMap.once('load', this.onLoad);\n }\n }\n }\n // Apply the visibiltity when layer's visibility change.\n this.olEventsKeys.push(\n // @ts-expect-error 'load' is a custom event\n this.maplibreLayer.on('load', this.onLoad.bind(this)), this.on('change:visible', (evt) => {\n // Once the map is loaded we can apply visiblity without waiting\n // the style. Maplibre take care of the application of style changes.\n this.applyLayoutVisibility(evt);\n }), this.on('propertychange', (evt) => {\n if (/(sources|layers|layersFilter|maplibreLayer|beforeId)/.test(evt.key)) {\n this.detachFromMap();\n this.attachToMap(map);\n }\n }), \n // When the style changes we wait that it is loaded to relaunch the onLoad\n this.maplibreLayer.on('propertychange', (evt) => {\n if (evt.key === 'style') {\n const mbMap = evt.target.mapLibreMap;\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('styledata', () => {\n void (mbMap === null || mbMap === void 0 ? void 0 : mbMap.once('idle', () => {\n this.onLoad();\n }));\n }));\n }\n }));\n }\n /**\n * Create a copy of the MaplibreStyleLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {MapboxStyleLayer} A MaplibreStyleLayer.\n * @public\n */\n clone(newOptions) {\n return new MaplibreStyleLayer(Object.assign(Object.assign({}, (this.get('options') || {})), (newOptions || {})));\n }\n createRenderer() {\n return new MaplibreStyleLayerRenderer(this);\n }\n /**\n * Terminate the layer.\n * @override\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n if ((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) {\n this.maplibreLayer.mapLibreMap.off('load', this.onLoad);\n this.removeLayers();\n this.removeSources();\n }\n }\n // /**\n // * Request feature information for a given coordinate.\n // * @param {ol/coordinate~Coordinate} coordinate Coordinate to request the information at.\n // * @return {Promise} Promise with features, layer and coordinate.\n // * @deprecated Use getFeatureInfoAtCoordinate([layer], coordinate) from mobility-toolbox-ol package instead.\n // */\n // getFeatureInfoAtCoordinate(\n // coordinate: Coordinate,\n // ): Promise {\n // deprecated(\n // `Deprecated. getFeatureInfoAtCoordinate([layer], coordinate) from ol package instead.`,\n // );\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // // Ignore the getFeatureInfo until the Maplibre map is loaded\n // if (!mapLibreMap.isStyleLoaded()) {\n // return Promise.resolve({ coordinate, features: [], layer: this });\n // }\n // // We query features only on style layers used by this layer.\n // let layers = this.layers || [];\n // if (this.layersFilter) {\n // layers = mapLibreMap.getStyle().layers.filter(this.layersFilter);\n // }\n // if (this.queryRenderedLayersFilter) {\n // layers = mapLibreMap\n // .getStyle()\n // .layers.filter(this.queryRenderedLayersFilter);\n // }\n // return Promise.resolve({\n // coordinate,\n // features: [],\n // layer: this,\n // });\n // // this.maplibreLayer\n // // .getFeatureInfoAtCoordinate(coordinate, {\n // // layers: layers.map((layer) => layer && layer.id),\n // // validate: false,\n // // })\n // // .then((featureInfo: LayerGetFeatureInfoResponse) => {\n // // const features: Feature[] = featureInfo.features.filter(\n // // (feature: Feature) => {\n // // // @ts-expect-error\n // // return this.featureInfoFilter(\n // // feature,\n // // this.map?.getView().getResolution(),\n // // ) as Feature[];\n // // },\n // // );\n // // this.highlight(features);\n // // return { ...featureInfo, features, layer: this };\n // // });\n // }\n /**\n * Highlight a list of features.\n * @param {Array
                } [features=[]] Features to highlight.\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n highlight(features = []) {\n var _a;\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: true}) instead.`);\n // Filter out selected features\n const filtered = ((_a = this.highlightedFeatures) === null || _a === void 0 ? void 0 : _a.filter((feature) => {\n return !(this.selectedFeatures || [])\n .map((feat) => {\n return feat.getId();\n })\n .includes(feature.getId());\n })) || [];\n // Remove previous highlight\n this.setHoverState(filtered, false);\n this.highlightedFeatures = features;\n // Add highlight\n this.setHoverState(this.highlightedFeatures, true);\n }\n /**\n * On Maplibre map load callback function. Add style layers and dynaimc filters.\n */\n onLoad() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap)) {\n return;\n }\n this.addSources();\n this.addLayers();\n const { mapLibreMap } = this.maplibreLayer;\n const style = mapLibreMap.getStyle();\n if ((style === null || style === void 0 ? void 0 : style.layers) && this.layersFilter) {\n const styles = style.layers.filter(this.layersFilter);\n this.set('disabled', !styles.length);\n }\n this.applyLayoutVisibility();\n }\n removeLayers() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !Array.isArray(this.layers)) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n this.layers.forEach((styleLayer) => {\n const { id } = styleLayer;\n if (id && (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.getLayer(id))) {\n mapLibreMap.removeLayer(id);\n }\n });\n }\n }\n // /**\n // * Set filter that determines which features should be rendered in a style layer.\n // * @param {maplibregl.filter} filter Determines which features should be rendered in a style layer.\n // */\n // setFilter(filter: { [key: string]: any }) {\n // if (!this.maplibreLayer?.mapLibreMap) {\n // return;\n // }\n // const { mapLibreMap } = this.maplibreLayer;\n // this.styleLayers.forEach(({ id }) => {\n // if (id && filter && mapLibreMap.getLayer(id)) {\n // // @ts-expect-error\n // mapLibreMap.setFilter(id, filter);\n // }\n // });\n // }\n removeSources() {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !this.sources) {\n return;\n }\n const { mapLibreMap } = this.maplibreLayer;\n if (mapLibreMap) {\n Object.keys(this.sources).forEach((id) => {\n if (mapLibreMap.getSource(id)) {\n mapLibreMap.removeSource(id);\n }\n });\n }\n }\n /**\n * Select a list of features.\n * @param {Array
                  } [features=[]] Features to select.\n * @deprecated Use layer.setFeatureState(features, {selected: true|false}) instead.\n */\n select(features = []) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {selected: true}) instead.`);\n this.setHoverState(this.selectedFeatures || [], false);\n this.selectedFeatures = features;\n this.setHoverState(this.selectedFeatures || [], true);\n }\n /**\n * Set the [feature state](https://maplibre.org/maplibre-style-spec/expressions/#feature-state) of the features.\n *\n * @param {ol/Feature~Feature[]} features\n * @param {{[key: string]: any}} state The feature state\n * @public\n */\n setFeatureState(features, state) {\n var _a;\n if (!((_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) || !features.length) {\n return;\n }\n const mapLibreMap = this.maplibreLayer.mapLibreMap;\n features.forEach((feature) => {\n const { source, sourceLayer } = (feature.get(VECTOR_TILE_FEATURE_PROPERTY) || {});\n if ((!source && !sourceLayer) || !feature.getId()) {\n if (!feature.getId()) {\n deprecated(\"No feature's id found. To use the feature state functionnality, tiles must be generated with --generate-ids. See https://github.com/Maplibre/tippecanoe#adding-calculated-attributes.\", feature.getProperties());\n }\n return;\n }\n if (source) {\n mapLibreMap.setFeatureState({\n id: feature.getId(),\n source,\n sourceLayer,\n }, state);\n }\n else {\n deprecated('No source found for the feature. To use the feature state functionnality, a source must be defined.', feature.getProperties());\n }\n });\n }\n /**\n * Set if features are hovered or not.\n * @param {Array
                    } features\n * @param {boolean} state Is the feature hovered\n * @deprecated Use layer.setFeatureState(features, {hover: true|false}) instead.\n */\n setHoverState(features, state) {\n deprecated(`Deprecated. Use layer.setFeatureState(features, {hover: ${state}}) instead.`);\n this.setFeatureState(features, { hover: state });\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap(map);\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n}\nexport default MaplibreStyleLayer;\n", @@ -13414,7 +13414,7 @@ "lineNumber": 1 }, { - "__docId__": 644, + "__docId__": 643, "kind": "function", "name": "deprecated", "memberof": "build/ol/layers/MaplibreStyleLayer.js", @@ -13434,7 +13434,7 @@ "ignore": true }, { - "__docId__": 645, + "__docId__": 644, "kind": "class", "name": "MaplibreStyleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js", @@ -13455,7 +13455,7 @@ ] }, { - "__docId__": 646, + "__docId__": 645, "kind": "get", "name": "beforeId", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13474,7 +13474,7 @@ } }, { - "__docId__": 647, + "__docId__": 646, "kind": "set", "name": "beforeId", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13488,7 +13488,7 @@ "undocument": true }, { - "__docId__": 648, + "__docId__": 647, "kind": "get", "name": "layers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13507,7 +13507,7 @@ } }, { - "__docId__": 649, + "__docId__": 648, "kind": "set", "name": "layers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13521,7 +13521,7 @@ "undocument": true }, { - "__docId__": 650, + "__docId__": 649, "kind": "get", "name": "layersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13540,7 +13540,7 @@ } }, { - "__docId__": 651, + "__docId__": 650, "kind": "set", "name": "layersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13554,7 +13554,7 @@ "undocument": true }, { - "__docId__": 652, + "__docId__": 651, "kind": "get", "name": "mapboxLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13573,7 +13573,7 @@ } }, { - "__docId__": 653, + "__docId__": 652, "kind": "get", "name": "maplibreLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13592,7 +13592,7 @@ } }, { - "__docId__": 654, + "__docId__": 653, "kind": "set", "name": "maplibreLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13606,7 +13606,7 @@ "undocument": true }, { - "__docId__": 655, + "__docId__": 654, "kind": "get", "name": "queryRenderedLayersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13625,7 +13625,7 @@ } }, { - "__docId__": 656, + "__docId__": 655, "kind": "set", "name": "queryRenderedLayersFilter", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13639,7 +13639,7 @@ "undocument": true }, { - "__docId__": 657, + "__docId__": 656, "kind": "get", "name": "sources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13658,7 +13658,7 @@ } }, { - "__docId__": 658, + "__docId__": 657, "kind": "set", "name": "sources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13672,7 +13672,7 @@ "undocument": true }, { - "__docId__": 659, + "__docId__": 658, "kind": "get", "name": "styleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13691,7 +13691,7 @@ } }, { - "__docId__": 660, + "__docId__": 659, "kind": "set", "name": "styleLayer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13705,7 +13705,7 @@ "deprecated": true }, { - "__docId__": 662, + "__docId__": 661, "kind": "get", "name": "styleLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13724,7 +13724,7 @@ } }, { - "__docId__": 663, + "__docId__": 662, "kind": "set", "name": "styleLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13738,7 +13738,7 @@ "deprecated": true }, { - "__docId__": 665, + "__docId__": 664, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13823,7 +13823,7 @@ ] }, { - "__docId__": 666, + "__docId__": 665, "kind": "member", "name": "highlightedFeatures", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13840,7 +13840,7 @@ } }, { - "__docId__": 667, + "__docId__": 666, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13857,7 +13857,7 @@ } }, { - "__docId__": 668, + "__docId__": 667, "kind": "member", "name": "selectedFeatures", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13874,7 +13874,7 @@ } }, { - "__docId__": 672, + "__docId__": 671, "kind": "method", "name": "addLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13890,7 +13890,7 @@ "return": null }, { - "__docId__": 673, + "__docId__": 672, "kind": "method", "name": "addSources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13906,7 +13906,7 @@ "return": null }, { - "__docId__": 674, + "__docId__": 673, "kind": "method", "name": "applyLayoutVisibility", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13929,7 +13929,7 @@ "return": null }, { - "__docId__": 675, + "__docId__": 674, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13956,7 +13956,7 @@ "return": null }, { - "__docId__": 676, + "__docId__": 675, "kind": "method", "name": "clone", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -13989,7 +13989,7 @@ } }, { - "__docId__": 677, + "__docId__": 676, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14009,7 +14009,7 @@ } }, { - "__docId__": 678, + "__docId__": 677, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14025,7 +14025,7 @@ "return": null }, { - "__docId__": 679, + "__docId__": 678, "kind": "method", "name": "highlight", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14054,7 +14054,7 @@ "return": null }, { - "__docId__": 681, + "__docId__": 680, "kind": "method", "name": "onLoad", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14069,7 +14069,7 @@ "return": null }, { - "__docId__": 682, + "__docId__": 681, "kind": "method", "name": "removeLayers", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14085,7 +14085,7 @@ "return": null }, { - "__docId__": 683, + "__docId__": 682, "kind": "method", "name": "removeSources", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14101,7 +14101,7 @@ "return": null }, { - "__docId__": 684, + "__docId__": 683, "kind": "method", "name": "select", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14130,7 +14130,7 @@ "return": null }, { - "__docId__": 686, + "__docId__": 685, "kind": "method", "name": "setFeatureState", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14166,7 +14166,7 @@ "return": null }, { - "__docId__": 687, + "__docId__": 686, "kind": "method", "name": "setHoverState", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14203,7 +14203,7 @@ "return": null }, { - "__docId__": 688, + "__docId__": 687, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MaplibreStyleLayer.js~MaplibreStyleLayer", @@ -14226,10 +14226,10 @@ "return": null }, { - "__docId__": 689, + "__docId__": 688, "kind": "file", "name": "build/ol/layers/MapsetLayer.js", - "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MapsetLayer_abortController;\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { transformExtent } from 'ol/proj';\nimport { Vector } from 'ol/source';\nimport MapsetAPI from '../../api/MapsetApi';\nimport MapsetKmlFormat from '../utils/MapsetKmlFormat';\nconst kmlFormatter = new MapsetKmlFormat();\n/**\n * An OpenLayers layer able to display plan data from [mapset](https://geops.com/de/solution/mapset).\n *\n * @example\n * import { MapsetLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MapsetLayer({\n * apiKey: 'yourApiKey',\n * // tags: ['test'],\n * // tenants: ['geopstest'],\n * // url: 'https://editor.mapset.io/api/v1',\n * });\n *\n * @see MapsetAPI\n * @see OpenLayers Mapset layer example\n *\n *\n * @extends {ol/layer/VectorLayer~VectorLayer}\n *\n * @public\n */\nclass MapsetLayer extends VectorLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.fetchPlans();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n if (this.api.apiKey !== value) {\n this.api.apiKey = value;\n void this.fetchPlans();\n }\n }\n get doNotRevert32pxScaling() {\n return this.get('doNotRevert32pxScaling');\n }\n set doNotRevert32pxScaling(value) {\n this.set('doNotRevert32pxScaling', value);\n this.updateFeatures();\n }\n get planId() {\n return this.get('planId');\n }\n set planId(value) {\n if (this.planId !== value) {\n this.set('planId', value);\n void this.fetchPlanById(value);\n }\n }\n get plans() {\n return this.get('plans');\n }\n set plans(value) {\n this.set('plans', value);\n this.updateFeatures();\n }\n get tags() {\n return this.api.tags;\n }\n set tags(value) {\n var _a;\n if (((_a = this.api.tags) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tags = value;\n void this.fetchPlans();\n }\n }\n get tenants() {\n return this.api.tenants;\n }\n set tenants(value) {\n var _a;\n if (((_a = this.api.tenants) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tenants = value;\n void this.fetchPlans();\n }\n }\n get timestamp() {\n return this.get('timestamp');\n }\n set timestamp(value) {\n if (this.timestamp !== value) {\n this.set('timestamp', value);\n void this.fetchPlans();\n }\n }\n get url() {\n var _a;\n return (_a = this.api) === null || _a === void 0 ? void 0 : _a.url;\n }\n set url(value) {\n var _a;\n if (this.api && ((_a = this.api) === null || _a === void 0 ? void 0 : _a.url) !== value) {\n this.api.url = value;\n void this.fetchPlans();\n }\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string[]} [options.tags] The tags of the required plans.\n * @param {string} [options.timestamp] The timestamp of the required plans.\n * @param {string[]} [options.tenants] The tenants of the required plans.\n * @param {string} [options.url] The URL of the [geOps Mapset API](https://geops.com/de/solution/mapset).\n * @public\n */\n constructor(options) {\n var _a, _b;\n super(Object.assign({ source: (_a = options.source) !== null && _a !== void 0 ? _a : new Vector() }, (options || {})));\n this.loadAll = true;\n this.olEventsKeys = [];\n _MapsetLayer_abortController.set(this, void 0);\n this.api =\n (_b = options.api) !== null && _b !== void 0 ? _b : new MapsetAPI({\n apiKey: options.apiKey,\n tags: options.tags,\n tenants: options.tenants,\n url: options.url,\n });\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (options.loadAll === false) {\n this.loadAll = options.loadAll;\n }\n }\n fetchPlanById(planId) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a;\n (_a = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _a === void 0 ? void 0 : _a.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (!planId) {\n this.plans = [];\n return;\n }\n let planById;\n try {\n this.dispatchEvent('featuresloadstart');\n planById = yield this.api.getPlanById(planId, {\n signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal,\n });\n this.plans = [planById];\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return;\n }\n // eslint-disable-next-line no-console\n console.error('MapsetLayer: Error fetching plan by ID...', e);\n this.plans = [];\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n return;\n });\n }\n fetchPlans() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (!this.getVisible()) {\n return;\n }\n const view = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView();\n if (!view) {\n return;\n }\n const extent = transformExtent(view.calculateExtent(), view.getProjection(), 'EPSG:4326');\n const zoom = view.getZoom();\n if (!zoom || !extent) {\n this.plans = [];\n return;\n }\n (_b = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _b === void 0 ? void 0 : _b.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n let plans = [];\n try {\n this.dispatchEvent('featuresloadstart');\n plans = yield this.api.getPlans({\n bbox: extent === null || extent === void 0 ? void 0 : extent.toString(),\n timestamp: (_c = this.timestamp) !== null && _c !== void 0 ? _c : new Date().toISOString(),\n zoom,\n }, { signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal });\n this.plans = plans;\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n console.error('MapsetLayer: Error fetching plans...', e);\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n });\n }\n setMapInternal(map) {\n super.setMapInternal(map);\n if (map && this.loadAll) {\n void this.fetchPlans();\n this.olEventsKeys.push(map.on('moveend', () => {\n void this.fetchPlans();\n }), this.on('change:visible', () => {\n void this.fetchPlans();\n }));\n }\n else {\n unByKey(this.olEventsKeys);\n }\n if (map && this.planId) {\n void this.fetchPlanById(this.planId);\n }\n }\n updateFeatures() {\n var _a, _b, _c, _d, _e;\n (_a = this.getSource()) === null || _a === void 0 ? void 0 : _a.clear();\n const map = this.getMapInternal();\n if (map && ((_b = this.plans) === null || _b === void 0 ? void 0 : _b.length) !== 0) {\n const features = (_d = (_c = this.plans) === null || _c === void 0 ? void 0 : _c.flatMap((plan) => {\n return kmlFormatter.readFeatures(plan.data, map.getView().getProjection(), this.doNotRevert32pxScaling);\n })) !== null && _d !== void 0 ? _d : [];\n (_e = this.getSource()) === null || _e === void 0 ? void 0 : _e.addFeatures(features);\n }\n this.dispatchEvent('updatefeatures');\n }\n}\n_MapsetLayer_abortController = new WeakMap();\nexport default MapsetLayer;\n", + "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MapsetLayer_abortController;\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { transformExtent } from 'ol/proj';\nimport { Vector } from 'ol/source';\nimport MapsetAPI from '../../api/MapsetApi';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nimport MapsetKmlFormat from '../utils/MapsetKmlFormat';\nconst kmlFormatter = new MapsetKmlFormat();\n/**\n * An OpenLayers layer able to display plan data from [mapset](https://geops.com/de/solution/mapset).\n *\n * @example\n * import { MapsetLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new MapsetLayer({\n * apiKey: 'yourApiKey',\n * // tags: ['test'],\n * // tenants: ['geopstest'],\n * // url: 'https://editor.mapset.io/api/v1',\n * });\n *\n * @see MapsetAPI\n * @see OpenLayers Mapset layer example\n *\n *\n * @extends {ol/layer/VectorLayer~VectorLayer}\n *\n * @public\n */\nclass MapsetLayer extends VectorLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.fetchPlans();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n if (this.api.apiKey !== value) {\n this.api.apiKey = value;\n void this.fetchPlans();\n }\n }\n get planId() {\n return this.get('planId');\n }\n set planId(value) {\n if (this.planId !== value) {\n this.set('planId', value);\n void this.fetchPlanById(value);\n }\n }\n get plans() {\n return this.get('plans');\n }\n set plans(value) {\n this.set('plans', value);\n this.updateFeatures();\n }\n get tags() {\n return this.api.tags;\n }\n set tags(value) {\n var _a;\n if (((_a = this.api.tags) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tags = value;\n void this.fetchPlans();\n }\n }\n get tenants() {\n return this.api.tenants;\n }\n set tenants(value) {\n var _a;\n if (((_a = this.api.tenants) === null || _a === void 0 ? void 0 : _a.toString()) !== (value === null || value === void 0 ? void 0 : value.toString())) {\n this.api.tenants = value;\n void this.fetchPlans();\n }\n }\n get timestamp() {\n return this.get('timestamp');\n }\n set timestamp(value) {\n if (this.timestamp !== value) {\n this.set('timestamp', value);\n void this.fetchPlans();\n }\n }\n get url() {\n var _a;\n return (_a = this.api) === null || _a === void 0 ? void 0 : _a.url;\n }\n set url(value) {\n var _a;\n if (this.api && ((_a = this.api) === null || _a === void 0 ? void 0 : _a.url) !== value) {\n this.api.url = value;\n void this.fetchPlans();\n }\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string[]} [options.tags] The tags of the required plans.\n * @param {string} [options.timestamp] The timestamp of the required plans.\n * @param {string[]} [options.tenants] The tenants of the required plans.\n * @param {string} [options.url] The URL of the [geOps Mapset API](https://geops.com/de/solution/mapset).\n * @public\n */\n constructor(options) {\n var _a, _b;\n super(Object.assign({ source: (_a = options.source) !== null && _a !== void 0 ? _a : new Vector() }, (options || {})));\n this.loadAll = true;\n this.olEventsKeys = [];\n _MapsetLayer_abortController.set(this, void 0);\n this.api =\n (_b = options.api) !== null && _b !== void 0 ? _b : new MapsetAPI({\n apiKey: options.apiKey,\n tags: options.tags,\n tenants: options.tenants,\n url: options.url,\n });\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (options.loadAll === false) {\n this.loadAll = options.loadAll;\n }\n defineDeprecatedProperties(this, options);\n }\n fetchPlanById(planId) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a;\n (_a = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _a === void 0 ? void 0 : _a.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n if (!planId) {\n this.plans = [];\n return;\n }\n let planById;\n try {\n this.dispatchEvent('featuresloadstart');\n planById = yield this.api.getPlanById(planId, {\n signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal,\n });\n this.plans = [planById];\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return;\n }\n // eslint-disable-next-line no-console\n console.error('MapsetLayer: Error fetching plan by ID...', e);\n this.plans = [];\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n return;\n });\n }\n fetchPlans() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (!this.getVisible()) {\n return;\n }\n const view = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView();\n if (!view) {\n return;\n }\n const extent = transformExtent(view.calculateExtent(), view.getProjection(), 'EPSG:4326');\n const zoom = view.getZoom();\n if (!zoom || !extent) {\n this.plans = [];\n return;\n }\n (_b = __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\")) === null || _b === void 0 ? void 0 : _b.abort();\n __classPrivateFieldSet(this, _MapsetLayer_abortController, new AbortController(), \"f\");\n let plans = [];\n try {\n this.dispatchEvent('featuresloadstart');\n plans = yield this.api.getPlans({\n bbox: extent === null || extent === void 0 ? void 0 : extent.toString(),\n timestamp: (_c = this.timestamp) !== null && _c !== void 0 ? _c : new Date().toISOString(),\n zoom,\n }, { signal: __classPrivateFieldGet(this, _MapsetLayer_abortController, \"f\").signal });\n this.plans = plans;\n this.dispatchEvent('featuresloadend');\n }\n catch (e) {\n // @ts-expect-error Abort errors are OK\n if ((e === null || e === void 0 ? void 0 : e.name).includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n this.dispatchEvent('featuresloaderror');\n throw e;\n }\n });\n }\n setMapInternal(map) {\n super.setMapInternal(map);\n if (map && this.loadAll) {\n void this.fetchPlans();\n this.olEventsKeys.push(map.on('moveend', () => {\n void this.fetchPlans();\n }), this.on('change:visible', () => {\n void this.fetchPlans();\n }));\n }\n else {\n unByKey(this.olEventsKeys);\n }\n if (map && this.planId) {\n void this.fetchPlanById(this.planId);\n }\n }\n updateFeatures() {\n var _a, _b, _c, _d, _e;\n (_a = this.getSource()) === null || _a === void 0 ? void 0 : _a.clear();\n const map = this.getMapInternal();\n if (map && ((_b = this.plans) === null || _b === void 0 ? void 0 : _b.length) !== 0) {\n const features = (_d = (_c = this.plans) === null || _c === void 0 ? void 0 : _c.flatMap((plan) => {\n var _a;\n return kmlFormatter.readFeatures(plan.data, Object.assign({ featureProjection: map.getView().getProjection(), getResolutionForZoom: (zoom) => {\n return map.getView().getResolutionForZoom(zoom);\n } }, ((_a = this.get('readOptions')) !== null && _a !== void 0 ? _a : {})));\n })) !== null && _d !== void 0 ? _d : [];\n (_e = this.getSource()) === null || _e === void 0 ? void 0 : _e.addFeatures(features);\n }\n this.dispatchEvent('updatefeatures');\n }\n}\n_MapsetLayer_abortController = new WeakMap();\nexport default MapsetLayer;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/layers/MapsetLayer.js", "access": "private", @@ -14237,7 +14237,7 @@ "lineNumber": 1 }, { - "__docId__": 690, + "__docId__": 689, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14258,7 +14258,7 @@ "ignore": true }, { - "__docId__": 691, + "__docId__": 690, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14279,7 +14279,7 @@ "ignore": true }, { - "__docId__": 692, + "__docId__": 691, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14300,7 +14300,7 @@ "ignore": true }, { - "__docId__": 693, + "__docId__": 692, "kind": "variable", "name": "kmlFormatter", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14311,7 +14311,7 @@ "importPath": "mobility-toolbox-js/build/ol/layers/MapsetLayer.js", "importStyle": null, "description": null, - "lineNumber": 28, + "lineNumber": 29, "undocument": true, "type": { "types": [ @@ -14321,7 +14321,7 @@ "ignore": true }, { - "__docId__": 694, + "__docId__": 693, "kind": "class", "name": "MapsetLayer", "memberof": "build/ol/layers/MapsetLayer.js", @@ -14339,14 +14339,14 @@ "MapsetAPI", "OpenLayers Mapset layer example" ], - "lineNumber": 50, + "lineNumber": 51, "interface": false, "extends": [ "ol/layer/VectorLayer~VectorLayer" ] }, { - "__docId__": 695, + "__docId__": 694, "kind": "get", "name": "api", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14356,7 +14356,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#api", "access": "private", "description": null, - "lineNumber": 51, + "lineNumber": 52, "undocument": true, "type": { "types": [ @@ -14365,7 +14365,7 @@ } }, { - "__docId__": 696, + "__docId__": 695, "kind": "set", "name": "api", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14375,11 +14375,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#api", "access": "private", "description": null, - "lineNumber": 54, + "lineNumber": 55, "undocument": true }, { - "__docId__": 697, + "__docId__": 696, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14389,7 +14389,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#apiKey", "access": "private", "description": null, - "lineNumber": 58, + "lineNumber": 59, "undocument": true, "type": { "types": [ @@ -14398,7 +14398,7 @@ } }, { - "__docId__": 698, + "__docId__": 697, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14408,44 +14408,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#apiKey", "access": "private", "description": null, - "lineNumber": 61, - "undocument": true - }, - { - "__docId__": 699, - "kind": "get", - "name": "doNotRevert32pxScaling", - "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", - "generator": false, - "async": false, - "static": false, - "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#doNotRevert32pxScaling", - "access": "private", - "description": null, - "lineNumber": 67, - "undocument": true, - "type": { - "types": [ - "*" - ] - } - }, - { - "__docId__": 700, - "kind": "set", - "name": "doNotRevert32pxScaling", - "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", - "generator": false, - "async": false, - "static": false, - "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#doNotRevert32pxScaling", - "access": "private", - "description": null, - "lineNumber": 70, + "lineNumber": 62, "undocument": true }, { - "__docId__": 701, + "__docId__": 698, "kind": "get", "name": "planId", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14455,7 +14422,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#planId", "access": "private", "description": null, - "lineNumber": 74, + "lineNumber": 68, "undocument": true, "type": { "types": [ @@ -14464,7 +14431,7 @@ } }, { - "__docId__": 702, + "__docId__": 699, "kind": "set", "name": "planId", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14474,11 +14441,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#planId", "access": "private", "description": null, - "lineNumber": 77, + "lineNumber": 71, "undocument": true }, { - "__docId__": 703, + "__docId__": 700, "kind": "get", "name": "plans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14488,7 +14455,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#plans", "access": "private", "description": null, - "lineNumber": 83, + "lineNumber": 77, "undocument": true, "type": { "types": [ @@ -14497,7 +14464,7 @@ } }, { - "__docId__": 704, + "__docId__": 701, "kind": "set", "name": "plans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14507,11 +14474,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#plans", "access": "private", "description": null, - "lineNumber": 86, + "lineNumber": 80, "undocument": true }, { - "__docId__": 705, + "__docId__": 702, "kind": "get", "name": "tags", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14521,7 +14488,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#tags", "access": "private", "description": null, - "lineNumber": 90, + "lineNumber": 84, "undocument": true, "type": { "types": [ @@ -14530,7 +14497,7 @@ } }, { - "__docId__": 706, + "__docId__": 703, "kind": "set", "name": "tags", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14540,11 +14507,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#tags", "access": "private", "description": null, - "lineNumber": 93, + "lineNumber": 87, "undocument": true }, { - "__docId__": 707, + "__docId__": 704, "kind": "get", "name": "tenants", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14554,7 +14521,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#tenants", "access": "private", "description": null, - "lineNumber": 100, + "lineNumber": 94, "undocument": true, "type": { "types": [ @@ -14563,7 +14530,7 @@ } }, { - "__docId__": 708, + "__docId__": 705, "kind": "set", "name": "tenants", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14573,11 +14540,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#tenants", "access": "private", "description": null, - "lineNumber": 103, + "lineNumber": 97, "undocument": true }, { - "__docId__": 709, + "__docId__": 706, "kind": "get", "name": "timestamp", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14587,7 +14554,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#timestamp", "access": "private", "description": null, - "lineNumber": 110, + "lineNumber": 104, "undocument": true, "type": { "types": [ @@ -14596,7 +14563,7 @@ } }, { - "__docId__": 710, + "__docId__": 707, "kind": "set", "name": "timestamp", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14606,11 +14573,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#timestamp", "access": "private", "description": null, - "lineNumber": 113, + "lineNumber": 107, "undocument": true }, { - "__docId__": 711, + "__docId__": 708, "kind": "get", "name": "url", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14620,7 +14587,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#url", "access": "private", "description": null, - "lineNumber": 119, + "lineNumber": 113, "undocument": true, "type": { "types": [ @@ -14629,7 +14596,7 @@ } }, { - "__docId__": 712, + "__docId__": 709, "kind": "set", "name": "url", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14639,11 +14606,11 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#url", "access": "private", "description": null, - "lineNumber": 123, + "lineNumber": 117, "undocument": true }, { - "__docId__": 713, + "__docId__": 710, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14653,7 +14620,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#constructor", "access": "public", "description": "Constructor.", - "lineNumber": 141, + "lineNumber": 135, "params": [ { "nullable": null, @@ -14718,7 +14685,7 @@ ] }, { - "__docId__": 714, + "__docId__": 711, "kind": "member", "name": "loadAll", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14726,7 +14693,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#loadAll", "access": "private", "description": null, - "lineNumber": 144, + "lineNumber": 138, "undocument": true, "type": { "types": [ @@ -14735,7 +14702,7 @@ } }, { - "__docId__": 715, + "__docId__": 712, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14743,7 +14710,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#olEventsKeys", "access": "private", "description": null, - "lineNumber": 145, + "lineNumber": 139, "undocument": true, "type": { "types": [ @@ -14752,7 +14719,7 @@ } }, { - "__docId__": 718, + "__docId__": 715, "kind": "method", "name": "fetchPlanById", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14762,7 +14729,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#fetchPlanById", "access": "private", "description": null, - "lineNumber": 159, + "lineNumber": 154, "undocument": true, "params": [ { @@ -14779,7 +14746,7 @@ } }, { - "__docId__": 722, + "__docId__": 719, "kind": "method", "name": "fetchPlans", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14789,7 +14756,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#fetchPlans", "access": "private", "description": null, - "lineNumber": 192, + "lineNumber": 187, "undocument": true, "params": [], "return": { @@ -14799,7 +14766,7 @@ } }, { - "__docId__": 725, + "__docId__": 722, "kind": "method", "name": "setMapInternal", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14809,7 +14776,7 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#setMapInternal", "access": "private", "description": null, - "lineNumber": 233, + "lineNumber": 227, "undocument": true, "params": [ { @@ -14822,7 +14789,7 @@ "return": null }, { - "__docId__": 726, + "__docId__": 723, "kind": "method", "name": "updateFeatures", "memberof": "build/ol/layers/MapsetLayer.js~MapsetLayer", @@ -14832,13 +14799,13 @@ "longname": "build/ol/layers/MapsetLayer.js~MapsetLayer#updateFeatures", "access": "private", "description": null, - "lineNumber": 250, + "lineNumber": 244, "undocument": true, "params": [], "return": null }, { - "__docId__": 727, + "__docId__": 724, "kind": "file", "name": "build/ol/layers/MocoLayer.js", "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _MocoLayer_abortController, _MocoLayer_dataInternal;\nimport { getFeatureCollectionToRenderFromSituation, getGraphByZoom, MocoAPI, } from '..';\nimport { DEFAULT_GRAPH_MAPPING } from '../utils/getGraphByZoom';\nimport MaplibreStyleLayer from './MaplibreStyleLayer';\nexport const MOCO_SOURCE_ID = 'moco';\nexport const MOCO_MD_LAYER_FILTER = 'moco';\n/**\n * An OpenLayers layer able to display data from the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n *\n * @example\n * import { MaplibreLayer, MaplibreStyleLayer } from 'mobility-toolbox-js/ol';\n *\n * const maplibreLayer = new MaplibreLayer({\n * apiKey: 'yourApiKey',\n * });\n *\n * const layer = new MocoLayer({\n * apiKey: 'yourApiKey',\n * maplibreLayer: maplibreLayer,\n * // publicAt: new Date(),\n * // loadAll: true,\n * // notifications: undefined,\n * // tenant: \"geopstest\",\n * // url: 'https://moco.geops.io'\n * });\n *\n * @see OpenLayers MaplibreStyle layer example\n * @extends {MaplibreStyleLayer}\n * @private\n */\nclass MocoLayer extends MaplibreStyleLayer {\n get api() {\n return this.get('api');\n }\n set api(value) {\n this.set('api', value);\n void this.updateData();\n }\n get apiKey() {\n return this.api.apiKey;\n }\n set apiKey(value) {\n this.api.apiKey = value;\n void this.updateData();\n }\n get apiParameters() {\n return this.get('apiParameters');\n }\n set apiParameters(value) {\n this.set('apiParameters', value);\n void this.updateData();\n }\n get loadAll() {\n var _a;\n return (_a = this.get('loadAll')) !== null && _a !== void 0 ? _a : true;\n }\n set loadAll(value) {\n this.set('loadAll', value);\n void this.updateData();\n }\n set publicAt(value) {\n this.set('publicAt', value);\n void this.updateData();\n }\n get publicAt() {\n return this.get('publicAt');\n }\n set situations(value) {\n // If we set situations we do not want to load data from backend\n this.loadAll = false;\n this.set('situations', value);\n void this.updateData();\n }\n get situations() {\n return this.get('situations');\n }\n get tenant() {\n return this.get('tenant');\n }\n set tenant(value) {\n this.set('tenant', value);\n void this.updateData();\n }\n get url() {\n return this.api.url;\n }\n set url(value) {\n this.api.url = value;\n void this.updateData();\n }\n // The useGraphs option allows to filter notifications depending on the current graph.\n // Theoretically useless because this part is handled by the style itself.\n get useGraphs() {\n return this.get('useGraphs');\n }\n /**\n * Constructor.\n *\n * @param {Object} options\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.apiParameters] The url parameters to be included in the MOCO API request.\n * @param {boolean} [options.loadAll=true] If true, all active and published notifications will be loaded, otherwise only the notifications set in 'notifications' will be displayed.\n * @param {boolean} [options.useGraphs=false] If true, only the notifications using the current graphs for the current zoom level will be passed to the maplibre source.\n * @param {MocoNotification[]} [options.notifications] The notifications to display. If not set and loadAll is true, all active and published notifications will be loaded.\n * @param {string} [options.publicAt] The date to filter notifications. If not set, the current date is used.\n * @param {string} [options.tenant] The SSO config to use to get notifications from.\n * @param {string} [options.url] The URL of the [geOps MOCO API](https://geops.com/de/solution/disruption-information).\n * @public\n */\n constructor(options) {\n super(Object.assign({ api: new MocoAPI({\n apiKey: options.apiKey,\n tenant: options.tenant,\n url: options.url,\n }), layersFilter: ({ metadata, source, }) => {\n return ((metadata === null || metadata === void 0 ? void 0 : metadata['general.filter']) ===\n MOCO_MD_LAYER_FILTER || source === MOCO_SOURCE_ID);\n } }, options));\n _MocoLayer_abortController.set(this, null);\n /**\n * This is used to store the notifications data that are rendered on the map and to filter them depending on the graph.\n */\n _MocoLayer_dataInternal.set(this, {\n features: [],\n type: 'FeatureCollection',\n });\n }\n attachToMap(map) {\n var _a, _b;\n super.attachToMap(map);\n // If the source is already there (no load event triggered), we update data\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n void this.updateData();\n }\n if (this.useGraphs) {\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n this.olEventsKeys.push(mapInternal.on('moveend', () => {\n this.onZoomEnd();\n }));\n }\n }\n }\n detachFromMap() {\n var _a, _b;\n super.detachFromMap();\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (source) {\n // Remove the data from the map\n source.setData({\n features: [],\n type: 'FeatureCollection',\n });\n }\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n __classPrivateFieldSet(this, _MocoLayer_abortController, null, \"f\");\n }\n }\n getDataByGraph(data) {\n var _a, _b, _c, _d, _e;\n const zoom = (_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom();\n const graphs = (_e = ((_d = (_c = this.maplibreLayer) === null || _c === void 0 ? void 0 : _c.mapLibreMap) === null || _d === void 0 ? void 0 : _d.getStyle()).metadata) === null || _e === void 0 ? void 0 : _e.graphs;\n const graph = getGraphByZoom(zoom, graphs);\n const newData = {\n features: ((data === null || data === void 0 ? void 0 : data.features) || []).filter((feature) => {\n var _a;\n return ((_a = feature.properties) === null || _a === void 0 ? void 0 : _a.graph) === graph;\n }),\n type: 'FeatureCollection',\n };\n return newData;\n }\n /**\n * This functions load situations from backend depending on the current graph mapping in the style metadata.\n * @returns\n */\n loadData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d, _e;\n if (__classPrivateFieldGet(this, _MocoLayer_abortController, \"f\")) {\n __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").abort();\n }\n __classPrivateFieldSet(this, _MocoLayer_abortController, new AbortController(), \"f\");\n // Get graphs mapping\n const mdGraphs = (_c = ((_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getStyle()).metadata) === null || _c === void 0 ? void 0 : _c.graphs;\n const graphMapping = mdGraphs !== null && mdGraphs !== void 0 ? mdGraphs : DEFAULT_GRAPH_MAPPING;\n const graphsString = [...new Set(Object.values(graphMapping))].join(',');\n try {\n const response = yield this.api.export(Object.assign({ graph: graphsString, hasGeoms: true, publicAt: (_d = this.publicAt) === null || _d === void 0 ? void 0 : _d.toISOString(), publicNow: !this.publicAt }, ((_e = this.apiParameters) !== null && _e !== void 0 ? _e : {})), { signal: __classPrivateFieldGet(this, _MocoLayer_abortController, \"f\").signal });\n return response.paginatedSituations.results;\n }\n catch (error) {\n if (error && error.name.includes('AbortError')) {\n // Ignore abort error\n return [];\n }\n throw error;\n }\n });\n }\n onLoad() {\n super.onLoad();\n void this.updateData();\n }\n onZoomEnd() {\n var _a, _b;\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source || !__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\").features.length) {\n return;\n }\n // We update the data if the graph has changed\n const newData = this.getDataByGraph(__classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\"));\n if (newData !== __classPrivateFieldGet(this, _MocoLayer_dataInternal, \"f\")) {\n source.setData(newData);\n }\n }\n /**\n * This function updates the GeoJSON source data, with the current situations available in this.situations.\n * @returns\n */\n updateData() {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c;\n if (this.loadAll) {\n const situations = yield this.loadData();\n // We don't use the setter here to avoid infinite loop\n this.set('situations', situations !== null && situations !== void 0 ? situations : []);\n }\n const source = (_b = (_a = this.maplibreLayer) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.getSource(MOCO_SOURCE_ID);\n if (!source) {\n // eslint-disable-next-line no-console\n console.warn('MocoLayer: No source found for id : ', MOCO_SOURCE_ID);\n return Promise.reject(new Error('No source found'));\n }\n const data = {\n features: ((_c = this.situations) !== null && _c !== void 0 ? _c : []).flatMap((situation) => {\n return getFeatureCollectionToRenderFromSituation(situation, this.publicAt).features;\n }),\n type: 'FeatureCollection',\n };\n __classPrivateFieldSet(this, _MocoLayer_dataInternal, data, \"f\");\n // Apply new data to the source\n if (this.useGraphs) {\n source.setData(this.getDataByGraph(data));\n }\n else {\n source.setData(data);\n }\n return Promise.resolve(true);\n });\n }\n}\n_MocoLayer_abortController = new WeakMap(), _MocoLayer_dataInternal = new WeakMap();\nexport default MocoLayer;\n", @@ -14849,7 +14816,7 @@ "lineNumber": 1 }, { - "__docId__": 728, + "__docId__": 725, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/MocoLayer.js", @@ -14870,7 +14837,7 @@ "ignore": true }, { - "__docId__": 729, + "__docId__": 726, "kind": "variable", "name": "__classPrivateFieldGet", "memberof": "build/ol/layers/MocoLayer.js", @@ -14891,7 +14858,7 @@ "ignore": true }, { - "__docId__": 730, + "__docId__": 727, "kind": "variable", "name": "__classPrivateFieldSet", "memberof": "build/ol/layers/MocoLayer.js", @@ -14912,7 +14879,7 @@ "ignore": true }, { - "__docId__": 731, + "__docId__": 728, "kind": "variable", "name": "MOCO_SOURCE_ID", "memberof": "build/ol/layers/MocoLayer.js", @@ -14932,7 +14899,7 @@ } }, { - "__docId__": 732, + "__docId__": 729, "kind": "variable", "name": "MOCO_MD_LAYER_FILTER", "memberof": "build/ol/layers/MocoLayer.js", @@ -14952,7 +14919,7 @@ } }, { - "__docId__": 733, + "__docId__": 730, "kind": "class", "name": "MocoLayer", "memberof": "build/ol/layers/MocoLayer.js", @@ -14976,7 +14943,7 @@ ] }, { - "__docId__": 734, + "__docId__": 731, "kind": "get", "name": "api", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -14995,7 +14962,7 @@ } }, { - "__docId__": 735, + "__docId__": 732, "kind": "set", "name": "api", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15009,7 +14976,7 @@ "undocument": true }, { - "__docId__": 736, + "__docId__": 733, "kind": "get", "name": "apiKey", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15028,7 +14995,7 @@ } }, { - "__docId__": 737, + "__docId__": 734, "kind": "set", "name": "apiKey", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15042,7 +15009,7 @@ "undocument": true }, { - "__docId__": 738, + "__docId__": 735, "kind": "get", "name": "apiParameters", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15061,7 +15028,7 @@ } }, { - "__docId__": 739, + "__docId__": 736, "kind": "set", "name": "apiParameters", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15075,7 +15042,7 @@ "undocument": true }, { - "__docId__": 740, + "__docId__": 737, "kind": "get", "name": "loadAll", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15094,7 +15061,7 @@ } }, { - "__docId__": 741, + "__docId__": 738, "kind": "set", "name": "loadAll", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15108,7 +15075,7 @@ "undocument": true }, { - "__docId__": 742, + "__docId__": 739, "kind": "set", "name": "publicAt", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15122,7 +15089,7 @@ "undocument": true }, { - "__docId__": 743, + "__docId__": 740, "kind": "get", "name": "publicAt", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15141,7 +15108,7 @@ } }, { - "__docId__": 744, + "__docId__": 741, "kind": "set", "name": "situations", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15155,7 +15122,7 @@ "undocument": true }, { - "__docId__": 746, + "__docId__": 743, "kind": "get", "name": "situations", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15174,7 +15141,7 @@ } }, { - "__docId__": 747, + "__docId__": 744, "kind": "get", "name": "tenant", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15193,7 +15160,7 @@ } }, { - "__docId__": 748, + "__docId__": 745, "kind": "set", "name": "tenant", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15207,7 +15174,7 @@ "undocument": true }, { - "__docId__": 749, + "__docId__": 746, "kind": "get", "name": "url", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15226,7 +15193,7 @@ } }, { - "__docId__": 750, + "__docId__": 747, "kind": "set", "name": "url", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15240,7 +15207,7 @@ "undocument": true }, { - "__docId__": 751, + "__docId__": 748, "kind": "get", "name": "useGraphs", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15259,7 +15226,7 @@ } }, { - "__docId__": 752, + "__docId__": 749, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15368,7 +15335,7 @@ ] }, { - "__docId__": 753, + "__docId__": 750, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15391,7 +15358,7 @@ "return": null }, { - "__docId__": 754, + "__docId__": 751, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15407,7 +15374,7 @@ "return": null }, { - "__docId__": 755, + "__docId__": 752, "kind": "method", "name": "getDataByGraph", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15434,7 +15401,7 @@ } }, { - "__docId__": 756, + "__docId__": 753, "kind": "method", "name": "loadData", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15459,7 +15426,7 @@ } }, { - "__docId__": 757, + "__docId__": 754, "kind": "method", "name": "onLoad", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15475,7 +15442,7 @@ "return": null }, { - "__docId__": 758, + "__docId__": 755, "kind": "method", "name": "onZoomEnd", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15491,7 +15458,7 @@ "return": null }, { - "__docId__": 759, + "__docId__": 756, "kind": "method", "name": "updateData", "memberof": "build/ol/layers/MocoLayer.js~MocoLayer", @@ -15516,10 +15483,10 @@ } }, { - "__docId__": 760, + "__docId__": 757, "kind": "file", "name": "build/ol/layers/RealtimeLayer.js", - "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport debounce from 'lodash.debounce';\nimport { getIntersection, isEmpty } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport Layer from 'ol/layer/Layer';\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { Vector as VectorSource } from 'ol/source';\nimport Source from 'ol/source/Source';\nimport { realtimeDefaultStyle } from '../../common/styles';\nimport RealtimeEngine from '../../common/utils/RealtimeEngine';\nimport RealtimeLayerRenderer from '../renderers/RealtimeLayerRenderer';\nimport { fullTrajectoryStyle } from '../styles';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nimport { deprecated } from './MaplibreLayer';\nconst format = new GeoJSON();\n/**\n * An OpenLayers layer able to display data from the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { RealtimeLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new RealtimeLayer({\n * apiKey: \"yourApiKey\"\n * // allowRenderWhenAnimating: false,\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n *\n * @see RealtimeAPI\n * @see OpenLayers Realtime layer example\n *\n *\n * @extends {ol/layer/Layer~Layer}\n *\n *\n * @classproperty {boolean} allowRenderWhenAnimating - Allow rendering of the layer when the map is animating.\n * @public\n */\nclass RealtimeLayer extends Layer {\n get api() {\n return this.engine.api;\n }\n set api(api) {\n this.engine.api = api;\n }\n get canvas() {\n return this.engine.canvas;\n }\n get filter() {\n return this.engine.filter;\n }\n set filter(filter) {\n this.engine.filter = filter;\n }\n get hoverVehicleId() {\n return this.engine.hoverVehicleId;\n }\n set hoverVehicleId(id) {\n this.engine.hoverVehicleId = id;\n }\n get mode() {\n return this.engine.mode;\n }\n set mode(mode) {\n this.engine.mode = mode;\n }\n get pixelRatio() {\n return this.engine.pixelRatio;\n }\n get selectedVehicleId() {\n return this.engine.selectedVehicleId;\n }\n set selectedVehicleId(id) {\n this.engine.selectedVehicleId = id;\n }\n get sort() {\n return this.engine.sort;\n }\n set sort(sort) {\n this.engine.sort = sort;\n }\n get style() {\n var _a;\n return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.style;\n }\n set style(style) {\n if (this.engine) {\n this.engine.style = style;\n }\n }\n get styleOptions() {\n return this.engine.styleOptions;\n }\n set styleOptions(options) {\n this.engine.styleOptions = options;\n }\n get time() {\n return this.engine.time || new Date();\n }\n set time(time) {\n this.engine.time = time;\n }\n get trajectories() {\n return this.engine.trajectories;\n }\n /**\n * Constructor.\n *\n * @param {RealtimeLayerOptions} options\n * @param {boolean} [options.allowRenderWhenAnimating=false] Allow rendering of the layer when the map is animating.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.url=\"wss://api.geops.io/tracker-ws/v1/\"] The [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.\n * @public\n */\n constructor(options) {\n // We use a group to be able to add custom vector layer in extended class.\n // For example TrajservLayer use a vectorLayer to display the complete trajectory.\n super(Object.assign({ minZoom: 4, source: new Source({}) }, options));\n this.allowRenderWhenAnimating = false;\n this.maxNbFeaturesRequested = 100;\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n this.engine = new RealtimeEngine(Object.assign({ getViewState: this.getViewState.bind(this), onIdle: this.onRealtimeEngineIdle.bind(this), onRender: this.onRealtimeEngineRender.bind(this), style: realtimeDefaultStyle }, options));\n this.allowRenderWhenAnimating = !!options.allowRenderWhenAnimating;\n // We store the layer used to highlight the full Trajectory\n this.vectorLayer = new VectorLayer({\n minZoom: this.getMinZoom(),\n source: new VectorSource({ features: [] }),\n style: (feature, resolution) => {\n return (options.fullTrajectoryStyle || fullTrajectoryStyle)(feature, resolution, this);\n },\n updateWhileAnimating: this.allowRenderWhenAnimating,\n updateWhileInteracting: true,\n });\n this.onZoomEndDebounced = debounce(this.onZoomEnd, 100);\n this.onMoveEndDebounced = debounce(this.onMoveEnd, 100);\n }\n /**\n * Add a trajectory.\n * @param trajectory\n */\n addTrajectory(trajectory) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.addTrajectory(trajectory);\n }\n attachToMap() {\n this.engine.attachToMap();\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n // If the layer is visible we start the rendering clock\n if (this.getVisible()) {\n this.engine.start();\n }\n this.olEventsKeys.push(mapInternal.on('movestart', () => {\n if (this.engine.isUpdateBboxOnMoveEnd) {\n this.engine.updateIdleState();\n }\n }), ...mapInternal.on(['moveend', 'change:target'], \n // @ts-expect-error - bad ol definitions\n (evt) => {\n const view = (evt.map || evt.target).getView();\n if (!view || (view === null || view === void 0 ? void 0 : view.getAnimating()) || (view === null || view === void 0 ? void 0 : view.getInteracting())) {\n return;\n }\n const zoom = view.getZoom();\n // Update the interval between render updates\n if (this.currentZoom !== zoom) {\n this.onZoomEndDebounced(evt);\n }\n this.currentZoom = zoom;\n this.onMoveEndDebounced(evt);\n }), this.on('change:visible', (evt) => {\n if (evt.target.getVisible()) {\n this.engine.start();\n }\n else {\n this.engine.stop();\n }\n }), this.on('propertychange', (evt) => {\n // We apply every property change event related to visiblity to the vectorlayer\n if (/(opacity|visible|zIndex|minResolution|maxResolution|minZoom|maxZoom)/.test(evt.key)) {\n this.vectorLayer.set(evt.key, evt.target.get(evt.key));\n }\n }));\n }\n }\n cleanVectorLayer() {\n var _a, _b, _c;\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear(true);\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n /**\n * Create a copy of the RealtimeLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {RealtimeLayer} A RealtimeLayer\n * @public\n */\n clone(newOptions) {\n return new RealtimeLayer(Object.assign(Object.assign({}, this.get('options')), newOptions));\n }\n createRenderer() {\n return new RealtimeLayerRenderer(this);\n }\n /**\n * Destroy the container of the tracker.\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.removeLayer(this.vectorLayer);\n this.engine.detachFromMap();\n }\n /**\n * Get the full trajectory of a vehicle as features.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} A list of features representing a full trajectory.\n * @public\n */\n getFullTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n const data = yield this.engine.api.getFullTrajectory(id, this.engine.mode, this.engine.getGeneralizationLevelByZoom(Math.floor(((_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom()) || 0)));\n if ((_d = (_c = data === null || data === void 0 ? void 0 : data.content) === null || _c === void 0 ? void 0 : _c.features) === null || _d === void 0 ? void 0 : _d.length) {\n return format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n return [];\n });\n }\n /**\n * Get the stop sequences of a vehicle.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} An array of stop sequences.\n * @public\n */\n getStopSequences(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const data = yield this.engine.api.getStopSequence(id);\n return data === null || data === void 0 ? void 0 : data.content;\n });\n }\n /**\n * Get full trajectory and stop sequences of a vehicle.\n *\n * @param {RealtimeTrainId} id A vehicle's id.\n * @returns {Promise<{fullTrajectory: Feature[], stopSequences: RealtimeStopSequence[]}>} An object containing the full trajectory and the stop sequences.\n */\n getTrajectoryInfos(id) {\n return __awaiter(this, void 0, void 0, function* () {\n // When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.\n // Then we combine them in one response.\n const promises = [this.getStopSequences(id), this.getFullTrajectory(id)];\n const [stopSequences, fullTrajectory] = yield Promise.all(promises);\n return {\n fullTrajectory: fullTrajectory,\n stopSequences: stopSequences,\n };\n });\n }\n getVehicles(filterFunc) {\n return this.engine.getVehicles(filterFunc);\n }\n getViewState() {\n const mapInternal = this.getMapInternal();\n if (!(mapInternal === null || mapInternal === void 0 ? void 0 : mapInternal.getView())) {\n return {};\n }\n const view = mapInternal.getView();\n let extent = view.calculateExtent();\n const layerExtent = this.getExtent();\n if (layerExtent) {\n extent = getIntersection(extent, layerExtent);\n // If there is no intersection we use the layer extent\n if (isEmpty(extent)) {\n extent = layerExtent;\n }\n }\n return {\n center: view.getCenter(),\n extent: extent,\n pixelRatio: this.engine.pixelRatio,\n resolution: view.getResolution(),\n rotation: view.getRotation(),\n size: mapInternal.getSize(),\n visible: this.getVisible(),\n zoom: view.getZoom(),\n };\n }\n highlight(features) {\n const feat = Array.isArray(features) ? features[0] : features;\n const id = feat === null || feat === void 0 ? void 0 : feat.get('train_id');\n if (this.hoverVehicleId !== id) {\n this.hoverVehicleId = id;\n this.engine.renderTrajectories(true);\n }\n }\n /**\n * Highlight the trajectory of journey.\n */\n highlightTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const promise = new Promise((resolve) => {\n this.api.subscribeFullTrajectory(id, this.engine.mode, (data) => {\n var _a, _b;\n if (this.selectedVehicleId === id && (data === null || data === void 0 ? void 0 : data.content)) {\n let features = [];\n if ((_b = (_a = data === null || data === void 0 ? void 0 : data.content) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.length) {\n features = format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n this.updateHighlightFeatures(features);\n resolve(features);\n }\n });\n });\n return promise;\n // const features = await this.getFullTrajectory(id);\n // this.updateHighlightFeatures(features);\n // return features;\n });\n }\n onMoveEnd() {\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n this.engine.setBbox();\n }\n onRealtimeEngineIdle() {\n this.changed();\n }\n /**\n * Callback when the RealtimeEngine has rendered successfully.\n */\n onRealtimeEngineRender(renderState, viewState) {\n this.renderedViewState = Object.assign({}, viewState);\n // @ts-expect-error - we are in the same class\n const { container } = this.getRenderer();\n if (container) {\n container.style.transform = '';\n }\n }\n onZoomEnd() {\n this.engine.onZoomEnd();\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n }\n /**\n * Remove a trajectory.\n *\n * @param trajectoryOrId\n */\n removeTrajectory(trajectoryOrId) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.removeTrajectory(trajectoryOrId);\n }\n /**\n * Render the trajectories of the vehicles.\n * @deprecated Use this.engine.renderTrajectories instead.\n */\n renderTrajectories(noInterpolate) {\n deprecated('RealtimeLayer.renderTrajectories is deprecated. Use RealtimeLayer.engine.renderTrajectories instead.');\n this.engine.renderTrajectories(noInterpolate);\n }\n select(features) {\n const feat = Array.isArray(features) ? features[0] : features;\n const id = feat === null || feat === void 0 ? void 0 : feat.get('train_id');\n if (this.selectedVehicleId !== id) {\n if (this.selectedVehicleId) {\n this.api.unsubscribeFullTrajectory(this.selectedVehicleId);\n }\n this.cleanVectorLayer();\n this.selectedVehicleId = id;\n this.engine.renderTrajectories(true);\n }\n if (id) {\n void this.highlightTrajectory(id);\n }\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n shouldRender() {\n var _a, _b;\n return this.allowRenderWhenAnimating\n ? false\n : ((_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView().getAnimating()) ||\n ((_b = this.getMapInternal()) === null || _b === void 0 ? void 0 : _b.getView().getInteracting());\n }\n /**\n * Start the rendering.\n *\n * @public\n */\n start() {\n this.engine.start();\n }\n /**\n * Stop the rendering.\n *\n * @public\n */\n stop() {\n this.engine.stop();\n }\n updateHighlightFeatures(features) {\n var _a, _b, _c, _d, _e, _f;\n this.cleanVectorLayer();\n if (features === null || features === void 0 ? void 0 : features.length) {\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeatures(features);\n }\n if (this.vectorLayer.getMapInternal() &&\n this.vectorLayer.getMapInternal() !== this.getMapInternal()) {\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n // Add the vector layer to the map\n const zIndex = this.getZIndex();\n if (zIndex !== undefined) {\n this.vectorLayer.setZIndex(zIndex - 1);\n if (!this.vectorLayer.getMapInternal()) {\n (_d = this.getMapInternal()) === null || _d === void 0 ? void 0 : _d.addLayer(this.vectorLayer);\n }\n }\n else if (!this.vectorLayer.getMapInternal()) {\n const index = ((_e = this.getMapInternal()) === null || _e === void 0 ? void 0 : _e.getLayers().getArray().indexOf(this)) || 0;\n if (index) {\n (_f = this.getMapInternal()) === null || _f === void 0 ? void 0 : _f.getLayers().insertAt(index, this.vectorLayer);\n }\n }\n return features;\n }\n}\nexport default RealtimeLayer;\n", + "content": "var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport debounce from 'lodash.debounce';\nimport { getIntersection, isEmpty } from 'ol/extent';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport Layer from 'ol/layer/Layer';\nimport VectorLayer from 'ol/layer/Vector';\nimport { unByKey } from 'ol/Observable';\nimport { Vector as VectorSource } from 'ol/source';\nimport Source from 'ol/source/Source';\nimport { realtimeDefaultStyle } from '../../common/styles';\nimport RealtimeEngine from '../../common/utils/RealtimeEngine';\nimport RealtimeLayerRenderer from '../renderers/RealtimeLayerRenderer';\nimport { fullTrajectoryStyle } from '../styles';\nimport defineDeprecatedProperties from '../utils/defineDeprecatedProperties';\nimport { deprecated } from './MaplibreLayer';\nconst format = new GeoJSON();\n/**\n * An OpenLayers layer able to display data from the [geOps Realtime API](https://developer.geops.io/apis/realtime/).\n *\n * @example\n * import { RealtimeLayer } from 'mobility-toolbox-js/ol';\n *\n * const layer = new RealtimeLayer({\n * apiKey: \"yourApiKey\"\n * // allowRenderWhenAnimating: false,\n * // url: \"wss://api.geops.io/tracker-ws/v1/\",\n * });\n *\n *\n * @see RealtimeAPI\n * @see OpenLayers Realtime layer example\n *\n *\n * @extends {ol/layer/Layer~Layer}\n *\n *\n * @classproperty {boolean} allowRenderWhenAnimating - Allow rendering of the layer when the map is animating.\n * @public\n */\nclass RealtimeLayer extends Layer {\n get api() {\n return this.engine.api;\n }\n set api(api) {\n this.engine.api = api;\n }\n get canvas() {\n return this.engine.canvas;\n }\n get filter() {\n return this.engine.filter;\n }\n set filter(filter) {\n this.engine.filter = filter;\n }\n get hoverVehicleId() {\n return this.engine.hoverVehicleId;\n }\n set hoverVehicleId(id) {\n this.engine.hoverVehicleId = id;\n }\n get hoverVehicleIds() {\n return this.engine.hoverVehicleIds;\n }\n set hoverVehicleIds(ids) {\n this.engine.hoverVehicleIds = ids;\n }\n get mode() {\n return this.engine.mode;\n }\n set mode(mode) {\n this.engine.mode = mode;\n }\n get pixelRatio() {\n return this.engine.pixelRatio;\n }\n get selectedVehicleId() {\n return this.engine.selectedVehicleId;\n }\n set selectedVehicleId(id) {\n this.engine.selectedVehicleId = id;\n }\n get sort() {\n return this.engine.sort;\n }\n set sort(sort) {\n this.engine.sort = sort;\n }\n get style() {\n var _a;\n return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.style;\n }\n set style(style) {\n if (this.engine) {\n this.engine.style = style;\n }\n }\n get styleOptions() {\n return this.engine.styleOptions;\n }\n set styleOptions(options) {\n this.engine.styleOptions = options;\n }\n get time() {\n return this.engine.time || new Date();\n }\n set time(time) {\n this.engine.time = time;\n }\n get trajectories() {\n return this.engine.trajectories;\n }\n /**\n * Constructor.\n *\n * @param {RealtimeLayerOptions} options\n * @param {boolean} [options.allowRenderWhenAnimating=false] Allow rendering of the layer when the map is animating.\n * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).\n * @param {string} [options.url=\"wss://api.geops.io/tracker-ws/v1/\"] The [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.\n * @public\n */\n constructor(options) {\n // We use a group to be able to add custom vector layer in extended class.\n // For example TrajservLayer use a vectorLayer to display the complete trajectory.\n super(Object.assign({ minZoom: 4, source: new Source({}) }, options));\n this.allowRenderWhenAnimating = false;\n this.maxNbFeaturesRequested = 100;\n this.olEventsKeys = [];\n // For backward compatibility with v2\n defineDeprecatedProperties(this, options);\n this.engine = new RealtimeEngine(Object.assign({ getViewState: this.getViewState.bind(this), onIdle: this.onRealtimeEngineIdle.bind(this), onRender: this.onRealtimeEngineRender.bind(this), style: realtimeDefaultStyle }, options));\n this.allowRenderWhenAnimating = !!options.allowRenderWhenAnimating;\n // We store the layer used to highlight the full Trajectory\n this.vectorLayer = new VectorLayer({\n minZoom: this.getMinZoom(),\n source: new VectorSource({ features: [] }),\n style: (feature, resolution) => {\n return (options.fullTrajectoryStyle || fullTrajectoryStyle)(feature, resolution, this);\n },\n updateWhileAnimating: this.allowRenderWhenAnimating,\n updateWhileInteracting: true,\n });\n this.onZoomEndDebounced = debounce(this.onZoomEnd.bind(this), 100);\n this.onMoveEndDebounced = debounce(this.onMoveEnd.bind(this), 100);\n }\n /**\n * Add a trajectory.\n * @param trajectory\n */\n addTrajectory(trajectory) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.addTrajectory(trajectory);\n }\n attachToMap() {\n this.engine.attachToMap();\n const mapInternal = this.getMapInternal();\n if (mapInternal) {\n // If the layer is visible we start the rendering clock\n if (this.getVisible()) {\n this.engine.start();\n }\n this.olEventsKeys.push(mapInternal.on('movestart', () => {\n if (this.engine.isUpdateBboxOnMoveEnd) {\n this.engine.updateIdleState();\n }\n }), ...mapInternal.on(['moveend', 'change:target'], \n // @ts-expect-error - bad ol definitions\n (evt) => {\n const view = (evt.map || evt.target).getView();\n if (!view || (view === null || view === void 0 ? void 0 : view.getAnimating()) || (view === null || view === void 0 ? void 0 : view.getInteracting())) {\n return;\n }\n const zoom = view.getZoom();\n // Update the interval between render updates\n if (this.currentZoom !== zoom) {\n this.onZoomEndDebounced(evt);\n }\n this.currentZoom = zoom;\n this.onMoveEndDebounced(evt);\n }), this.on('change:visible', (evt) => {\n if (evt.target.getVisible()) {\n this.engine.start();\n }\n else {\n this.engine.stop();\n }\n }), this.on('propertychange', (evt) => {\n // We apply every property change event related to visiblity to the vectorlayer\n if (/(opacity|visible|zIndex|minResolution|maxResolution|minZoom|maxZoom)/.test(evt.key)) {\n this.vectorLayer.set(evt.key, evt.target.get(evt.key));\n }\n }));\n }\n }\n cleanVectorLayer() {\n var _a, _b, _c;\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear(true);\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n /**\n * Create a copy of the RealtimeLayer.\n *\n * @param {Object} newOptions Options to override. See constructor.\n * @return {RealtimeLayer} A RealtimeLayer\n * @public\n */\n clone(newOptions) {\n return new RealtimeLayer(Object.assign(Object.assign({}, this.get('options')), newOptions));\n }\n createRenderer() {\n return new RealtimeLayerRenderer(this);\n }\n /**\n * Destroy the container of the tracker.\n */\n detachFromMap() {\n var _a;\n unByKey(this.olEventsKeys);\n (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.removeLayer(this.vectorLayer);\n this.engine.detachFromMap();\n }\n /**\n * Get the full trajectory of a vehicle as features.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} A list of features representing a full trajectory.\n * @public\n */\n getFullTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n const data = yield this.engine.api.getFullTrajectory(id, this.engine.mode, this.engine.getGeneralizationLevelByZoom(Math.floor(((_b = (_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView()) === null || _b === void 0 ? void 0 : _b.getZoom()) || 0)));\n if ((_d = (_c = data === null || data === void 0 ? void 0 : data.content) === null || _c === void 0 ? void 0 : _c.features) === null || _d === void 0 ? void 0 : _d.length) {\n return format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n return [];\n });\n }\n /**\n * Get the stop sequences of a vehicle.\n *\n * @param {string} id A vehicle's id.\n * @returns {Promise} An array of stop sequences.\n * @public\n */\n getStopSequences(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const data = yield this.engine.api.getStopSequence(id);\n return data === null || data === void 0 ? void 0 : data.content;\n });\n }\n /**\n * Get full trajectory and stop sequences of a vehicle.\n *\n * @param {RealtimeTrainId} id A vehicle's id.\n * @returns {Promise<{fullTrajectory: Feature[], stopSequences: RealtimeStopSequence[]}>} An object containing the full trajectory and the stop sequences.\n */\n getTrajectoryInfos(id) {\n return __awaiter(this, void 0, void 0, function* () {\n // When a vehicle is selected, we request the complete stop sequence and the complete full trajectory.\n // Then we combine them in one response.\n const promises = [this.getStopSequences(id), this.getFullTrajectory(id)];\n const [stopSequences, fullTrajectory] = yield Promise.all(promises);\n return {\n fullTrajectory: fullTrajectory,\n stopSequences: stopSequences,\n };\n });\n }\n getVehicles(filterFunc) {\n return this.engine.getVehicles(filterFunc);\n }\n getViewState() {\n const mapInternal = this.getMapInternal();\n if (!(mapInternal === null || mapInternal === void 0 ? void 0 : mapInternal.getView())) {\n return {};\n }\n const view = mapInternal.getView();\n let extent = view.calculateExtent();\n const layerExtent = this.getExtent();\n if (layerExtent) {\n extent = getIntersection(extent, layerExtent);\n // If there is no intersection we use the layer extent\n if (isEmpty(extent)) {\n extent = layerExtent;\n }\n }\n return {\n center: view.getCenter(),\n extent: extent,\n pixelRatio: this.engine.pixelRatio,\n resolution: view.getResolution(),\n rotation: view.getRotation(),\n size: mapInternal.getSize(),\n visible: this.getVisible(),\n zoom: view.getZoom(),\n };\n }\n highlight(features) {\n var _a;\n const feats = Array.isArray(features) ? features : [features];\n const ids = feats.map((f) => {\n return f.get('train_id');\n });\n if (((_a = this.hoverVehicleIds) === null || _a === void 0 ? void 0 : _a.join()) !== ids.join()) {\n this.hoverVehicleId = ids[0];\n this.hoverVehicleIds = ids;\n this.engine.renderTrajectories(true);\n }\n }\n /**\n * Highlight the trajectory of journey.\n */\n highlightTrajectory(id) {\n return __awaiter(this, void 0, void 0, function* () {\n const promise = new Promise((resolve) => {\n this.api.subscribeFullTrajectory(id, this.engine.mode, (data) => {\n var _a, _b;\n if (this.selectedVehicleId === id && (data === null || data === void 0 ? void 0 : data.content)) {\n let features = [];\n if ((_b = (_a = data === null || data === void 0 ? void 0 : data.content) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b.length) {\n features = format.readFeatures(data === null || data === void 0 ? void 0 : data.content);\n }\n this.updateHighlightFeatures(features);\n resolve(features);\n }\n });\n });\n return promise;\n // const features = await this.getFullTrajectory(id);\n // this.updateHighlightFeatures(features);\n // return features;\n });\n }\n onMoveEnd() {\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n this.engine.setBbox();\n }\n onRealtimeEngineIdle() {\n this.changed();\n }\n /**\n * Callback when the RealtimeEngine has rendered successfully.\n */\n onRealtimeEngineRender(renderState, viewState) {\n this.renderedViewState = Object.assign({}, viewState);\n // @ts-expect-error - we are in the same classs\n const { container } = this.getRenderer();\n if (container) {\n container.style.transform = '';\n }\n }\n onZoomEnd() {\n this.engine.onZoomEnd();\n if (!this.engine.isUpdateBboxOnMoveEnd || !this.getVisible()) {\n return;\n }\n }\n /**\n * Remove a trajectory.\n *\n * @param trajectoryOrId\n */\n removeTrajectory(trajectoryOrId) {\n var _a;\n (_a = this.engine) === null || _a === void 0 ? void 0 : _a.removeTrajectory(trajectoryOrId);\n }\n /**\n * Render the trajectories of the vehicles.\n * @deprecated Use this.engine.renderTrajectories instead.\n */\n renderTrajectories(noInterpolate) {\n deprecated('RealtimeLayer.renderTrajectories is deprecated. Use RealtimeLayer.engine.renderTrajectories instead.');\n this.engine.renderTrajectories(noInterpolate);\n }\n select(features) {\n const feat = Array.isArray(features) ? features[0] : features;\n const id = feat === null || feat === void 0 ? void 0 : feat.get('train_id');\n if (this.selectedVehicleId !== id) {\n if (this.selectedVehicleId) {\n this.api.unsubscribeFullTrajectory(this.selectedVehicleId);\n }\n this.cleanVectorLayer();\n this.selectedVehicleId = id;\n this.engine.renderTrajectories(true);\n }\n if (id) {\n void this.highlightTrajectory(id);\n }\n }\n setMapInternal(map) {\n if (map) {\n super.setMapInternal(map);\n this.attachToMap();\n }\n else {\n this.detachFromMap();\n super.setMapInternal(map);\n }\n }\n shouldRender() {\n var _a, _b;\n return this.allowRenderWhenAnimating\n ? false\n : ((_a = this.getMapInternal()) === null || _a === void 0 ? void 0 : _a.getView().getAnimating()) ||\n ((_b = this.getMapInternal()) === null || _b === void 0 ? void 0 : _b.getView().getInteracting());\n }\n /**\n * Start the rendering.\n *\n * @public\n */\n start() {\n this.engine.start();\n }\n /**\n * Stop the rendering.\n *\n * @public\n */\n stop() {\n this.engine.stop();\n }\n updateHighlightFeatures(features) {\n var _a, _b, _c, _d, _e, _f;\n this.cleanVectorLayer();\n if (features === null || features === void 0 ? void 0 : features.length) {\n (_b = (_a = this.vectorLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeatures(features);\n }\n if (this.vectorLayer.getMapInternal() &&\n this.vectorLayer.getMapInternal() !== this.getMapInternal()) {\n (_c = this.vectorLayer.getMapInternal()) === null || _c === void 0 ? void 0 : _c.removeLayer(this.vectorLayer);\n }\n // Add the vector layer to the map\n const zIndex = this.getZIndex();\n if (zIndex !== undefined) {\n this.vectorLayer.setZIndex(zIndex - 1);\n if (!this.vectorLayer.getMapInternal()) {\n (_d = this.getMapInternal()) === null || _d === void 0 ? void 0 : _d.addLayer(this.vectorLayer);\n }\n }\n else if (!this.vectorLayer.getMapInternal()) {\n const index = ((_e = this.getMapInternal()) === null || _e === void 0 ? void 0 : _e.getLayers().getArray().indexOf(this)) || 0;\n if (index) {\n (_f = this.getMapInternal()) === null || _f === void 0 ? void 0 : _f.getLayers().insertAt(index, this.vectorLayer);\n }\n }\n return features;\n }\n}\nexport default RealtimeLayer;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/layers/RealtimeLayer.js", "access": "private", @@ -15527,7 +15494,7 @@ "lineNumber": 1 }, { - "__docId__": 761, + "__docId__": 758, "kind": "variable", "name": "__awaiter", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15548,7 +15515,7 @@ "ignore": true }, { - "__docId__": 762, + "__docId__": 759, "kind": "variable", "name": "format", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15569,7 +15536,7 @@ "ignore": true }, { - "__docId__": 763, + "__docId__": 760, "kind": "class", "name": "RealtimeLayer", "memberof": "build/ol/layers/RealtimeLayer.js", @@ -15600,7 +15567,7 @@ ] }, { - "__docId__": 764, + "__docId__": 761, "kind": "get", "name": "api", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15619,7 +15586,7 @@ } }, { - "__docId__": 765, + "__docId__": 762, "kind": "set", "name": "api", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15633,7 +15600,7 @@ "undocument": true }, { - "__docId__": 766, + "__docId__": 763, "kind": "get", "name": "canvas", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15652,7 +15619,7 @@ } }, { - "__docId__": 767, + "__docId__": 764, "kind": "get", "name": "filter", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15671,7 +15638,7 @@ } }, { - "__docId__": 768, + "__docId__": 765, "kind": "set", "name": "filter", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15685,7 +15652,7 @@ "undocument": true }, { - "__docId__": 769, + "__docId__": 766, "kind": "get", "name": "hoverVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15704,7 +15671,7 @@ } }, { - "__docId__": 770, + "__docId__": 767, "kind": "set", "name": "hoverVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15718,7 +15685,40 @@ "undocument": true }, { - "__docId__": 771, + "__docId__": 768, + "kind": "get", + "name": "hoverVehicleIds", + "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", + "generator": false, + "async": false, + "static": false, + "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#hoverVehicleIds", + "access": "private", + "description": null, + "lineNumber": 70, + "undocument": true, + "type": { + "types": [ + "*" + ] + } + }, + { + "__docId__": 769, + "kind": "set", + "name": "hoverVehicleIds", + "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", + "generator": false, + "async": false, + "static": false, + "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#hoverVehicleIds", + "access": "private", + "description": null, + "lineNumber": 73, + "undocument": true + }, + { + "__docId__": 770, "kind": "get", "name": "mode", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15728,7 +15728,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#mode", "access": "private", "description": null, - "lineNumber": 70, + "lineNumber": 76, "undocument": true, "type": { "types": [ @@ -15737,7 +15737,7 @@ } }, { - "__docId__": 772, + "__docId__": 771, "kind": "set", "name": "mode", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15747,11 +15747,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#mode", "access": "private", "description": null, - "lineNumber": 73, + "lineNumber": 79, "undocument": true }, { - "__docId__": 773, + "__docId__": 772, "kind": "get", "name": "pixelRatio", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15761,7 +15761,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#pixelRatio", "access": "private", "description": null, - "lineNumber": 76, + "lineNumber": 82, "undocument": true, "type": { "types": [ @@ -15770,7 +15770,7 @@ } }, { - "__docId__": 774, + "__docId__": 773, "kind": "get", "name": "selectedVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15780,7 +15780,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#selectedVehicleId", "access": "private", "description": null, - "lineNumber": 79, + "lineNumber": 85, "undocument": true, "type": { "types": [ @@ -15789,7 +15789,7 @@ } }, { - "__docId__": 775, + "__docId__": 774, "kind": "set", "name": "selectedVehicleId", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15799,11 +15799,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#selectedVehicleId", "access": "private", "description": null, - "lineNumber": 82, + "lineNumber": 88, "undocument": true }, { - "__docId__": 776, + "__docId__": 775, "kind": "get", "name": "sort", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15813,7 +15813,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#sort", "access": "private", "description": null, - "lineNumber": 85, + "lineNumber": 91, "undocument": true, "type": { "types": [ @@ -15822,7 +15822,7 @@ } }, { - "__docId__": 777, + "__docId__": 776, "kind": "set", "name": "sort", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15832,11 +15832,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#sort", "access": "private", "description": null, - "lineNumber": 88, + "lineNumber": 94, "undocument": true }, { - "__docId__": 778, + "__docId__": 777, "kind": "get", "name": "style", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15846,7 +15846,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#style", "access": "private", "description": null, - "lineNumber": 91, + "lineNumber": 97, "undocument": true, "type": { "types": [ @@ -15855,7 +15855,7 @@ } }, { - "__docId__": 779, + "__docId__": 778, "kind": "set", "name": "style", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15865,11 +15865,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#style", "access": "private", "description": null, - "lineNumber": 95, + "lineNumber": 101, "undocument": true }, { - "__docId__": 780, + "__docId__": 779, "kind": "get", "name": "styleOptions", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15879,7 +15879,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#styleOptions", "access": "private", "description": null, - "lineNumber": 100, + "lineNumber": 106, "undocument": true, "type": { "types": [ @@ -15888,7 +15888,7 @@ } }, { - "__docId__": 781, + "__docId__": 780, "kind": "set", "name": "styleOptions", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15898,11 +15898,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#styleOptions", "access": "private", "description": null, - "lineNumber": 103, + "lineNumber": 109, "undocument": true }, { - "__docId__": 782, + "__docId__": 781, "kind": "get", "name": "time", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15912,7 +15912,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#time", "access": "private", "description": null, - "lineNumber": 106, + "lineNumber": 112, "undocument": true, "type": { "types": [ @@ -15921,7 +15921,7 @@ } }, { - "__docId__": 783, + "__docId__": 782, "kind": "set", "name": "time", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15931,11 +15931,11 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#time", "access": "private", "description": null, - "lineNumber": 109, + "lineNumber": 115, "undocument": true }, { - "__docId__": 784, + "__docId__": 783, "kind": "get", "name": "trajectories", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15945,7 +15945,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#trajectories", "access": "private", "description": null, - "lineNumber": 112, + "lineNumber": 118, "undocument": true, "type": { "types": [ @@ -15954,7 +15954,7 @@ } }, { - "__docId__": 785, + "__docId__": 784, "kind": "constructor", "name": "constructor", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -15964,7 +15964,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#constructor", "access": "public", "description": "Constructor.", - "lineNumber": 124, + "lineNumber": 130, "params": [ { "nullable": null, @@ -16013,7 +16013,7 @@ ] }, { - "__docId__": 786, + "__docId__": 785, "kind": "member", "name": "allowRenderWhenAnimating", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16021,7 +16021,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#allowRenderWhenAnimating", "access": "private", "description": null, - "lineNumber": 128, + "lineNumber": 134, "undocument": true, "type": { "types": [ @@ -16030,7 +16030,7 @@ } }, { - "__docId__": 787, + "__docId__": 786, "kind": "member", "name": "maxNbFeaturesRequested", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16038,7 +16038,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#maxNbFeaturesRequested", "access": "private", "description": null, - "lineNumber": 129, + "lineNumber": 135, "undocument": true, "type": { "types": [ @@ -16047,7 +16047,7 @@ } }, { - "__docId__": 788, + "__docId__": 787, "kind": "member", "name": "olEventsKeys", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16055,7 +16055,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#olEventsKeys", "access": "private", "description": null, - "lineNumber": 130, + "lineNumber": 136, "undocument": true, "type": { "types": [ @@ -16064,7 +16064,7 @@ } }, { - "__docId__": 789, + "__docId__": 788, "kind": "member", "name": "engine", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16072,7 +16072,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#engine", "access": "private", "description": null, - "lineNumber": 133, + "lineNumber": 139, "undocument": true, "type": { "types": [ @@ -16081,7 +16081,7 @@ } }, { - "__docId__": 791, + "__docId__": 790, "kind": "member", "name": "vectorLayer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16089,7 +16089,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#vectorLayer", "access": "private", "description": null, - "lineNumber": 136, + "lineNumber": 142, "undocument": true, "type": { "types": [ @@ -16098,7 +16098,7 @@ } }, { - "__docId__": 792, + "__docId__": 791, "kind": "member", "name": "onZoomEndDebounced", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16106,7 +16106,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onZoomEndDebounced", "access": "private", "description": null, - "lineNumber": 145, + "lineNumber": 151, "undocument": true, "type": { "types": [ @@ -16115,7 +16115,7 @@ } }, { - "__docId__": 793, + "__docId__": 792, "kind": "member", "name": "onMoveEndDebounced", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16123,7 +16123,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onMoveEndDebounced", "access": "private", "description": null, - "lineNumber": 146, + "lineNumber": 152, "undocument": true, "type": { "types": [ @@ -16132,7 +16132,7 @@ } }, { - "__docId__": 794, + "__docId__": 793, "kind": "method", "name": "addTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16142,7 +16142,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#addTrajectory", "access": "private", "description": "Add a trajectory.", - "lineNumber": 152, + "lineNumber": 158, "params": [ { "nullable": null, @@ -16158,7 +16158,7 @@ "return": null }, { - "__docId__": 795, + "__docId__": 794, "kind": "method", "name": "attachToMap", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16168,13 +16168,13 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#attachToMap", "access": "private", "description": null, - "lineNumber": 156, + "lineNumber": 162, "undocument": true, "params": [], "return": null }, { - "__docId__": 796, + "__docId__": 795, "kind": "member", "name": "currentZoom", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16182,7 +16182,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#currentZoom", "access": "private", "description": null, - "lineNumber": 180, + "lineNumber": 186, "undocument": true, "type": { "types": [ @@ -16191,7 +16191,7 @@ } }, { - "__docId__": 797, + "__docId__": 796, "kind": "method", "name": "cleanVectorLayer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16201,13 +16201,13 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#cleanVectorLayer", "access": "private", "description": null, - "lineNumber": 197, + "lineNumber": 203, "undocument": true, "params": [], "return": null }, { - "__docId__": 798, + "__docId__": 797, "kind": "method", "name": "clone", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16217,7 +16217,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#clone", "access": "public", "description": "Create a copy of the RealtimeLayer.", - "lineNumber": 209, + "lineNumber": 215, "params": [ { "nullable": null, @@ -16240,7 +16240,7 @@ } }, { - "__docId__": 799, + "__docId__": 798, "kind": "method", "name": "createRenderer", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16250,7 +16250,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#createRenderer", "access": "private", "description": null, - "lineNumber": 212, + "lineNumber": 218, "undocument": true, "params": [], "return": { @@ -16260,7 +16260,7 @@ } }, { - "__docId__": 800, + "__docId__": 799, "kind": "method", "name": "detachFromMap", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16270,12 +16270,12 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#detachFromMap", "access": "private", "description": "Destroy the container of the tracker.", - "lineNumber": 218, + "lineNumber": 224, "params": [], "return": null }, { - "__docId__": 801, + "__docId__": 800, "kind": "method", "name": "getFullTrajectory", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16285,7 +16285,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#getFullTrajectory", "access": "public", "description": "Get the full trajectory of a vehicle as features.", - "lineNumber": 231, + "lineNumber": 237, "unknown": [ { "tagName": "@returns", @@ -16314,7 +16314,7 @@ } }, { - "__docId__": 802, + "__docId__": 801, "kind": "method", "name": "getStopSequences", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16324,7 +16324,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#getStopSequences", "access": "public", "description": "Get the stop sequences of a vehicle.", - "lineNumber": 248, + "lineNumber": 254, "unknown": [ { "tagName": "@returns", @@ -16353,7 +16353,7 @@ } }, { - "__docId__": 803, + "__docId__": 802, "kind": "method", "name": "getTrajectoryInfos", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16363,7 +16363,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#getTrajectoryInfos", "access": "private", "description": "Get full trajectory and stop sequences of a vehicle.", - "lineNumber": 260, + "lineNumber": 266, "unknown": [ { "tagName": "@returns", @@ -16392,7 +16392,7 @@ } }, { - "__docId__": 804, + "__docId__": 803, "kind": "method", "name": "getVehicles", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16402,7 +16402,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#getVehicles", "access": "private", "description": null, - "lineNumber": 272, + "lineNumber": 278, "undocument": true, "params": [ { @@ -16419,7 +16419,7 @@ } }, { - "__docId__": 805, + "__docId__": 804, "kind": "method", "name": "getViewState", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16429,7 +16429,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#getViewState", "access": "private", "description": null, - "lineNumber": 275, + "lineNumber": 281, "undocument": true, "params": [], "return": { @@ -16439,7 +16439,7 @@ } }, { - "__docId__": 806, + "__docId__": 805, "kind": "method", "name": "highlight", "memberof": "build/ol/layers/RealtimeLayer.js~RealtimeLayer", @@ -16449,7 +16449,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#highlight", "access": "private", "description": null, - "lineNumber": 301, + "lineNumber": 307, "undocument": true, "params": [ { @@ -16472,7 +16472,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#highlightTrajectory", "access": "private", "description": "Highlight the trajectory of journey.", - "lineNumber": 312, + "lineNumber": 322, "params": [ { "name": "id", @@ -16498,7 +16498,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onMoveEnd", "access": "private", "description": null, - "lineNumber": 333, + "lineNumber": 343, "undocument": true, "params": [], "return": null @@ -16514,7 +16514,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onRealtimeEngineIdle", "access": "private", "description": null, - "lineNumber": 339, + "lineNumber": 349, "undocument": true, "params": [], "return": null @@ -16530,7 +16530,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onRealtimeEngineRender", "access": "private", "description": "Callback when the RealtimeEngine has rendered successfully.", - "lineNumber": 345, + "lineNumber": 355, "params": [ { "name": "renderState", @@ -16556,7 +16556,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#renderedViewState", "access": "private", "description": null, - "lineNumber": 346, + "lineNumber": 356, "undocument": true, "type": { "types": [ @@ -16575,7 +16575,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#onZoomEnd", "access": "private", "description": null, - "lineNumber": 353, + "lineNumber": 363, "undocument": true, "params": [], "return": null @@ -16591,7 +16591,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#removeTrajectory", "access": "private", "description": "Remove a trajectory.", - "lineNumber": 364, + "lineNumber": 374, "params": [ { "nullable": null, @@ -16617,7 +16617,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#renderTrajectories", "access": "private", "description": "Render the trajectories of the vehicles.", - "lineNumber": 372, + "lineNumber": 382, "deprecated": "Use this.engine.renderTrajectories instead.", "params": [ { @@ -16640,7 +16640,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#select", "access": "private", "description": null, - "lineNumber": 376, + "lineNumber": 386, "undocument": true, "params": [ { @@ -16663,7 +16663,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#setMapInternal", "access": "private", "description": null, - "lineNumber": 391, + "lineNumber": 401, "undocument": true, "params": [ { @@ -16686,7 +16686,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#shouldRender", "access": "private", "description": null, - "lineNumber": 401, + "lineNumber": 411, "undocument": true, "params": [], "return": { @@ -16706,7 +16706,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#start", "access": "public", "description": "Start the rendering.", - "lineNumber": 413, + "lineNumber": 423, "params": [], "return": null }, @@ -16721,7 +16721,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#stop", "access": "public", "description": "Stop the rendering.", - "lineNumber": 421, + "lineNumber": 431, "params": [], "return": null }, @@ -16736,7 +16736,7 @@ "longname": "build/ol/layers/RealtimeLayer.js~RealtimeLayer#updateHighlightFeatures", "access": "private", "description": null, - "lineNumber": 424, + "lineNumber": 434, "undocument": true, "params": [ { @@ -16882,7 +16882,7 @@ "__docId__": 830, "kind": "file", "name": "build/ol/renderers/MaplibreLayerRenderer.js", - "content": "import { MapLibreLayerRenderer } from '@geoblocks/ol-maplibre-layer/lib';\n/**\n * This class is usea renderer for Maplibre Layer to be able to use the native ol\n * functionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.\n * @private\n */\nexport default class MaplibreLayerRenderer extends MapLibreLayerRenderer {\n constructor(layer, translateZoom) {\n super(layer, translateZoom);\n this.ignoreNextRender = false;\n this.tranaslateZoom2 = translateZoom;\n this.setIsReady = this.setIsReady.bind(this);\n this.ignoreNextRender = false;\n }\n prepareFrame() {\n return true;\n }\n renderFrame(frameState) {\n const layer = this.getLayer();\n const { mapLibreMap } = layer;\n const map = layer.getMapInternal();\n if (!layer || !map || !mapLibreMap) {\n // @ts-expect-error - can return null\n return null;\n }\n if (this.ready && this.ignoreNextRender) {\n this.ignoreNextRender = false;\n return mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.getContainer();\n }\n this.ready = false;\n this.ignoreNextRender = false;\n this.updateReadyState();\n const container = super.renderFrame(frameState);\n // Mark the renderer as ready when the map is idle\n void (mapLibreMap === null || mapLibreMap === void 0 ? void 0 : mapLibreMap.once('idle', this.setIsReady.bind(this)));\n return container;\n }\n setIsReady() {\n if (!this.ready) {\n this.ready = true;\n this.ignoreNextRender = true;\n this.getLayer().changed();\n }\n }\n updateReadyState() {\n var _a, _b, _c, _d;\n void ((_b = (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.mapLibreMap) === null || _b === void 0 ? void 0 : _b.off('idle', this.setIsReady.bind(this)));\n void ((_d = (_c = this.getLayer()) === null || _c === void 0 ? void 0 : _c.mapLibreMap) === null || _d === void 0 ? void 0 : _d.once('idle', this.setIsReady.bind(this)));\n }\n}\n", + "content": "import { MapLibreLayerRenderer } from '@geoblocks/ol-maplibre-layer/lib';\nimport { toDegrees } from 'ol/math.js';\nimport { toLonLat } from 'ol/proj';\nfunction sameSize(map, frameState) {\n return (map.transform.width === Math.floor(frameState.size[0]) &&\n map.transform.height === Math.floor(frameState.size[1]));\n}\n/**\n * This class is usea renderer for Maplibre Layer to be able to use the native ol\n * functionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.\n * @private\n */\nexport default class MaplibreLayerRenderer extends MapLibreLayerRenderer {\n constructor(layer, translateZoom) {\n super(layer, translateZoom);\n this.ignoreNextRender = false;\n this.translateZoom2 = translateZoom;\n this.setIsReady = this.setIsReady.bind(this);\n this.ignoreNextRender = false;\n }\n prepareFrame() {\n return true;\n }\n renderFrame(frameState) {\n const layer = this.getLayer();\n const { mapLibreMap } = layer;\n const map = layer.getMapInternal();\n if (!layer || !map || !mapLibreMap) {\n // @ts-expect-error - can return null\n return null;\n }\n // eslint-disable-next-line @typescript-eslint/unbound-method\n void mapLibreMap.off('idle', this.setIsReady);\n // When the browser is zoomed it could happens that the renderFrame call for readyness\n // in setIsReady is called with a different size than the one of the mapLibreMap,\n // so we need to render.\n if (this.ready &&\n this.ignoreNextRender &&\n sameSize(mapLibreMap, frameState)) {\n this.ignoreNextRender = false;\n return mapLibreMap.getContainer();\n }\n this.ready = false;\n this.ignoreNextRender = false;\n const mapLibreCanvas = mapLibreMap.getCanvas();\n const { viewState } = frameState;\n // adjust view parameters in MapLibre\n mapLibreMap.jumpTo({\n bearing: toDegrees(-viewState.rotation),\n center: toLonLat(viewState.center, viewState.projection),\n zoom: (this.translateZoom2\n ? this.translateZoom2(viewState.zoom)\n : viewState.zoom) - 1,\n });\n const opacity = layer.getOpacity().toString();\n if (opacity !== (mapLibreCanvas === null || mapLibreCanvas === void 0 ? void 0 : mapLibreCanvas.style.opacity)) {\n mapLibreCanvas.style.opacity = opacity;\n }\n if (!mapLibreCanvas.isConnected) {\n // The canvas is not connected to the DOM, request a map rendering at the next animation frame\n // to set the canvas size.\n map.render();\n }\n else if (!sameSize(mapLibreMap, frameState)) {\n mapLibreMap.resize();\n }\n // eslint-disable-next-line @typescript-eslint/unbound-method\n void mapLibreMap.once('idle', this.setIsReady);\n mapLibreMap.redraw();\n return mapLibreMap.getContainer();\n }\n setIsReady() {\n var _a;\n if (!this.ready) {\n this.ready = true;\n this.ignoreNextRender = true;\n (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.changed();\n }\n }\n}\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/renderers/MaplibreLayerRenderer.js", "access": "private", @@ -16891,6 +16891,43 @@ }, { "__docId__": 831, + "kind": "function", + "name": "sameSize", + "memberof": "build/ol/renderers/MaplibreLayerRenderer.js", + "generator": false, + "async": false, + "static": true, + "longname": "build/ol/renderers/MaplibreLayerRenderer.js~sameSize", + "access": "private", + "export": false, + "importPath": "mobility-toolbox-js/build/ol/renderers/MaplibreLayerRenderer.js", + "importStyle": null, + "description": null, + "lineNumber": 4, + "undocument": true, + "params": [ + { + "name": "map", + "types": [ + "*" + ] + }, + { + "name": "frameState", + "types": [ + "*" + ] + } + ], + "return": { + "types": [ + "*" + ] + }, + "ignore": true + }, + { + "__docId__": 832, "kind": "class", "name": "MaplibreLayerRenderer", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js", @@ -16901,14 +16938,14 @@ "importPath": "mobility-toolbox-js/build/ol/renderers/MaplibreLayerRenderer.js", "importStyle": "MaplibreLayerRenderer", "description": "This class is usea renderer for Maplibre Layer to be able to use the native ol\nfunctionnalities like map.getFeaturesAtPixel or map.hasFeatureAtPixel.", - "lineNumber": 7, + "lineNumber": 13, "interface": false, "extends": [ "@geoblocks/ol-maplibre-layer/lib~MapLibreLayerRenderer" ] }, { - "__docId__": 832, + "__docId__": 833, "kind": "constructor", "name": "constructor", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16918,11 +16955,11 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#constructor", "access": "private", "description": null, - "lineNumber": 8, + "lineNumber": 14, "undocument": true }, { - "__docId__": 833, + "__docId__": 834, "kind": "member", "name": "ignoreNextRender", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16930,7 +16967,7 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#ignoreNextRender", "access": "private", "description": null, - "lineNumber": 10, + "lineNumber": 16, "undocument": true, "type": { "types": [ @@ -16939,15 +16976,15 @@ } }, { - "__docId__": 834, + "__docId__": 835, "kind": "member", - "name": "tranaslateZoom2", + "name": "translateZoom2", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", "static": false, - "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#tranaslateZoom2", + "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#translateZoom2", "access": "private", "description": null, - "lineNumber": 11, + "lineNumber": 17, "undocument": true, "type": { "types": [ @@ -16956,7 +16993,7 @@ } }, { - "__docId__": 837, + "__docId__": 838, "kind": "method", "name": "prepareFrame", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16966,7 +17003,7 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#prepareFrame", "access": "private", "description": null, - "lineNumber": 15, + "lineNumber": 21, "undocument": true, "params": [], "return": { @@ -16976,7 +17013,7 @@ } }, { - "__docId__": 838, + "__docId__": 839, "kind": "method", "name": "renderFrame", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -16986,7 +17023,7 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#renderFrame", "access": "private", "description": null, - "lineNumber": 18, + "lineNumber": 24, "undocument": true, "params": [ { @@ -17003,7 +17040,7 @@ } }, { - "__docId__": 840, + "__docId__": 841, "kind": "member", "name": "ready", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -17011,7 +17048,7 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#ready", "access": "private", "description": null, - "lineNumber": 30, + "lineNumber": 43, "undocument": true, "type": { "types": [ @@ -17020,7 +17057,7 @@ } }, { - "__docId__": 842, + "__docId__": 843, "kind": "method", "name": "setIsReady", "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", @@ -17030,23 +17067,7 @@ "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#setIsReady", "access": "private", "description": null, - "lineNumber": 38, - "undocument": true, - "params": [], - "return": null - }, - { - "__docId__": 845, - "kind": "method", - "name": "updateReadyState", - "memberof": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer", - "generator": false, - "async": false, - "static": false, - "longname": "build/ol/renderers/MaplibreLayerRenderer.js~MaplibreLayerRenderer#updateReadyState", - "access": "private", - "description": null, - "lineNumber": 45, + "lineNumber": 72, "undocument": true, "params": [], "return": null @@ -17810,7 +17831,7 @@ "__docId__": 879, "kind": "file", "name": "build/ol/utils/MapsetKmlFormat.js", - "content": "import { replace } from 'lodash';\nimport { Feature, getUid } from 'ol';\nimport { asString } from 'ol/color';\nimport KML from 'ol/format/KML';\nimport CircleGeom from 'ol/geom/Circle';\nimport GeometryCollection from 'ol/geom/GeometryCollection';\nimport MultiPoint from 'ol/geom/MultiPoint';\nimport Point from 'ol/geom/Point';\nimport { fromCircle } from 'ol/geom/Polygon';\nimport { get, transform } from 'ol/proj';\nimport { Circle, Fill, Icon, Stroke, Style, Text } from 'ol/style';\nimport { parse } from 'ol/xml';\nimport getPolygonPattern from './getMapsetPolygonPattern';\nconst CIRCLE_GEOMETRY_CENTER = 'circleGeometryCenter';\nconst CIRCLE_GEOMETRY_RADIUS = 'circleGeometryRadius';\nconst EPSG_4326 = get('EPSG:4326');\n// Default style for KML layer\nconst kmlFill = new Fill({\n color: [255, 0, 0, 0.7],\n});\nconst kmlStroke = new Stroke({\n color: [255, 0, 0, 1],\n width: 1.5,\n});\nconst kmlcircle = new Circle({\n fill: kmlFill,\n radius: 7,\n stroke: kmlStroke,\n});\nconst kmlStyle = new Style({\n fill: kmlFill,\n image: kmlcircle,\n stroke: kmlStroke,\n text: new Text({\n fill: kmlFill,\n font: 'normal 16px Helvetica',\n stroke: new Stroke({\n color: [255, 255, 255, 1],\n width: 3,\n }),\n }),\n});\n// Comes from ol >= 6.7,\n// https://github.com/openlayers/openlayers/blob/main/src/ol/format/KML.js#L320\nconst scaleForSize = (size) => {\n return 32 / Math.min(size[0], size[1]);\n};\nconst applyTextStyleForIcon = (olIcon, olText) => {\n const size = olIcon.getSize() || [48, 48];\n const scale = (olIcon.getScale() || 1);\n const anchor = olIcon.getAnchor() || [\n (size[0] * scale) / 2,\n (size[1] * scale) / 2,\n ];\n const offset = [\n scale * (size[0] - anchor[0]) + 5,\n scale * (size[1] / 2 - anchor[1]),\n ];\n olText.setOffsetX(offset[0]);\n olText.setOffsetY(offset[1]);\n olText.setTextAlign('left');\n};\nconst getVertexCoord = (geom, start = true, index = 0) => {\n const coords = geom === null || geom === void 0 ? void 0 : geom.getCoordinates();\n if (!coords) {\n return undefined;\n }\n const len = coords.length - 1;\n return start ? coords[index] : coords[len - index];\n};\nconst getLineIcon = (feature, icon, color, start = true) => {\n const geom = feature.getGeometry();\n const coordA = getVertexCoord(geom, start, 1);\n const coordB = getVertexCoord(geom, start);\n if (!coordA || !coordB) {\n return new Style();\n }\n const dx = start ? coordA[0] - coordB[0] : coordB[0] - coordA[0];\n const dy = start ? coordA[1] - coordB[1] : coordB[1] - coordA[1];\n const rotation = Math.atan2(dy, dx);\n return new Style({\n geometry: (feat) => {\n const ge = feat.getGeometry();\n return new Point(getVertexCoord(ge, start));\n },\n image: new Icon({\n color,\n rotateWithView: true,\n rotation: -rotation,\n scale: icon.scale,\n size: icon.size, // ie 11\n src: icon.url,\n }),\n zIndex: icon.zIndex,\n });\n};\nclass MapsetKmlFormat {\n constructor() {\n /**\n * Write the tag into a KML string. Returns the KML string with added tag.\n * @param {String} kmlString A string representing a KML file.\n * @param {Object} cameraAttributes Object containing the camera tags (longitude, latitude, altitude, heading, tilt, altitudeMode, roll)\n * as keys with corresponding values. See https://developers.google.com/kml/documentation/kmlreference#camera\n */\n this.writeDocumentCamera = (kmlString, cameraAttributes) => {\n const kmlDoc = parse(this.removeDocumentCamera(kmlString));\n if (cameraAttributes) {\n // Create Camera node with child attributes if the cameraAttributes object is defined\n const cameraNode = kmlDoc.createElement('Camera');\n Object.keys(cameraAttributes).forEach((key) => {\n const cameraAttribute = kmlDoc.createElement(`${key.charAt(0).toUpperCase() + key.slice(1)}`);\n cameraAttribute.innerHTML = cameraAttributes[key];\n cameraNode.appendChild(cameraAttribute);\n });\n const documentNode = kmlDoc.getElementsByTagName('Document')[0];\n documentNode.appendChild(cameraNode);\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n };\n }\n /**\n * Read a KML string.\n * @param {String} kmlString A string representing a KML file.\n * @param {} featureProjection The projection used by the map.\n * @param {} doNotRevert32pxScaling Set it to true if you use ol < 6.7 and last version of react-spatial, Fix the 32px scaling, introduced by (ol >= 6.7), see https://github.com/openlayers/openlayers/pull/12695.\n */\n readFeatures(kmlString, featureProjection, doNotRevert32pxScaling = false) {\n // Since ol 6.7, the KML follows better the spec and GoogleEarth interpretation, see https://github.com/openlayers/openlayers/pull/12695.\n // so the value is interpreted using an image size of 32px.\n // So when revert32pxScaling is true we fix back the scale, to use only, if you use an OL < 6.7.\n // Now the writeFeatures function use the iconScale extended data to set the image's scale.\n // If the extended data is not found it will look at this boolean to define if we must revert the scale or not.\n const features = new KML().readFeatures(kmlString, {\n featureProjection,\n });\n features.forEach((feature) => {\n var _a, _b;\n // Transform back polygon to circle geometry\n const { [CIRCLE_GEOMETRY_CENTER]: circleGeometryCenter, [CIRCLE_GEOMETRY_RADIUS]: circleGeometryRadius, } = (feature === null || feature === void 0 ? void 0 : feature.getProperties()) || {};\n if (feature && circleGeometryCenter && circleGeometryRadius) {\n const circle = new CircleGeom(transform(JSON.parse(circleGeometryCenter), EPSG_4326, featureProjection || EPSG_4326), parseFloat(circleGeometryRadius));\n circle.setProperties((_b = (_a = feature === null || feature === void 0 ? void 0 : feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getProperties()) !== null && _b !== void 0 ? _b : {});\n feature.setGeometry(circle);\n }\n this.sanitizeFeature(feature, doNotRevert32pxScaling);\n });\n return features;\n }\n /**\n * Removes the tag from a KML string. Returns the KML string with removed tag.\n * @param {String} kmlString A string representing a KML file.\n */\n removeDocumentCamera(kmlString) {\n const kmlDoc = parse(kmlString);\n // Remove old Camera node\n const oldCameraNode = kmlDoc.getElementsByTagName('Camera')[0];\n if (oldCameraNode) {\n oldCameraNode.remove();\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n }\n sanitizeFeature(feature, doNotRevert32pxScaling = false) {\n var _a, _b, _c, _d, _e, _f, _g;\n const geom = feature.getGeometry();\n let styles = feature.getStyleFunction();\n // Store maxZoom in properties\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n feature.set('maxZoom', maxZoom);\n }\n // Store minZoom in properties\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n feature.set('minZoom', minZoom);\n }\n // The use of clone is part of the scale fix for OL > 6.7\n // If an IconStyle has no gx:w and gx:h defined, a scale factor is applied\n // after the image is loaded. To avoided having the scale factor applied we\n // clone the style and keep the scale as it is.\n // Having gx:w and gx:h not defined should not happen, using the last version of the parser/reader.\n const tmpStyles = styles === null || styles === void 0 ? void 0 : styles(feature, 1);\n const style = (_a = (Array.isArray(tmpStyles) ? tmpStyles[0] : tmpStyles)) === null || _a === void 0 ? void 0 : _a.clone();\n let stroke = style === null || style === void 0 ? void 0 : style.getStroke();\n if (feature.get('lineCap')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineCap(feature.get('lineCap'));\n }\n if (feature.get('lineJoin')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineJoin(feature.get('lineJoin'));\n }\n if (feature.get('lineDash')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDash((feature === null || feature === void 0 ? void 0 : feature.get('lineDash')).split(',').map((l) => {\n return parseInt(l, 10);\n }));\n }\n if (feature.get('lineDashOffset')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDashOffset(parseInt(feature.get('lineDashOffset'), 10));\n }\n if (feature.get('miterLimit')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setMiterLimit(parseInt(feature.get('miterLimit'), 10));\n }\n // The canvas draws a stroke width=1 by default if width=0, so we\n // remove the stroke style in that case.\n if (stroke && stroke.getWidth() === 0) {\n stroke = undefined;\n }\n if (feature.get('zIndex')) {\n style === null || style === void 0 ? void 0 : style.setZIndex(parseInt(feature.get('zIndex'), 10));\n }\n // if the feature is a Point and we are offline, we use default vector\n // style.\n // if the feature is a Point and has a name with a text style, we\n // create a correct text style.\n // TODO Handle GeometryCollection displaying name on the first Point\n // geometry.\n if (style && (geom instanceof Point || geom instanceof MultiPoint)) {\n let image = style.getImage();\n let text = null;\n let fill = style.getFill();\n // If the feature has name we display it on the map as Google does\n if (feature.get('name') &&\n style.getText() &&\n ((_b = style.getText()) === null || _b === void 0 ? void 0 : _b.getScale()) !== 0) {\n if (image && image.getScale() === 0) {\n // transparentCircle is used to allow selection\n image = new Circle({\n fill: new Fill({ color: [0, 0, 0, 0] }),\n radius: 1,\n stroke: new Stroke({ color: [0, 0, 0, 0] }),\n });\n }\n // We replace empty white spaces used to keep normal spaces before and after the name.\n let name = feature.get('name');\n if (/\\u200B/g.test(name)) {\n name = name.replace(/\\u200B/g, '');\n feature.set('name', name);\n }\n // For backward compatibility we translate the bold and italic textFont property to a textArray prop\n const font = feature.get('textFont') || 'normal 16px Arial';\n // Since we use rich text in mapset editor we use a text array instead,\n // it's only necessary when there is new lines in the text\n // Manage new lines\n if (name.includes('\\n')) {\n const array = [];\n const split = name.split('\\n');\n split.forEach((txt, idx) => {\n array.push(txt || '\\u200B', txt ? font : '');\n if (idx < split.length - 1) {\n array.push('\\n', '');\n }\n });\n name = array;\n }\n else {\n name = [name, font];\n }\n text = new Text({\n fill: style.getText().getFill(),\n font: `${font.replace(/bold/g, 'normal')}, Arial, sans-serif`, // We manage bold in textArray\n // rotation unsupported by KML, taken instead from custom field.\n rotation: feature.get('textRotation') || 0,\n // stroke: style.getText().getStroke(),\n scale: (_c = style.getText()) === null || _c === void 0 ? void 0 : _c.getScale(),\n // since ol 6.3.1 : https://github.com/openlayers/openlayers/pull/10613/files#diff-1883da8b57e690db7ea0c35ce53c880aR925\n // a default textstroke is added to mimic google earth.\n // it was not the case before, the stroke was always null. So to keep\n // the same behavior we don't copy the stroke style.\n // TODO : maybe we should use this functionnality in the futur.\n text: name,\n });\n if (feature.get('textArray')) {\n try {\n const textArray = JSON.parse(replace(feature.get('textArray'), /\\r?\\n/g, '\\\\n'));\n text.setText(textArray);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('Error parsing textArray', feature.get('textArray'), err);\n }\n }\n if (feature.get('textStrokeColor') && feature.get('textStrokeWidth')) {\n text.setStroke(new Stroke({\n color: feature.get('textStrokeColor'),\n width: parseFloat(feature.get('textStrokeWidth')),\n }));\n }\n if (feature.get('textAlign')) {\n text.setTextAlign(feature.get('textAlign'));\n }\n if (feature.get('textOffsetX')) {\n text.setOffsetX(parseFloat(feature.get('textOffsetX')));\n }\n if (feature.get('textOffsetY')) {\n text.setOffsetY(parseFloat(feature.get('textOffsetY')));\n }\n if (feature.get('textBackgroundFillColor')) {\n text.setBackgroundFill(new Fill({\n color: feature.get('textBackgroundFillColor'),\n }));\n }\n if (feature.get('textPadding')) {\n text.setPadding((_d = feature.get('textPadding')) === null || _d === void 0 ? void 0 : _d.split(',').map((n) => {\n return parseFloat(n);\n }));\n }\n if (image instanceof Icon) {\n applyTextStyleForIcon(image, text);\n }\n }\n if (image instanceof Icon) {\n /* Apply icon rotation if defined (by default only written as\n * tag, which is not read as rotation value by the ol KML module)\n */\n image.setRotation(parseFloat(feature.get('iconRotation')) || 0);\n if (feature.get('iconScale')) {\n image.setScale(parseFloat(feature.get('iconScale')) || 0);\n // We fix the 32px scaling introduced by OL 6.7 only if the image has a size defined.\n }\n else if (!doNotRevert32pxScaling && image.getSize()) {\n const resizeScale = scaleForSize(image.getSize());\n image.setScale(image.getScaleArray()[0] / resizeScale);\n }\n }\n fill = null;\n stroke = null;\n styles = (feat, resolution) => {\n /* Options to be used for picture scaling with map, should have at least\n * a resolution attribute (this is the map resolution at the zoom level when\n * the picture is created), can take an optional constant for further scale\n * adjustment.\n * e.g. { resolution: 0.123, defaultScale: 1 / 6 }\n */\n var _a;\n if (feat.get('pictureOptions')) {\n let pictureOptions = feat.get('pictureOptions');\n if (typeof pictureOptions === 'string') {\n pictureOptions = JSON.parse(pictureOptions);\n }\n feat.set('pictureOptions', pictureOptions);\n if (pictureOptions.resolution) {\n image === null || image === void 0 ? void 0 : image.setScale((pictureOptions.resolution / resolution) *\n ((_a = pictureOptions === null || pictureOptions === void 0 ? void 0 : pictureOptions.defaultScale) !== null && _a !== void 0 ? _a : 1));\n }\n }\n return new Style({\n fill: fill !== null && fill !== void 0 ? fill : undefined,\n image: image !== null && image !== void 0 ? image : undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: text !== null && text !== void 0 ? text : undefined,\n zIndex: style.getZIndex(),\n });\n };\n }\n // Remove image and text styles for polygons and lines\n if (!(geom instanceof Point ||\n geom instanceof MultiPoint ||\n geom instanceof GeometryCollection)) {\n styles = [\n new Style({\n fill: (_e = style === null || style === void 0 ? void 0 : style.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: undefined,\n zIndex: style === null || style === void 0 ? void 0 : style.getZIndex(),\n }),\n ];\n // Parse the fillPattern json string and store parsed object\n const fillPattern = feature.get('fillPattern');\n if (fillPattern) {\n const fillPatternOptions = JSON.parse(fillPattern);\n feature.set('fillPattern', fillPatternOptions);\n /* We set the fill pattern for polygons */\n if (!(style === null || style === void 0 ? void 0 : style.getFill())) {\n styles[0].setFill(new Fill());\n }\n const patternOrColor = (fillPatternOptions === null || fillPatternOptions === void 0 ? void 0 : fillPatternOptions.empty)\n ? [0, 0, 0, 0]\n : getPolygonPattern(fillPatternOptions.id, fillPatternOptions.color);\n (_g = (_f = styles[0]) === null || _f === void 0 ? void 0 : _f.getFill()) === null || _g === void 0 ? void 0 : _g.setColor(patternOrColor);\n }\n // Add line's icons styles\n if (feature.get('lineStartIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineStartIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor()));\n }\n if (feature.get('lineEndIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineEndIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor(), false));\n }\n }\n feature.setStyle(styles);\n }\n /**\n * Create a KML string.\n * @param {VectorLayer} layer A openlayers VectorLayer.\n * @param {} featureProjection The current projection used by the features.\n * @param {} mapResolution The current map resolution.\n */\n writeFeatures(layer, featureProjection, mapResolution) {\n var _a, _b;\n let featString;\n const exportFeatures = [];\n [...((_b = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getFeatures()) !== null && _b !== void 0 ? _b : [])]\n .sort((a, b) => {\n // The order of features must be kept.\n // We could use the useSpatialIndex = false property on the layer\n // but we prefer to sort feature by ol uid because ol uid is an integer\n // increased on each creation of a feature.\n // So we will keep the order of creation made by the the KML parser.\n // Ideally we should order by the zIndex of the style only.\n if (getUid(a) <= getUid(b)) {\n return -1;\n }\n return 1;\n })\n .forEach((feature) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;\n const clone = feature.clone();\n if (((_a = clone.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Circle') {\n // We transform circle elements into polygons\n // because circle not supported in KML spec and in ol KML parser\n const circleGeom = feature.getGeometry();\n clone.setGeometry(fromCircle(circleGeom, 100));\n clone.set(CIRCLE_GEOMETRY_CENTER, JSON.stringify(transform(circleGeom.getCenter(), featureProjection, EPSG_4326)));\n clone.set(CIRCLE_GEOMETRY_RADIUS, circleGeom.getRadius());\n }\n clone.setId(feature.getId());\n (_b = clone.getGeometry()) === null || _b === void 0 ? void 0 : _b.transform(featureProjection, EPSG_4326);\n // We remove all ExtendedData not related to style.\n Object.keys(feature.getProperties()).forEach((key) => {\n if (![\n CIRCLE_GEOMETRY_CENTER,\n CIRCLE_GEOMETRY_RADIUS,\n 'description',\n 'geometry',\n 'name',\n ].includes(key)) {\n clone.unset(key, true);\n }\n });\n let styles;\n if (feature.getStyleFunction()) {\n styles = (_c = feature.getStyleFunction()) === null || _c === void 0 ? void 0 : _c(feature, mapResolution);\n }\n else if (layer === null || layer === void 0 ? void 0 : layer.getStyleFunction()) {\n styles = (_d = layer.getStyleFunction()) === null || _d === void 0 ? void 0 : _d(feature, mapResolution);\n }\n const mainStyle = Array.isArray(styles) ? styles[0] : styles;\n const newStyle = {\n fill: (_e = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: (_f = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getImage()) !== null && _f !== void 0 ? _f : undefined,\n stroke: (_g = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getStroke()) !== null && _g !== void 0 ? _g : undefined,\n text: (_h = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getText()) !== null && _h !== void 0 ? _h : undefined,\n zIndex: (_j = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getZIndex()) !== null && _j !== void 0 ? _j : undefined,\n };\n if (newStyle.zIndex) {\n clone.set('zIndex', newStyle.zIndex);\n }\n const text = (_k = newStyle.text) === null || _k === void 0 ? void 0 : _k.getText();\n if (text) {\n let kmlText = '';\n if (Array.isArray(text)) {\n // text can be a string or an array of strings\n clone.set('textArray', JSON.stringify(text));\n const textArray = text;\n // in the KML we just add the text without the bold or italic information\n kmlText = textArray\n .map((t, idx) => {\n return idx % 2 === 0 ? t : '';\n })\n .join('')\n .replace(/\\u200B/g, '');\n }\n // We add the current text as features's name so it will be added as Placemark's name in the kml\n if (kmlText) {\n // If we see spaces at the beginning or at the end we add a empty\n // white space at the beginning and at the end.\n if (/^(\\s|\\n)|(\\n|\\s)$/g.test(kmlText)) {\n clone.set('name', `\\u200B${kmlText}\\u200B`);\n }\n else {\n clone.set('name', kmlText);\n }\n }\n }\n // Set custom properties to be converted in extendedData in KML.\n if ((_l = newStyle.text) === null || _l === void 0 ? void 0 : _l.getRotation()) {\n clone.set('textRotation', newStyle.text.getRotation());\n }\n if ((_m = newStyle.text) === null || _m === void 0 ? void 0 : _m.getFont()) {\n clone.set('textFont', newStyle.text.getFont());\n }\n if ((_o = newStyle.text) === null || _o === void 0 ? void 0 : _o.getTextAlign()) {\n clone.set('textAlign', newStyle.text.getTextAlign());\n }\n if ((_p = newStyle.text) === null || _p === void 0 ? void 0 : _p.getOffsetX()) {\n clone.set('textOffsetX', newStyle.text.getOffsetX());\n }\n if ((_q = newStyle.text) === null || _q === void 0 ? void 0 : _q.getOffsetY()) {\n clone.set('textOffsetY', newStyle.text.getOffsetY());\n }\n if ((_r = newStyle.text) === null || _r === void 0 ? void 0 : _r.getStroke()) {\n if ((_s = newStyle.text.getStroke()) === null || _s === void 0 ? void 0 : _s.getColor()) {\n clone.set('textStrokeColor', asString((_t = newStyle.text.getStroke()) === null || _t === void 0 ? void 0 : _t.getColor()));\n }\n if ((_u = newStyle.text.getStroke()) === null || _u === void 0 ? void 0 : _u.getWidth()) {\n clone.set('textStrokeWidth', (_v = newStyle.text.getStroke()) === null || _v === void 0 ? void 0 : _v.getWidth());\n }\n }\n if ((_w = newStyle.text) === null || _w === void 0 ? void 0 : _w.getBackgroundFill()) {\n clone.set('textBackgroundFillColor', asString((_x = newStyle.text.getBackgroundFill()) === null || _x === void 0 ? void 0 : _x.getColor()));\n }\n if ((_y = newStyle.text) === null || _y === void 0 ? void 0 : _y.getPadding()) {\n clone.set('textPadding', (_z = newStyle.text.getPadding()) === null || _z === void 0 ? void 0 : _z.join());\n }\n if ((_0 = newStyle.stroke) === null || _0 === void 0 ? void 0 : _0.getLineCap()) {\n clone.set('lineCap', newStyle.stroke.getLineCap());\n }\n if ((_1 = newStyle.stroke) === null || _1 === void 0 ? void 0 : _1.getLineJoin()) {\n clone.set('lineJoin', newStyle.stroke.getLineJoin());\n }\n if ((_2 = newStyle.stroke) === null || _2 === void 0 ? void 0 : _2.getLineDash()) {\n clone.set('lineDash', (_3 = newStyle.stroke.getLineDash()) === null || _3 === void 0 ? void 0 : _3.join(','));\n }\n if ((_4 = newStyle.stroke) === null || _4 === void 0 ? void 0 : _4.getLineDashOffset()) {\n clone.set('lineDashOffset', newStyle.stroke.getLineDashOffset());\n }\n if ((_5 = newStyle.stroke) === null || _5 === void 0 ? void 0 : _5.getMiterLimit()) {\n clone.set('miterLimit', newStyle.stroke.getMiterLimit());\n }\n if (newStyle.image instanceof Circle) {\n newStyle.image = undefined;\n }\n if (newStyle.image) {\n const imgSource = newStyle.image.getSrc();\n if (!/(http(s?)):\\/\\//gi.test(imgSource)) {\n // eslint-disable-next-line no-console\n console.log('Local image source not supported for KML export.' +\n 'Should use remote web server');\n }\n if (newStyle.image.getRotation()) {\n // We set the icon rotation as extended data\n clone.set('iconRotation', newStyle.image.getRotation());\n }\n if (newStyle.image.getScale()) {\n // We set the scale as extended metadata because the in the KML is related to a 32px img, since ol >= 6.10.\n clone.set('iconScale', newStyle.image.getScale());\n }\n // Set map resolution to use for icon-to-map proportional scaling\n if (feature.get('pictureOptions')) {\n clone.set('pictureOptions', JSON.stringify(feature.get('pictureOptions')));\n }\n }\n // In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc)\n if (feature.get('fillPattern')) {\n clone.set('fillPattern', JSON.stringify(feature.get('fillPattern')));\n newStyle.fill = undefined;\n }\n // maxZoom: maximum zoom level at which the feature is displayed\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n clone.set('maxZoom', maxZoom);\n }\n // minZoom: minimum zoom level at which the feature is displayed\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n clone.set('minZoom', minZoom);\n }\n // If only text is displayed we must specify an\n // image style with scale=0\n if (newStyle.text && !newStyle.image) {\n newStyle.image = new Icon({\n scale: 0,\n src: 'noimage',\n });\n }\n // In case we use line's icon .\n const extraLineStyles = (Array.isArray(styles) && styles.slice(1)) || [];\n extraLineStyles.forEach((extraLineStyle) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n if (extraLineStyle &&\n extraLineStyle.getImage() instanceof Icon &&\n extraLineStyle.getGeometry()) {\n const coord = (_b = (_a = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getGeometry()) === null || _a === void 0 ? void 0 : _a(feature)) === null || _b === void 0 ? void 0 : _b.getCoordinates();\n const startCoord = (_c = feature.getGeometry()) === null || _c === void 0 ? void 0 : _c.getFirstCoordinate();\n if ((coord === null || coord === void 0 ? void 0 : coord[0]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[0]) &&\n (coord === null || coord === void 0 ? void 0 : coord[1]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[1])) {\n clone.set('lineStartIcon', JSON.stringify({\n scale: (_d = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _d === void 0 ? void 0 : _d.getScale(),\n size: (_e = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _e === void 0 ? void 0 : _e.getSize(),\n url: (_f = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _f === void 0 ? void 0 : _f.getSrc(),\n zIndex: extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getZIndex(),\n }));\n }\n else {\n clone.set('lineEndIcon', JSON.stringify({\n scale: (_g = extraLineStyle.getImage()) === null || _g === void 0 ? void 0 : _g.getScale(),\n size: (_h = extraLineStyle.getImage()) === null || _h === void 0 ? void 0 : _h.getSize(),\n url: (_j = extraLineStyle.getImage()) === null || _j === void 0 ? void 0 : _j.getSrc(),\n zIndex: extraLineStyle.getZIndex(),\n }));\n }\n }\n });\n const olStyle = new Style(newStyle);\n clone.setStyle(olStyle);\n if (!(clone.getGeometry() instanceof Point &&\n olStyle.getText() &&\n !((_6 = olStyle.getText()) === null || _6 === void 0 ? void 0 : _6.getText()))) {\n exportFeatures.push(clone);\n }\n });\n if (exportFeatures.length > 0) {\n if (exportFeatures.length === 1) {\n // force the add of a node\n exportFeatures.push(new Feature());\n }\n featString = new KML({\n defaultStyle: [kmlStyle],\n extractStyles: true,\n }).writeFeatures(exportFeatures);\n // Remove no image hack\n featString = featString.replace(/\\s*noimage<\\/href>\\s*<\\/Icon>/g, '');\n // Remove empty placemark added to have\n // tag\n featString = featString.replace(//g, '');\n // Add KML document name\n if (layer.get('name')) {\n featString = featString.replace(//, `${layer.get('name')}`);\n }\n }\n return featString;\n }\n}\nexport default MapsetKmlFormat;\n", + "content": "import { Feature, getUid } from 'ol';\nimport { asString } from 'ol/color';\nimport KML from 'ol/format/KML';\nimport CircleGeom from 'ol/geom/Circle';\nimport GeometryCollection from 'ol/geom/GeometryCollection';\nimport MultiPoint from 'ol/geom/MultiPoint';\nimport Point from 'ol/geom/Point';\nimport { fromCircle } from 'ol/geom/Polygon';\nimport { get, transform } from 'ol/proj';\nimport { Circle, Fill, Icon, Stroke, Style, Text } from 'ol/style';\nimport { parse } from 'ol/xml';\nimport getPolygonPattern from './getMapsetPolygonPattern';\nconst CIRCLE_GEOMETRY_CENTER = 'circleGeometryCenter';\nconst CIRCLE_GEOMETRY_RADIUS = 'circleGeometryRadius';\nconst EPSG_4326 = get('EPSG:4326');\n// Default style for KML layer\nconst kmlFill = new Fill({\n color: [255, 0, 0, 0.7],\n});\nconst kmlStroke = new Stroke({\n color: [255, 0, 0, 1],\n width: 1.5,\n});\nconst kmlcircle = new Circle({\n fill: kmlFill,\n radius: 7,\n stroke: kmlStroke,\n});\nconst kmlStyle = new Style({\n fill: kmlFill,\n image: kmlcircle,\n stroke: kmlStroke,\n text: new Text({\n fill: kmlFill,\n font: 'normal 16px Helvetica',\n stroke: new Stroke({\n color: [255, 255, 255, 1],\n width: 3,\n }),\n }),\n});\n// Comes from ol >= 6.7,\n// https://github.com/openlayers/openlayers/blob/main/src/ol/format/KML.js#L320\nconst scaleForSize = (size) => {\n return 32 / Math.min(size[0], size[1]);\n};\nconst applyTextStyleForIcon = (olIcon, olText) => {\n const size = olIcon.getSize() || [48, 48];\n const scale = (olIcon.getScale() || 1);\n const anchor = olIcon.getAnchor() || [\n (size[0] * scale) / 2,\n (size[1] * scale) / 2,\n ];\n const offset = [\n scale * (size[0] - anchor[0]) + 5,\n scale * (size[1] / 2 - anchor[1]),\n ];\n olText.setOffsetX(offset[0]);\n olText.setOffsetY(offset[1]);\n olText.setTextAlign('left');\n};\nconst getVertexCoord = (geom, start = true, index = 0) => {\n const coords = geom === null || geom === void 0 ? void 0 : geom.getCoordinates();\n if (!coords) {\n return undefined;\n }\n const len = coords.length - 1;\n return start ? coords[index] : coords[len - index];\n};\nconst getLineIcon = (feature, icon, color, start = true) => {\n const geom = feature.getGeometry();\n const coordA = getVertexCoord(geom, start, 1);\n const coordB = getVertexCoord(geom, start);\n if (!coordA || !coordB) {\n return new Style();\n }\n const dx = start ? coordA[0] - coordB[0] : coordB[0] - coordA[0];\n const dy = start ? coordA[1] - coordB[1] : coordB[1] - coordA[1];\n const rotation = Math.atan2(dy, dx);\n return new Style({\n geometry: (feat) => {\n const ge = feat.getGeometry();\n return new Point(getVertexCoord(ge, start));\n },\n image: new Icon({\n color,\n rotateWithView: true,\n rotation: -rotation,\n scale: icon.scale,\n size: icon.size, // ie 11\n src: icon.url,\n }),\n zIndex: icon.zIndex,\n });\n};\nclass MapsetKmlFormat {\n constructor() {\n /**\n * Write the tag into a KML string. Returns the KML string with added tag.\n * @param {String} kmlString A string representing a KML file.\n * @param {Object} cameraAttributes Object containing the camera tags (longitude, latitude, altitude, heading, tilt, altitudeMode, roll)\n * as keys with corresponding values. See https://developers.google.com/kml/documentation/kmlreference#camera\n */\n this.writeDocumentCamera = (kmlString, cameraAttributes) => {\n const kmlDoc = parse(this.removeDocumentCamera(kmlString));\n if (cameraAttributes) {\n // Create Camera node with child attributes if the cameraAttributes object is defined\n const cameraNode = kmlDoc.createElement('Camera');\n Object.keys(cameraAttributes).forEach((key) => {\n const cameraAttribute = kmlDoc.createElement(`${key.charAt(0).toUpperCase() + key.slice(1)}`);\n cameraAttribute.innerHTML = cameraAttributes[key];\n cameraNode.appendChild(cameraAttribute);\n });\n const documentNode = kmlDoc.getElementsByTagName('Document')[0];\n documentNode.appendChild(cameraNode);\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n };\n }\n /**\n * Read a KML string.\n *\n * @param {String} kmlString A string representing a KML file.\n * @param {Object} formatOptions used to read and writes features. It extends the ol KML format read options with some custom options.\n * @param {boolean} [formatOptions.applyMinMaxZoom=true] Generate a style function to apply the minZoom and maxZoom properties of features if they are defined and if the getResolutionForZoom function is provided in options. The style function will return undefined for features that are out of the zoom range defined by minZoom and maxZoom, so they will not be displayed on the map.\n * @param {boolean} [formatOptions.doNotRevert32pxScaling=false] Set it to true if you use ol < 6.7 and last version of react-spatial, Fix the 32px scaling, introduced by (ol >= 6.7), see https://github.com/openlayers/openlayers/pull/12695.\n * @param {function} [formatOptions.getResolutionForZoom] A function to get the resolution for a given zoom level. Mandatory if applyMinMaxZoom is true. It can be the map.getView().getResolutionForZoom function.\n */\n readFeatures(kmlString, formatOptions = {}) {\n // Since ol 6.7, the KML follows better the spec and GoogleEarth interpretation, see https://github.com/openlayers/openlayers/pull/12695.\n // so the value is interpreted using an image size of 32px.\n // So when revert32pxScaling is true we fix back the scale, to use only, if you use an OL < 6.7.\n // Now the writeFeatures function use the iconScale extended data to set the image's scale.\n // If the extended data is not found it will look at this boolean to define if we must revert the scale or not.\n const { featureProjection = EPSG_4326 } = formatOptions;\n const features = new KML().readFeatures(kmlString, formatOptions);\n features.forEach((feature) => {\n var _a, _b;\n // Transform back polygon to circle geometry\n const { [CIRCLE_GEOMETRY_CENTER]: circleGeometryCenter, [CIRCLE_GEOMETRY_RADIUS]: circleGeometryRadius, } = (feature === null || feature === void 0 ? void 0 : feature.getProperties()) || {};\n if (feature && circleGeometryCenter && circleGeometryRadius) {\n const circle = new CircleGeom(transform(JSON.parse(circleGeometryCenter), EPSG_4326, featureProjection), parseFloat(circleGeometryRadius));\n circle.setProperties((_b = (_a = feature === null || feature === void 0 ? void 0 : feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getProperties()) !== null && _b !== void 0 ? _b : {});\n feature.setGeometry(circle);\n }\n this.sanitizeFeature(feature, formatOptions);\n });\n return features;\n }\n /**\n * Removes the tag from a KML string. Returns the KML string with removed tag.\n * @param {String} kmlString A string representing a KML file.\n */\n removeDocumentCamera(kmlString) {\n const kmlDoc = parse(kmlString);\n // Remove old Camera node\n const oldCameraNode = kmlDoc.getElementsByTagName('Camera')[0];\n if (oldCameraNode) {\n oldCameraNode.remove();\n }\n return new XMLSerializer().serializeToString(kmlDoc);\n }\n sanitizeFeature(feature, formatOptions) {\n var _a, _b, _c, _d, _e, _f, _g;\n const { applyMinMaxZoom = true, doNotRevert32pxScaling = false, getResolutionForZoom, } = formatOptions;\n const geom = feature.getGeometry();\n let styles = feature.getStyleFunction();\n // Store maxZoom in properties\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n feature.set('maxZoom', maxZoom);\n }\n // Store minZoom in properties\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n feature.set('minZoom', minZoom);\n }\n // The use of clone is part of the scale fix for OL > 6.7\n // If an IconStyle has no gx:w and gx:h defined, a scale factor is applied\n // after the image is loaded. To avoided having the scale factor applied we\n // clone the style and keep the scale as it is.\n // Having gx:w and gx:h not defined should not happen, using the last version of the parser/reader.\n const tmpStyles = styles === null || styles === void 0 ? void 0 : styles(feature, 1);\n const style = (_a = (Array.isArray(tmpStyles) ? tmpStyles[0] : tmpStyles)) === null || _a === void 0 ? void 0 : _a.clone();\n let stroke = style === null || style === void 0 ? void 0 : style.getStroke();\n if (feature.get('lineCap')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineCap(feature.get('lineCap'));\n }\n if (feature.get('lineJoin')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineJoin(feature.get('lineJoin'));\n }\n if (feature.get('lineDash')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDash((feature === null || feature === void 0 ? void 0 : feature.get('lineDash')).split(',').map((l) => {\n return parseInt(l, 10);\n }));\n }\n if (feature.get('lineDashOffset')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setLineDashOffset(parseInt(feature.get('lineDashOffset'), 10));\n }\n if (feature.get('miterLimit')) {\n stroke === null || stroke === void 0 ? void 0 : stroke.setMiterLimit(parseInt(feature.get('miterLimit'), 10));\n }\n // The canvas draws a stroke width=1 by default if width=0, so we\n // remove the stroke style in that case.\n if (stroke && stroke.getWidth() === 0) {\n stroke = undefined;\n }\n if (feature.get('zIndex')) {\n style === null || style === void 0 ? void 0 : style.setZIndex(parseInt(feature.get('zIndex'), 10));\n }\n // if the feature is a Point and we are offline, we use default vector\n // style.\n // if the feature is a Point and has a name with a text style, we\n // create a correct text style.\n // TODO Handle GeometryCollection displaying name on the first Point\n // geometry.\n if (style && (geom instanceof Point || geom instanceof MultiPoint)) {\n let image = style.getImage();\n let text = null;\n let fill = style.getFill();\n // If the feature has name we display it on the map as Google does\n if (feature.get('name') &&\n style.getText() &&\n ((_b = style.getText()) === null || _b === void 0 ? void 0 : _b.getScale()) !== 0) {\n if (image && image.getScale() === 0) {\n // transparentCircle is used to allow selection\n image = new Circle({\n fill: new Fill({ color: [0, 0, 0, 0] }),\n radius: 1,\n stroke: new Stroke({ color: [0, 0, 0, 0] }),\n });\n }\n // We replace empty white spaces used to keep normal spaces before and after the name.\n let name = feature.get('name');\n if (/\\u200B/g.test(name)) {\n name = name.replace(/\\u200B/g, '');\n feature.set('name', name);\n }\n // For backward compatibility we translate the bold and italic textFont property to a textArray prop\n const font = feature.get('textFont') || 'normal 16px Arial';\n // Since we use rich text in mapset editor we use a text array instead,\n // it's only necessary when there is new lines in the text\n // Manage new lines\n if (name.includes('\\n')) {\n const array = [];\n const split = name.split('\\n');\n split.forEach((txt, idx) => {\n array.push(txt || '\\u200B', txt ? font : '');\n if (idx < split.length - 1) {\n array.push('\\n', '');\n }\n });\n name = array;\n }\n else {\n name = [name, font];\n }\n text = new Text({\n fill: style.getText().getFill(),\n font: `${font.replace(/bold/g, 'normal')}, Arial, sans-serif`, // We manage bold in textArray\n // rotation unsupported by KML, taken instead from custom field.\n rotation: feature.get('textRotation') || 0,\n // stroke: style.getText().getStroke(),\n scale: (_c = style.getText()) === null || _c === void 0 ? void 0 : _c.getScale(),\n // since ol 6.3.1 : https://github.com/openlayers/openlayers/pull/10613/files#diff-1883da8b57e690db7ea0c35ce53c880aR925\n // a default textstroke is added to mimic google earth.\n // it was not the case before, the stroke was always null. So to keep\n // the same behavior we don't copy the stroke style.\n // TODO : maybe we should use this functionnality in the futur.\n text: name,\n });\n if (feature.get('textArray')) {\n try {\n const textArray = JSON.parse((feature.get('textArray') || '').replace(/\\r?\\n/g, '\\\\n'));\n text.setText(textArray);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error('Error parsing textArray', feature.get('textArray'), err);\n }\n }\n if (feature.get('textStrokeColor') && feature.get('textStrokeWidth')) {\n text.setStroke(new Stroke({\n color: feature.get('textStrokeColor'),\n width: parseFloat(feature.get('textStrokeWidth')),\n }));\n }\n if (feature.get('textAlign')) {\n text.setTextAlign(feature.get('textAlign'));\n }\n if (feature.get('textOffsetX')) {\n text.setOffsetX(parseFloat(feature.get('textOffsetX')));\n }\n if (feature.get('textOffsetY')) {\n text.setOffsetY(parseFloat(feature.get('textOffsetY')));\n }\n if (feature.get('textBackgroundFillColor')) {\n text.setBackgroundFill(new Fill({\n color: feature.get('textBackgroundFillColor'),\n }));\n }\n if (feature.get('textPadding')) {\n text.setPadding((_d = feature.get('textPadding')) === null || _d === void 0 ? void 0 : _d.split(',').map((n) => {\n return parseFloat(n);\n }));\n }\n if (image instanceof Icon) {\n applyTextStyleForIcon(image, text);\n }\n }\n if (image instanceof Icon) {\n /* Apply icon rotation if defined (by default only written as\n * tag, which is not read as rotation value by the ol KML module)\n */\n image.setRotation(parseFloat(feature.get('iconRotation')) || 0);\n if (feature.get('iconScale')) {\n image.setScale(parseFloat(feature.get('iconScale')) || 0);\n // We fix the 32px scaling introduced by OL 6.7 only if the image has a size defined.\n }\n else if (!doNotRevert32pxScaling && image.getSize()) {\n const resizeScale = scaleForSize(image.getSize());\n image.setScale(image.getScaleArray()[0] / resizeScale);\n }\n }\n fill = null;\n stroke = null;\n styles = ((feat, resolution) => {\n /* Options to be used for picture scaling with map, should have at least\n * a resolution attribute (this is the map resolution at the zoom level when\n * the picture is created), can take an optional constant for further scale\n * adjustment.\n * e.g. { resolution: 0.123, defaultScale: 1 / 6 }\n */\n var _a;\n if (feat.get('pictureOptions')) {\n let pictureOptions = feat.get('pictureOptions');\n if (typeof pictureOptions === 'string') {\n pictureOptions = JSON.parse(pictureOptions);\n }\n feat.set('pictureOptions', pictureOptions);\n if (pictureOptions.resolution) {\n image === null || image === void 0 ? void 0 : image.setScale((pictureOptions.resolution / resolution) *\n ((_a = pictureOptions === null || pictureOptions === void 0 ? void 0 : pictureOptions.defaultScale) !== null && _a !== void 0 ? _a : 1));\n }\n }\n return new Style({\n fill: fill !== null && fill !== void 0 ? fill : undefined,\n image: image !== null && image !== void 0 ? image : undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: text !== null && text !== void 0 ? text : undefined,\n zIndex: style.getZIndex(),\n });\n });\n }\n // Remove image and text styles for polygons and lines\n if (!(geom instanceof Point ||\n geom instanceof MultiPoint ||\n geom instanceof GeometryCollection)) {\n styles = [\n new Style({\n fill: (_e = style === null || style === void 0 ? void 0 : style.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: undefined,\n stroke: stroke !== null && stroke !== void 0 ? stroke : undefined,\n text: undefined,\n zIndex: style === null || style === void 0 ? void 0 : style.getZIndex(),\n }),\n ];\n // Parse the fillPattern json string and store parsed object\n const fillPattern = feature.get('fillPattern');\n if (fillPattern) {\n const fillPatternOptions = JSON.parse(fillPattern);\n feature.set('fillPattern', fillPatternOptions);\n /* We set the fill pattern for polygons */\n if (!(style === null || style === void 0 ? void 0 : style.getFill())) {\n styles[0].setFill(new Fill());\n }\n const patternOrColor = (fillPatternOptions === null || fillPatternOptions === void 0 ? void 0 : fillPatternOptions.empty)\n ? [0, 0, 0, 0]\n : getPolygonPattern(fillPatternOptions.id, fillPatternOptions.color);\n (_g = (_f = styles[0]) === null || _f === void 0 ? void 0 : _f.getFill()) === null || _g === void 0 ? void 0 : _g.setColor(patternOrColor);\n }\n // Add line's icons styles\n if (feature.get('lineStartIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineStartIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor()));\n }\n if (feature.get('lineEndIcon')) {\n styles.push(getLineIcon(feature, JSON.parse(feature.get('lineEndIcon')), stroke === null || stroke === void 0 ? void 0 : stroke.getColor(), false));\n }\n }\n // Apply minZoom and maxZoom properties if they are defined on the feature\n // and if the getResolutionForZoom function is provided in options\n let styleFunction = undefined;\n if (applyMinMaxZoom &&\n getResolutionForZoom &&\n (!Number.isNaN(feature.get('minZoom')) ||\n !Number.isNaN(feature.get('maxZoom')))) {\n styleFunction = (feat, resolution) => {\n const minRes = getResolutionForZoom(feature.get('minZoom') || -Infinity);\n const maxRes = getResolutionForZoom(feature.get('maxZoom') || Infinity);\n // We test if the resolution exists because you could call the styleFuntion\n // with an undefined resolution like in mapset to get the actula styles\n // without applying the min max zoom filter.\n if (!Number.isNaN(resolution) &&\n (resolution >= minRes || maxRes >= resolution)) {\n return;\n }\n if (typeof styles === 'function') {\n return styles(feat, resolution);\n }\n return styles;\n };\n }\n feature.setStyle(styleFunction !== null && styleFunction !== void 0 ? styleFunction : styles);\n }\n /**\n * Create a KML string.\n * @param {VectorLayer} layer A openlayers VectorLayer.\n * @param {} featureProjection The current projection used by the features.\n * @param {} mapResolution The current map resolution.\n */\n writeFeatures(layer, featureProjection, mapResolution) {\n var _a, _b;\n let featString;\n const exportFeatures = [];\n [...((_b = (_a = layer === null || layer === void 0 ? void 0 : layer.getSource()) === null || _a === void 0 ? void 0 : _a.getFeatures()) !== null && _b !== void 0 ? _b : [])]\n .sort((a, b) => {\n // The order of features must be kept.\n // We could use the useSpatialIndex = false property on the layer\n // but we prefer to sort feature by ol uid because ol uid is an integer\n // increased on each creation of a feature.\n // So we will keep the order of creation made by the the KML parser.\n // Ideally we should order by the zIndex of the style only.\n if (getUid(a) <= getUid(b)) {\n return -1;\n }\n return 1;\n })\n .forEach((feature) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;\n const clone = feature.clone();\n if (((_a = clone.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Circle') {\n // We transform circle elements into polygons\n // because circle not supported in KML spec and in ol KML parser\n const circleGeom = feature.getGeometry();\n clone.setGeometry(fromCircle(circleGeom, 100));\n clone.set(CIRCLE_GEOMETRY_CENTER, JSON.stringify(transform(circleGeom.getCenter(), featureProjection, EPSG_4326)));\n clone.set(CIRCLE_GEOMETRY_RADIUS, circleGeom.getRadius());\n }\n clone.setId(feature.getId());\n (_b = clone.getGeometry()) === null || _b === void 0 ? void 0 : _b.transform(featureProjection, EPSG_4326);\n // We remove all ExtendedData not related to style.\n Object.keys(feature.getProperties()).forEach((key) => {\n if (![\n CIRCLE_GEOMETRY_CENTER,\n CIRCLE_GEOMETRY_RADIUS,\n 'description',\n 'geometry',\n 'name',\n ].includes(key)) {\n clone.unset(key, true);\n }\n });\n let styles;\n if (feature.getStyleFunction()) {\n styles = (_c = feature.getStyleFunction()) === null || _c === void 0 ? void 0 : _c(feature, mapResolution);\n }\n else if (layer === null || layer === void 0 ? void 0 : layer.getStyleFunction()) {\n styles = (_d = layer.getStyleFunction()) === null || _d === void 0 ? void 0 : _d(feature, mapResolution);\n }\n const mainStyle = Array.isArray(styles) ? styles[0] : styles;\n const newStyle = {\n fill: (_e = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getFill()) !== null && _e !== void 0 ? _e : undefined,\n image: (_f = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getImage()) !== null && _f !== void 0 ? _f : undefined,\n stroke: (_g = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getStroke()) !== null && _g !== void 0 ? _g : undefined,\n text: (_h = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getText()) !== null && _h !== void 0 ? _h : undefined,\n zIndex: (_j = mainStyle === null || mainStyle === void 0 ? void 0 : mainStyle.getZIndex()) !== null && _j !== void 0 ? _j : undefined,\n };\n if (newStyle.zIndex) {\n clone.set('zIndex', newStyle.zIndex);\n }\n const text = (_k = newStyle.text) === null || _k === void 0 ? void 0 : _k.getText();\n if (text) {\n let kmlText = '';\n if (Array.isArray(text)) {\n // text can be a string or an array of strings\n clone.set('textArray', JSON.stringify(text));\n const textArray = text;\n // in the KML we just add the text without the bold or italic information\n kmlText = textArray\n .map((t, idx) => {\n return idx % 2 === 0 ? t : '';\n })\n .join('')\n .replace(/\\u200B/g, '');\n }\n // We add the current text as features's name so it will be added as Placemark's name in the kml\n if (kmlText) {\n // If we see spaces at the beginning or at the end we add a empty\n // white space at the beginning and at the end.\n if (/^(\\s|\\n)|(\\n|\\s)$/g.test(kmlText)) {\n clone.set('name', `\\u200B${kmlText}\\u200B`);\n }\n else {\n clone.set('name', kmlText);\n }\n }\n }\n // Set custom properties to be converted in extendedData in KML.\n if ((_l = newStyle.text) === null || _l === void 0 ? void 0 : _l.getRotation()) {\n clone.set('textRotation', newStyle.text.getRotation());\n }\n if ((_m = newStyle.text) === null || _m === void 0 ? void 0 : _m.getFont()) {\n clone.set('textFont', newStyle.text.getFont());\n }\n if ((_o = newStyle.text) === null || _o === void 0 ? void 0 : _o.getTextAlign()) {\n clone.set('textAlign', newStyle.text.getTextAlign());\n }\n if ((_p = newStyle.text) === null || _p === void 0 ? void 0 : _p.getOffsetX()) {\n clone.set('textOffsetX', newStyle.text.getOffsetX());\n }\n if ((_q = newStyle.text) === null || _q === void 0 ? void 0 : _q.getOffsetY()) {\n clone.set('textOffsetY', newStyle.text.getOffsetY());\n }\n if ((_r = newStyle.text) === null || _r === void 0 ? void 0 : _r.getStroke()) {\n if ((_s = newStyle.text.getStroke()) === null || _s === void 0 ? void 0 : _s.getColor()) {\n clone.set('textStrokeColor', asString((_t = newStyle.text.getStroke()) === null || _t === void 0 ? void 0 : _t.getColor()));\n }\n if ((_u = newStyle.text.getStroke()) === null || _u === void 0 ? void 0 : _u.getWidth()) {\n clone.set('textStrokeWidth', (_v = newStyle.text.getStroke()) === null || _v === void 0 ? void 0 : _v.getWidth());\n }\n }\n if ((_w = newStyle.text) === null || _w === void 0 ? void 0 : _w.getBackgroundFill()) {\n clone.set('textBackgroundFillColor', asString((_x = newStyle.text.getBackgroundFill()) === null || _x === void 0 ? void 0 : _x.getColor()));\n }\n if ((_y = newStyle.text) === null || _y === void 0 ? void 0 : _y.getPadding()) {\n clone.set('textPadding', (_z = newStyle.text.getPadding()) === null || _z === void 0 ? void 0 : _z.join());\n }\n if ((_0 = newStyle.stroke) === null || _0 === void 0 ? void 0 : _0.getLineCap()) {\n clone.set('lineCap', newStyle.stroke.getLineCap());\n }\n if ((_1 = newStyle.stroke) === null || _1 === void 0 ? void 0 : _1.getLineJoin()) {\n clone.set('lineJoin', newStyle.stroke.getLineJoin());\n }\n if ((_2 = newStyle.stroke) === null || _2 === void 0 ? void 0 : _2.getLineDash()) {\n clone.set('lineDash', (_3 = newStyle.stroke.getLineDash()) === null || _3 === void 0 ? void 0 : _3.join(','));\n }\n if ((_4 = newStyle.stroke) === null || _4 === void 0 ? void 0 : _4.getLineDashOffset()) {\n clone.set('lineDashOffset', newStyle.stroke.getLineDashOffset());\n }\n if ((_5 = newStyle.stroke) === null || _5 === void 0 ? void 0 : _5.getMiterLimit()) {\n clone.set('miterLimit', newStyle.stroke.getMiterLimit());\n }\n if (newStyle.image instanceof Circle) {\n newStyle.image = undefined;\n }\n if (newStyle.image) {\n const imgSource = newStyle.image.getSrc();\n if (!/(http(s?)):\\/\\//gi.test(imgSource)) {\n // eslint-disable-next-line no-console\n console.log('Local image source not supported for KML export.' +\n 'Should use remote web server');\n }\n if (newStyle.image.getRotation()) {\n // We set the icon rotation as extended data\n clone.set('iconRotation', newStyle.image.getRotation());\n }\n if (newStyle.image.getScale()) {\n // We set the scale as extended metadata because the in the KML is related to a 32px img, since ol >= 6.10.\n clone.set('iconScale', newStyle.image.getScale());\n }\n // Set map resolution to use for icon-to-map proportional scaling\n if (feature.get('pictureOptions')) {\n clone.set('pictureOptions', JSON.stringify(feature.get('pictureOptions')));\n }\n }\n // In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc)\n if (feature.get('fillPattern')) {\n clone.set('fillPattern', JSON.stringify(feature.get('fillPattern')));\n newStyle.fill = undefined;\n }\n // maxZoom: maximum zoom level at which the feature is displayed\n const maxZoom = parseFloat(feature.get('maxZoom'));\n if (!Number.isNaN(maxZoom)) {\n clone.set('maxZoom', maxZoom);\n }\n // minZoom: minimum zoom level at which the feature is displayed\n const minZoom = parseFloat(feature.get('minZoom'));\n if (!Number.isNaN(minZoom)) {\n clone.set('minZoom', minZoom);\n }\n // If only text is displayed we must specify an\n // image style with scale=0\n if (newStyle.text && !newStyle.image) {\n newStyle.image = new Icon({\n scale: 0,\n src: 'noimage',\n });\n }\n // In case we use line's icon .\n const extraLineStyles = (Array.isArray(styles) && styles.slice(1)) || [];\n extraLineStyles.forEach((extraLineStyle) => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n if (extraLineStyle &&\n extraLineStyle.getImage() instanceof Icon &&\n extraLineStyle.getGeometry()) {\n const coord = (_b = (_a = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getGeometry()) === null || _a === void 0 ? void 0 : _a(feature)) === null || _b === void 0 ? void 0 : _b.getCoordinates();\n const startCoord = (_c = feature.getGeometry()) === null || _c === void 0 ? void 0 : _c.getFirstCoordinate();\n if ((coord === null || coord === void 0 ? void 0 : coord[0]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[0]) &&\n (coord === null || coord === void 0 ? void 0 : coord[1]) === (startCoord === null || startCoord === void 0 ? void 0 : startCoord[1])) {\n clone.set('lineStartIcon', JSON.stringify({\n scale: (_d = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _d === void 0 ? void 0 : _d.getScale(),\n size: (_e = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _e === void 0 ? void 0 : _e.getSize(),\n url: (_f = extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getImage()) === null || _f === void 0 ? void 0 : _f.getSrc(),\n zIndex: extraLineStyle === null || extraLineStyle === void 0 ? void 0 : extraLineStyle.getZIndex(),\n }));\n }\n else {\n clone.set('lineEndIcon', JSON.stringify({\n scale: (_g = extraLineStyle.getImage()) === null || _g === void 0 ? void 0 : _g.getScale(),\n size: (_h = extraLineStyle.getImage()) === null || _h === void 0 ? void 0 : _h.getSize(),\n url: (_j = extraLineStyle.getImage()) === null || _j === void 0 ? void 0 : _j.getSrc(),\n zIndex: extraLineStyle.getZIndex(),\n }));\n }\n }\n });\n const olStyle = new Style(newStyle);\n clone.setStyle(olStyle);\n if (!(clone.getGeometry() instanceof Point &&\n olStyle.getText() &&\n !((_6 = olStyle.getText()) === null || _6 === void 0 ? void 0 : _6.getText()))) {\n exportFeatures.push(clone);\n }\n });\n if (exportFeatures.length > 0) {\n if (exportFeatures.length === 1) {\n // force the add of a node\n exportFeatures.push(new Feature());\n }\n featString = new KML({\n defaultStyle: [kmlStyle],\n extractStyles: true,\n }).writeFeatures(exportFeatures);\n // Remove no image hack\n featString = featString.replace(/\\s*noimage<\\/href>\\s*<\\/Icon>/g, '');\n // Remove empty placemark added to have\n // tag\n featString = featString.replace(//g, '');\n // Add KML document name\n if (layer.get('name')) {\n featString = featString.replace(//, `${layer.get('name')}`);\n }\n }\n return featString;\n }\n}\nexport default MapsetKmlFormat;\n", "static": true, "longname": "/home/olivier/GIT/mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "access": "private", @@ -17829,7 +17850,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 14, + "lineNumber": 13, "undocument": true, "type": { "types": [ @@ -17850,7 +17871,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 15, + "lineNumber": 14, "undocument": true, "type": { "types": [ @@ -17871,7 +17892,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 16, + "lineNumber": 15, "undocument": true, "type": { "types": [ @@ -17892,7 +17913,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 18, + "lineNumber": 17, "undocument": true, "type": { "types": [ @@ -17913,7 +17934,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 21, + "lineNumber": 20, "undocument": true, "type": { "types": [ @@ -17934,7 +17955,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 25, + "lineNumber": 24, "undocument": true, "type": { "types": [ @@ -17955,7 +17976,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 30, + "lineNumber": 29, "undocument": true, "type": { "types": [ @@ -17978,7 +17999,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 45, + "lineNumber": 44, "undocument": true, "params": [ { @@ -18009,7 +18030,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 48, + "lineNumber": 47, "undocument": true, "params": [ { @@ -18042,7 +18063,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 63, + "lineNumber": 62, "undocument": true, "params": [ { @@ -18091,7 +18112,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": null, "description": null, - "lineNumber": 71, + "lineNumber": 70, "undocument": true, "params": [ { @@ -18141,7 +18162,7 @@ "importPath": "mobility-toolbox-js/build/ol/utils/MapsetKmlFormat.js", "importStyle": "MapsetKmlFormat", "description": null, - "lineNumber": 97, + "lineNumber": 96, "undocument": true, "interface": false }, @@ -18156,7 +18177,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#constructor", "access": "private", "description": null, - "lineNumber": 98, + "lineNumber": 97, "undocument": true }, { @@ -18168,7 +18189,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#writeDocumentCamera", "access": "private", "description": "Write the tag into a KML string. Returns the KML string with added tag.", - "lineNumber": 105, + "lineNumber": 104, "params": [ { "nullable": null, @@ -18208,7 +18229,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#readFeatures", "access": "private", "description": "Read a KML string.", - "lineNumber": 127, + "lineNumber": 129, "params": [ { "nullable": null, @@ -18223,22 +18244,46 @@ { "nullable": null, "types": [ - "" + "Object" ], "spread": false, "optional": false, - "name": "featureProjection", - "description": "The projection used by the map." + "name": "formatOptions", + "description": "used to read and writes features. It extends the ol KML format read options with some custom options." }, { "nullable": null, "types": [ - "" + "boolean" ], "spread": false, - "optional": false, - "name": "doNotRevert32pxScaling", + "optional": true, + "defaultValue": "true", + "defaultRaw": true, + "name": "formatOptions.applyMinMaxZoom", + "description": "Generate a style function to apply the minZoom and maxZoom properties of features if they are defined and if the getResolutionForZoom function is provided in options. The style function will return undefined for features that are out of the zoom range defined by minZoom and maxZoom, so they will not be displayed on the map." + }, + { + "nullable": null, + "types": [ + "boolean" + ], + "spread": false, + "optional": true, + "defaultValue": "false", + "defaultRaw": false, + "name": "formatOptions.doNotRevert32pxScaling", "description": "Set it to true if you use ol < 6.7 and last version of react-spatial, Fix the 32px scaling, introduced by (ol >= 6.7), see https://github.com/openlayers/openlayers/pull/12695." + }, + { + "nullable": null, + "types": [ + "function" + ], + "spread": false, + "optional": true, + "name": "formatOptions.getResolutionForZoom", + "description": "A function to get the resolution for a given zoom level. Mandatory if applyMinMaxZoom is true. It can be the map.getView().getResolutionForZoom function." } ], "return": { @@ -18258,7 +18303,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#removeDocumentCamera", "access": "private", "description": "Removes the tag from a KML string. Returns the KML string with removed tag.", - "lineNumber": 153, + "lineNumber": 154, "params": [ { "nullable": null, @@ -18288,7 +18333,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#sanitizeFeature", "access": "private", "description": null, - "lineNumber": 162, + "lineNumber": 163, "undocument": true, "params": [ { @@ -18298,13 +18343,10 @@ ] }, { - "name": "doNotRevert32pxScaling", - "optional": true, + "name": "formatOptions", "types": [ - "boolean" - ], - "defaultRaw": false, - "defaultValue": "false" + "*" + ] } ], "return": null @@ -18320,7 +18362,7 @@ "longname": "build/ol/utils/MapsetKmlFormat.js~MapsetKmlFormat#writeFeatures", "access": "private", "description": "Create a KML string.", - "lineNumber": 396, + "lineNumber": 421, "params": [ { "nullable": null, @@ -19039,7 +19081,7 @@ }, { "kind": "packageJSON", - "content": "{\n \"name\": \"mobility-toolbox-js\",\n \"license\": \"MIT\",\n \"description\": \"Toolbox for JavaScript applications in the domains of mobility and logistics.\",\n \"version\": \"3.6.7\",\n \"homepage\": \"https://mobility-toolbox-js.geops.io/\",\n \"exports\": {\n \".\": \"./index.js\",\n \"./api\": \"./api/index.js\",\n \"./maplibre\": \"./maplibre/index.js\",\n \"./ol\": \"./ol/index.js\",\n \"./types\": \"./types/index.d.ts\"\n },\n \"dependencies\": {\n \"@geoblocks/ol-maplibre-layer\": \"^1.0.3\",\n \"@turf/helpers\": \"7.3.2\",\n \"@turf/transform-rotate\": \"7.3.2\",\n \"lodash.debounce\": \"4.0.8\",\n \"lodash.throttle\": \"4.1.1\",\n \"uuid\": \"13.0.0\"\n },\n \"peerDependencies\": {\n \"maplibre-gl\": \">=4\",\n \"ol\": \">=9\"\n },\n \"devDependencies\": {\n \"@babel/preset-env\": \"^7.28.6\",\n \"@babel/preset-typescript\": \"^7.28.5\",\n \"@commitlint/cli\": \"20.3.1\",\n \"@commitlint/config-conventional\": \"20.3.1\",\n \"@geops/eslint-config-react\": \"1.6.0-beta.1\",\n \"@graphql-codegen/cli\": \"^6.1.1\",\n \"@graphql-codegen/typescript\": \"^5.0.7\",\n \"@graphql-codegen/typescript-operations\": \"^5.0.7\",\n \"@types/geojson\": \"7946.0.16\",\n \"@types/lodash\": \"^4.17.23\",\n \"@types/lodash.debounce\": \"4.0.9\",\n \"@types/lodash.throttle\": \"4.1.9\",\n \"@types/mapbox-gl\": \"3.4.1\",\n \"@types/offscreencanvas\": \"2019.7.3\",\n \"@types/topojson\": \"3.2.6\",\n \"@types/uuid\": \"11.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"8.53.1\",\n \"@typescript-eslint/parser\": \"8.53.1\",\n \"cypress\": \"15.8.1\",\n \"esbuild\": \"0.27.2\",\n \"esdoc\": \"1.1.0\",\n \"esdoc-ecmascript-proposal-plugin\": \"1.0.0\",\n \"esdoc-publish-html-plugin\": \"1.1.2\",\n \"esdoc-standard-plugin\": \"1.0.0\",\n \"esdoc-typescript-plugin\": \"1.0.1\",\n \"eslint\": \"9.39.2\",\n \"fixpack\": \"4.0.0\",\n \"graphql\": \"^16.12.0\",\n \"husky\": \"9.1.7\",\n \"is-ci\": \"4.1.0\",\n \"jest\": \"30.2.0\",\n \"jest-canvas-mock\": \"2.5.2\",\n \"jest-environment-jsdom\": \"30.2.0\",\n \"jest-fetch-mock\": \"3.0.3\",\n \"jest-serializer-html\": \"7.1.0\",\n \"jest-transformer-svg\": \"2.1.0\",\n \"jest-websocket-mock\": \"2.5.0\",\n \"lint-staged\": \"16.2.7\",\n \"maplibre-gl\": \"5.16.0\",\n \"mock-socket\": \"9.3.1\",\n \"next\": \"15.5.6\",\n \"next-transpile-modules\": \"10.0.1\",\n \"ol\": \"10.7.0\",\n \"openapi-typescript\": \"5\",\n \"prettier\": \"3.8.1\",\n \"raw-loader\": \"4.0.2\",\n \"sort-json\": \"2.0.1\",\n \"standard-version\": \"9.5.0\",\n \"start-server-and-test\": \"2.1.3\",\n \"stylelint\": \"17.0.0\",\n \"stylelint-config-recommended-scss\": \"17.0.0\",\n \"stylelint-config-standard\": \"40.0.0\",\n \"stylelint-scss\": \"7.0.0\",\n \"ts-jest\": \"^29.4.6\",\n \"typescript\": \"5.9.3\",\n \"vite\": \"^7.3.1\"\n },\n \"scripts\": {\n \"apidoc\": \"esdoc && cp apidoc/index.json doc/src/components/Esdoc\",\n \"build\": \"yarn build:tsc && yarn esbuild:iife\",\n \"build:tsc\": \"rm -rf build && yarn tsc && cp package.json build/ && cp README.md build/ && cp LICENSE build/ && cp -R src/types build/ && find build -type f -name '*.test.*' -delete\",\n \"clean\": \"rm -rf .next && rm -rf doc/.next\",\n \"coverage\": \"yarn test --watchAll=false --coverage --coverageDirectory=coverage\",\n \"cy:open\": \"cypress open\",\n \"cy:test\": \"start-server-and-test dev http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:chrome\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:edge\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser edge'\",\n \"cy:test:firefox\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser firefox'\",\n \"dev\": \"vite\",\n \"doc\": \"yarn build && yarn apidoc && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn build\",\n \"doc:dev\": \"yarn clean && yarn build && yarn apidoc && yarn doc:dev:examples\",\n \"doc:dev:examples\": \"yarn clean && yarn build && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn dev\",\n \"esbuild\": \"yarn esbuild:all && yarn esbuild:iife\",\n \"esbuild:all\": \"esbuild src/index.js src/**/*.js src/**/*.ts src/**/**/*.js src/**/**/*.ts --target=chrome100 --outdir=build/ --loader:.js=jsx\",\n \"esbuild:iife\": \"yarn esbuild:iife:unminify && yarn esbuild:iife:minify\",\n \"esbuild:iife:base\": \"esbuild src/iife.js --bundle --sourcemap --target=chrome100\",\n \"esbuild:iife:minify\": \"yarn esbuild:iife:base --minify --outfile=build/mbt.min.js\",\n \"esbuild:iife:unminify\": \"yarn esbuild:iife:base --outfile=build/mbt.js\",\n \"format\": \"prettier --write 'src/**/*.js' 'src/**/*.ts' 'src/**/*.test.js' && eslint src/**/*.js src/**/*.test.js src/**/*.ts --fix && stylelint 'src/**/*.css' 'src/**/*.scss' --fix --allow-empty-input\",\n \"lint\": \"eslint src/**/*.js src/**/*.ts && stylelint src/**/*.css src/**/*.scss --allow-empty-input\",\n \"publish:beta\": \"HUSKY=0 yarn release -- --prerelease beta --skip.changelog && yarn run build && cd build && HUSKY=0 yarn publish --tag beta && git push origin HEAD && git push --tags \",\n \"publish:beta:dryrun\": \"yarn release -- --prerelease beta --dry-run --skip.changelog\",\n \"publish:public\": \"yarn release && yarn run build && cd build && HUSKY=0 yarn publish && git push origin HEAD && git push --tags \",\n \"publish:public:dryrun\": \"yarn release --dry-run\",\n \"release\": \"standard-version\",\n \"start\": \"yarn doc && cd doc && yarn start\",\n \"start:examples\": \"cd doc && yarn build && yarn start\",\n \"test\": \"TZ='UTC' jest \",\n \"test:watch\": \"yarn test --watchAll\",\n \"tsc\": \"tsc\",\n \"types:backend\": \" yarn types:stops && yarn types:routing && yarn types:moco && yarn types:realtime && yarn format\",\n \"types:moco\": \"openapi-typescript https://moco.geops.io/api/schema/?format=json --output src/types/moco.d.ts && graphql-codegen --config graphql-codegen-moco.ts\",\n \"types:realtime\": \"openapi-typescript https://tralis-tracker-api.geops.io/api/openapi.json --output src/types/realtimerest.d.ts\",\n \"types:routing\": \"openapi-typescript https://developer.geops.io/swagger/routing.json --output src/types/routing.d.ts\",\n \"types:stops\": \"openapi-typescript https://developer.geops.io/swagger/stops.json --output src/types/stops.d.ts\",\n \"up\": \"yarn upgrade-interactive --latest\"\n },\n \"browserslist\": [\n \">0.2%\",\n \"not dead\",\n \"not op_mini all\",\n \"not ie <= 11\",\n \"not android < 5\"\n ],\n \"keywords\": [\n \"mobility\",\n \"realtime\",\n \"routing\",\n \"stops\",\n \"toolbox\"\n ],\n \"packageManager\": \"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/geops/mobility-toolbox-js\"\n },\n \"sideEffects\": false\n}\n", + "content": "{\n \"name\": \"mobility-toolbox-js\",\n \"license\": \"MIT\",\n \"description\": \"Toolbox for JavaScript applications in the domains of mobility and logistics.\",\n \"version\": \"3.6.11\",\n \"homepage\": \"https://mobility-toolbox-js.geops.io/\",\n \"exports\": {\n \".\": \"./index.js\",\n \"./api\": \"./api/index.js\",\n \"./maplibre\": \"./maplibre/index.js\",\n \"./ol\": \"./ol/index.js\",\n \"./types\": \"./types/index.d.ts\"\n },\n \"dependencies\": {\n \"@geoblocks/ol-maplibre-layer\": \"^1.0.3\",\n \"@turf/helpers\": \"7.3.2\",\n \"@turf/transform-rotate\": \"7.3.2\",\n \"lodash.debounce\": \"4.0.8\",\n \"lodash.throttle\": \"4.1.1\",\n \"uuid\": \"13.0.0\"\n },\n \"peerDependencies\": {\n \"maplibre-gl\": \">=4\",\n \"ol\": \">=9\"\n },\n \"devDependencies\": {\n \"@babel/preset-env\": \"^7.28.6\",\n \"@babel/preset-typescript\": \"^7.28.5\",\n \"@commitlint/cli\": \"20.3.1\",\n \"@commitlint/config-conventional\": \"20.3.1\",\n \"@geops/eslint-config-react\": \"1.6.0-beta.1\",\n \"@graphql-codegen/cli\": \"^6.1.1\",\n \"@graphql-codegen/typescript\": \"^5.0.7\",\n \"@graphql-codegen/typescript-operations\": \"^5.0.7\",\n \"@types/geojson\": \"7946.0.16\",\n \"@types/lodash\": \"^4.17.23\",\n \"@types/lodash.debounce\": \"4.0.9\",\n \"@types/lodash.throttle\": \"4.1.9\",\n \"@types/mapbox-gl\": \"3.4.1\",\n \"@types/offscreencanvas\": \"2019.7.3\",\n \"@types/topojson\": \"3.2.6\",\n \"@types/uuid\": \"11.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"8.53.1\",\n \"@typescript-eslint/parser\": \"8.53.1\",\n \"cypress\": \"15.8.1\",\n \"esbuild\": \"0.27.2\",\n \"esdoc\": \"1.1.0\",\n \"esdoc-ecmascript-proposal-plugin\": \"1.0.0\",\n \"esdoc-publish-html-plugin\": \"1.1.2\",\n \"esdoc-standard-plugin\": \"1.0.0\",\n \"esdoc-typescript-plugin\": \"1.0.1\",\n \"eslint\": \"9.39.2\",\n \"fixpack\": \"4.0.0\",\n \"graphql\": \"^16.12.0\",\n \"husky\": \"9.1.7\",\n \"is-ci\": \"4.1.0\",\n \"jest\": \"30.2.0\",\n \"jest-canvas-mock\": \"2.5.2\",\n \"jest-environment-jsdom\": \"30.2.0\",\n \"jest-fetch-mock\": \"3.0.3\",\n \"jest-serializer-html\": \"7.1.0\",\n \"jest-transformer-svg\": \"2.1.0\",\n \"jest-websocket-mock\": \"2.5.0\",\n \"lint-staged\": \"16.2.7\",\n \"maplibre-gl\": \"5.16.0\",\n \"mock-socket\": \"9.3.1\",\n \"next\": \"15.5.6\",\n \"next-transpile-modules\": \"10.0.1\",\n \"ol\": \"10.7.0\",\n \"openapi-typescript\": \"5\",\n \"prettier\": \"3.8.1\",\n \"raw-loader\": \"4.0.2\",\n \"sort-json\": \"2.0.1\",\n \"standard-version\": \"9.5.0\",\n \"start-server-and-test\": \"2.1.3\",\n \"stylelint\": \"17.0.0\",\n \"stylelint-config-recommended-scss\": \"17.0.0\",\n \"stylelint-config-standard\": \"40.0.0\",\n \"stylelint-scss\": \"7.0.0\",\n \"ts-jest\": \"^29.4.6\",\n \"typescript\": \"5.9.3\",\n \"vite\": \"^7.3.1\"\n },\n \"scripts\": {\n \"apidoc\": \"esdoc && cp apidoc/index.json doc/src/components/Esdoc\",\n \"build\": \"yarn build:tsc && yarn esbuild:iife\",\n \"build:tsc\": \"rm -rf build && yarn tsc && cp package.json build/ && cp README.md build/ && cp LICENSE build/ && cp -R src/types build/ && find build -type f -name '*.test.*' -delete\",\n \"clean\": \"rm -rf .next && rm -rf doc/.next\",\n \"coverage\": \"yarn test --watchAll=false --coverage --coverageDirectory=coverage\",\n \"cy:open\": \"cypress open\",\n \"cy:test\": \"start-server-and-test dev http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:chrome\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser chrome'\",\n \"cy:test:edge\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser edge'\",\n \"cy:test:firefox\": \"yarn build && start-server-and-test start http://localhost:3000 'cypress run --browser firefox'\",\n \"dev\": \"vite\",\n \"doc\": \"yarn build && yarn apidoc && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn build\",\n \"doc:dev\": \"yarn clean && yarn build && yarn apidoc && yarn doc:dev:examples\",\n \"doc:dev:examples\": \"yarn clean && yarn build && cd doc && rm -rf node_modules/mobility-toolbox-js && yarn install --force && yarn dev\",\n \"esbuild\": \"yarn esbuild:all && yarn esbuild:iife\",\n \"esbuild:all\": \"esbuild src/index.js src/**/*.js src/**/*.ts src/**/**/*.js src/**/**/*.ts --target=chrome100 --outdir=build/ --loader:.js=jsx\",\n \"esbuild:iife\": \"yarn esbuild:iife:unminify && yarn esbuild:iife:minify\",\n \"esbuild:iife:base\": \"esbuild src/iife.js --bundle --sourcemap --target=chrome100\",\n \"esbuild:iife:minify\": \"yarn esbuild:iife:base --minify --outfile=build/mbt.min.js\",\n \"esbuild:iife:unminify\": \"yarn esbuild:iife:base --outfile=build/mbt.js\",\n \"format\": \"prettier --write 'src/**/*.js' 'src/**/*.ts' 'src/**/*.test.js' && eslint src/**/*.js src/**/*.test.js src/**/*.ts --fix && stylelint 'src/**/*.css' 'src/**/*.scss' --fix --allow-empty-input\",\n \"lint\": \"eslint src/**/*.js src/**/*.ts && stylelint src/**/*.css src/**/*.scss --allow-empty-input\",\n \"publish:beta\": \"HUSKY=0 yarn release -- --prerelease beta --skip.changelog && yarn run build && cd build && HUSKY=0 yarn publish --tag beta && git push origin HEAD && git push --tags \",\n \"publish:beta:dryrun\": \"yarn release -- --prerelease beta --dry-run --skip.changelog\",\n \"publish:public\": \"yarn release && yarn run build && cd build && HUSKY=0 yarn publish && git push origin HEAD && git push --tags \",\n \"publish:public:dryrun\": \"yarn release --dry-run\",\n \"release\": \"standard-version\",\n \"start\": \"yarn doc && cd doc && yarn start\",\n \"start:examples\": \"cd doc && yarn build && yarn start\",\n \"test\": \"TZ='UTC' jest \",\n \"test:watch\": \"yarn test --watchAll\",\n \"tsc\": \"tsc\",\n \"types:backend\": \" yarn types:stops && yarn types:routing && yarn types:moco && yarn types:realtime && yarn format\",\n \"types:moco\": \"openapi-typescript https://moco.geops.io/api/schema/?format=json --output src/types/moco.d.ts && graphql-codegen --config graphql-codegen-moco.ts\",\n \"types:realtime\": \"openapi-typescript https://tralis-tracker-api.geops.io/api/openapi.json --output src/types/realtimerest.d.ts\",\n \"types:routing\": \"openapi-typescript https://developer.geops.io/swagger/routing.json --output src/types/routing.d.ts\",\n \"types:stops\": \"openapi-typescript https://developer.geops.io/swagger/stops.json --output src/types/stops.d.ts\",\n \"up\": \"yarn upgrade-interactive --latest\"\n },\n \"browserslist\": [\n \">0.2%\",\n \"not dead\",\n \"not op_mini all\",\n \"not ie <= 11\",\n \"not android < 5\"\n ],\n \"keywords\": [\n \"mobility\",\n \"realtime\",\n \"routing\",\n \"stops\",\n \"toolbox\"\n ],\n \"packageManager\": \"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/geops/mobility-toolbox-js\"\n },\n \"sideEffects\": false\n}\n", "longname": "/home/olivier/GIT/mobility-toolbox-js/package.json", "name": "package.json", "static": true, diff --git a/doc/yarn.lock b/doc/yarn.lock index 7ee9e8fe..c1c3dbae 100644 --- a/doc/yarn.lock +++ b/doc/yarn.lock @@ -4401,7 +4401,7 @@ mkdirp@^0.5.1: minimist "^1.2.6" mobility-toolbox-js@./../build: - version "3.6.7" + version "3.6.11" dependencies: "@geoblocks/ol-maplibre-layer" "^1.0.3" "@turf/helpers" "7.3.2" diff --git a/src/common/styles/realtimeStyle.ts b/src/common/styles/realtimeStyle.ts index e87617a0..2368eaa0 100644 --- a/src/common/styles/realtimeStyle.ts +++ b/src/common/styles/realtimeStyle.ts @@ -50,7 +50,8 @@ const realtimeStyle: RealtimeStyleFunction = ( getTextColor, getTextFont, getTextSize, - hoverVehicleId, + // hoverVehicleId, + hoverVehicleIds, selectedVehicleId, showDelayBg, showDelayText, @@ -72,7 +73,7 @@ const realtimeStyle: RealtimeStyleFunction = ( let color = getColor(trajectory, viewState); let textColor = getTextColor(trajectory, viewState); const cancelled = state === 'JOURNEY_CANCELLED'; - const hover = !!(hoverVehicleId && hoverVehicleId === id); + const hover = hoverVehicleIds?.includes(id); const selected = !!(selectedVehicleId && selectedVehicleId === id); // Get the text color of the vehicle @@ -91,10 +92,25 @@ const realtimeStyle: RealtimeStyleFunction = ( ? radius + 5 * pixelRatio : 14 * pixelRatio; } + + if (radius === 0) { + return null; + } + + // Calcul if the text should be diplayed or not const isDisplayText = radius > getMaxRadiusForText() * pixelRatio; + const hasDelayText = + showDelayText && + isDisplayStrokeAndDelay && + ((hover ?? (delay || 0) >= delayDisplay) || cancelled); + + const hasDelayBg = showDelayBg && isDisplayStrokeAndDelay && delay !== null; + + const hasHeading = showHeading && isDisplayText && rotation; + // Optimize the cache key, very important in high zoom level - let key = `${radius}${hover || selected}${showHeading ? rotation : ''}`; + let key = `${radius}${hover ?? selected}${hasHeading ? rotation : ''}`; if (useDelayStyle) { key += `${operatorProvidesRealtime}${delay}${cancelled}`; @@ -106,35 +122,24 @@ const realtimeStyle: RealtimeStyleFunction = ( } } + key += `${showDelayText}${showDelayBg}`; + if (isDisplayText) { key += `${name}${textColor}`; } if (!cache[key]) { - if (radius === 0) { - return null; - } - // Get the color of the vehicle const circleFillColor = color; const hasStroke = isDisplayStrokeAndDelay || hover || selected; const hasDash = - !!isDisplayStrokeAndDelay && - !!useDelayStyle && + useDelayStyle && + isDisplayStrokeAndDelay && delay === null && operatorProvidesRealtime === 'yes'; - const hasDelayText = - showDelayText && - isDisplayStrokeAndDelay && - (hover || (delay || 0) >= delayDisplay || cancelled); - - const hasDelayBg = showDelayBg && isDisplayStrokeAndDelay && delay !== null; - - const hasHeading = showHeading && isDisplayText && rotation; - // Show delay if feature is hovered or if delay is above 5mins let fontSize = 0; let text = null; diff --git a/src/common/utils/RealtimeEngine.ts b/src/common/utils/RealtimeEngine.ts index 697e894e..babbf85b 100644 --- a/src/common/utils/RealtimeEngine.ts +++ b/src/common/utils/RealtimeEngine.ts @@ -32,7 +32,6 @@ import type { RealtimeTrajectory, ViewState, } from '../../types'; -import type { FilterFunction, SortFunction } from '../typedefs'; export interface RealtimeEngineOptions { api?: RealtimeAPI; @@ -45,7 +44,7 @@ export interface RealtimeEngineOptions { buffer?: number[]; canvas?: HTMLCanvasElement; debug?: boolean; - filter?: FilterFunction; + filter?: (item: RealtimeTrajectory) => boolean; generalizationLevelByZoom?: string[]; getGeneralizationLevelByZoom?: ( zoom: number, @@ -61,6 +60,7 @@ export interface RealtimeEngineOptions { getViewState?: () => ViewState; graphByZoom?: string[]; hoverVehicleId?: RealtimeTrainId; + hoverVehicleIds?: RealtimeTrainId[]; isUpdateBboxOnMoveEnd?: boolean; live?: boolean; minZoomInterpolation?: number; @@ -76,7 +76,7 @@ export interface RealtimeEngineOptions { renderTimeIntervalByZoom?: number[]; selectedVehicleId?: RealtimeTrainId; shouldRender?: () => boolean; - sort?: SortFunction; + sort?: (a: RealtimeTrajectory, b: RealtimeTrajectory) => number; speed?: number; style?: RealtimeStyleFunction; styleOptions?: Partial; @@ -181,7 +181,7 @@ class RealtimeEngine { noInterpolate?: boolean, ) => void; debug: boolean; - filter?: FilterFunction; + filter?: (item: RealtimeTrajectory) => boolean; format: GeoJSON; generalizationLevel?: string; generalizationLevelByZoom: string[]; @@ -191,6 +191,7 @@ class RealtimeEngine { getRenderTimeIntervalByZoom: (zoom: number) => number; graphByZoom: string[]; hoverVehicleId?: RealtimeTrainId; + hoverVehicleIds?: RealtimeTrainId[]; isIdle = false; isUpdateBboxOnMoveEnd: boolean; live?: boolean; @@ -207,7 +208,7 @@ class RealtimeEngine { requestId?: number; selectedVehicle!: RealtimeTrajectory; selectedVehicleId?: RealtimeTrainId; - sort?: SortFunction; + sort?: (a: RealtimeTrajectory, b: RealtimeTrajectory) => number; styleOptions: RealtimeStyleOptions; tenant: RealtimeTenant; throttleRenderTrajectories: ( @@ -404,12 +405,14 @@ class RealtimeEngine { // Define throttling and debounce render function this.throttleRenderTrajectories = throttle( + // eslint-disable-next-line @typescript-eslint/unbound-method this.renderTrajectoriesInternal, 50, { leading: false, trailing: true }, ); this.debounceRenderTrajectories = debounce( + // eslint-disable-next-line @typescript-eslint/unbound-method this.renderTrajectoriesInternal, 50, { leading: true, maxWait: 5000, trailing: true }, @@ -433,9 +436,7 @@ class RealtimeEngine { * @private */ addTrajectory(trajectory: RealtimeTrajectory) { - if (!this.trajectories) { - this.trajectories = {}; - } + this.trajectories ??= {}; const id = trajectory.properties.train_id; if (id !== undefined) { this.trajectories[id] = trajectory; @@ -448,6 +449,7 @@ class RealtimeEngine { // We stop the rendering and the websocket when hide and start again when show. document.addEventListener( 'visibilitychange', + // eslint-disable-next-line @typescript-eslint/unbound-method this.onDocumentVisibilityChange, ); } @@ -455,6 +457,7 @@ class RealtimeEngine { detachFromMap() { document.removeEventListener( 'visibilitychange', + // eslint-disable-next-line @typescript-eslint/unbound-method this.onDocumentVisibilityChange, ); @@ -488,12 +491,14 @@ class RealtimeEngine { // TODO: see if this should go elsewhere. if (this.useThrottle) { this.throttleRenderTrajectories = throttle( + // eslint-disable-next-line @typescript-eslint/unbound-method this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, trailing: true }, ); } else if (this.useDebounce) { this.debounceRenderTrajectories = debounce( + // eslint-disable-next-line @typescript-eslint/unbound-method this.renderTrajectoriesInternal, nextThrottleTick, { leading: true, maxWait: 5000, trailing: true }, @@ -511,10 +516,11 @@ class RealtimeEngine { * @param {function} filterFc A function use to filter results. * @return {Array} Array of vehicle. */ - getVehicles(filterFc: FilterFunction) { + getVehicles( + filterFc: (item: RealtimeTrajectory) => boolean, + ): RealtimeTrajectory[] { return ( (this.trajectories && - // @ts-expect-error good type must be defined Object.values(this.trajectories).filter(filterFc)) || [] ); @@ -542,7 +548,6 @@ class RealtimeEngine { let trajectories = Object.values(this.trajectories || {}); if (this.sort) { - // @ts-expect-error good type must be defined trajectories = trajectories.sort(this.sort); } @@ -777,7 +782,6 @@ class RealtimeEngine { // console.time('sort'); if (this.sort) { - // @ts-expect-error type problem trajectories.sort(this.sort); } // console.timeEnd('sort'); @@ -799,6 +803,7 @@ class RealtimeEngine { ...this.styleOptions, filter: this.filter, hoverVehicleId: this.hoverVehicleId, + hoverVehicleIds: this.hoverVehicleIds, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation ? true @@ -907,12 +912,14 @@ class RealtimeEngine { this.api.open(); this.api.subscribeTrajectory( this.mode, + // eslint-disable-next-line @typescript-eslint/unbound-method this.onTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd, ); this.api.subscribeDeletedVehicles( this.mode, + // eslint-disable-next-line @typescript-eslint/unbound-method this.onDeleteTrajectoryMessage, undefined, this.isUpdateBboxOnMoveEnd, @@ -948,7 +955,9 @@ class RealtimeEngine { } stop() { + // eslint-disable-next-line @typescript-eslint/unbound-method this.api.unsubscribeTrajectory(this.onTrajectoryMessage); + // eslint-disable-next-line @typescript-eslint/unbound-method this.api.unsubscribeDeletedVehicles(this.onDeleteTrajectoryMessage); this.api.close(); if (this.onStop) { diff --git a/src/common/utils/renderTrajectories.ts b/src/common/utils/renderTrajectories.ts index dc9ced85..063922b4 100644 --- a/src/common/utils/renderTrajectories.ts +++ b/src/common/utils/renderTrajectories.ts @@ -10,6 +10,7 @@ import type { RealtimeRenderState, RealtimeStyleFunction, RealtimeStyleOptions, + RealtimeTrainId, RealtimeTrajectory, ViewState, } from '../../types'; @@ -62,6 +63,7 @@ const renderTrajectories = ( : pixel; }, hoverVehicleId, + hoverVehicleIds, noInterpolate = false, selectedVehicleId, } = options; @@ -104,15 +106,16 @@ const renderTrajectories = ( let selectedVehicleImg; let selectedVehiclePx; const renderedTrajectories = []; - const cachePixel: Record = {}; - const cacheNbTrainAtPixel: Record = {}; - const cacheDistanceOffset: Record = {}; + const cacheStyle: Record = {}; + // const cachePixel: Record = {}; + // const cacheNbTrainAtPixel: Record = {}; + // const cacheDistanceOffset: Record = {}; for (let i = trajectories.length - 1; i >= 0; i -= 1) { const trajectory = trajectories[i]; + delete cacheStyle[trajectory.properties.train_id]; // Filter out trajectories - // eslint-disable-next-line @typescript-eslint/no-unsafe-call if (filter && !filter(trajectory)) { continue; } @@ -158,36 +161,40 @@ const renderTrajectories = ( if (!vehicleImg) { continue; } + cacheStyle[trajectory.properties.train_id] = vehicleImg; + + // if (resolution < 1) { + // const roundedPX = px.map((p) => { + // return Math.round(p / 40) * 40; + // }); + // const key = `${roundedPX.toString()}`; + // if (!cachePixel[key]) { + // cachePixel[key] = px; + // cacheNbTrainAtPixel[key] = 1; + // cacheDistanceOffset[key] = 40 * resolution; + // } else { + // // console.log( + // // 'Collision detected for train id', + // // id, + // // 'at pixel', + // // roundedPX, + // // ); + // // if (!hoverVehicleId) { + // px[0] += 40 * cacheNbTrainAtPixel[key]; + // // // } + // trajectories[i].properties.coordinate = [ + // coord[0] + cacheDistanceOffset[key], + // coord[1], + // ]; + // cacheNbTrainAtPixel[key]++; + // cacheDistanceOffset[key] += 40 * resolution; + // } + // } - if (resolution < 1) { - const roundedPX = px.map((p) => { - return Math.round(p / 5) * 5; - }); - const key = `${roundedPX.toString()}`; - if (!cachePixel[key]) { - cachePixel[key] = px; - cacheNbTrainAtPixel[key] = 1; - cacheDistanceOffset[key] = 40 * resolution; - } else { - // console.log( - // 'Collision detected for train id', - // id, - // 'at pixel', - // roundedPX, - // ); - // if (!hoverVehicleId) { - px[0] += 40 * cacheNbTrainAtPixel[key]; - // // } - trajectories[i].properties.coordinate = [ - coord[0] + cacheDistanceOffset[key], - coord[1], - ]; - cacheNbTrainAtPixel[key]++; - cacheDistanceOffset[key] += 40 * resolution; - } - } - - if (hoverVehicleId !== id && selectedVehicleId !== id) { + if ( + (hoverVehicleIds?.length ?? 0) <= 1 || + (!hoverVehicleIds?.includes(id) && selectedVehicleId !== id) + ) { // To optimize the performance we use integer as pixel coordinate // to avoid an additional work by the browser on zoom level < 12. // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead @@ -201,8 +208,8 @@ const renderTrajectories = ( if (hoverVehicleId && hoverVehicleId === id) { // Store the canvas to draw it at the end - hoverVehicleImg = vehicleImg; - hoverVehiclePx = px; + // hoverVehicleImg = vehicleImg; + // hoverVehiclePx = px; // console.log(resolution); } @@ -224,15 +231,22 @@ const renderTrajectories = ( } if (hoverVehicleImg && hoverVehiclePx) { - context?.drawImage( - hoverVehicleImg, - Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), - Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2), + console.log( + 'hoverVehicleId', + hoverVehicleId, + 'hoverVehicleIds', + hoverVehicleIds, ); + // context?.drawImage( + // hoverVehicleImg, + // Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), + // Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2), + // ); } return { // isReady: true, renderedTrajectories, + styleCacheByTrajectoryId: cacheStyle, }; }; diff --git a/src/ol/layers/RealtimeLayer.ts b/src/ol/layers/RealtimeLayer.ts index 29094bff..9e199333 100644 --- a/src/ol/layers/RealtimeLayer.ts +++ b/src/ol/layers/RealtimeLayer.ts @@ -32,7 +32,6 @@ import type Feature from 'ol/Feature'; import type { ObjectEvent } from 'ol/Object'; import type { State } from 'ol/View'; -import type { FilterFunction, SortFunction } from '../../common/typedefs'; import type { RealtimeEngineOptions } from '../../common/utils/RealtimeEngine'; import type { RealtimeAPI } from '../../maplibre'; import type { RealtimeStyleOptions } from '../../types'; @@ -76,7 +75,7 @@ export type RealtimeLayerOptions = { * @classproperty {boolean} allowRenderWhenAnimating - Allow rendering of the layer when the map is animating. * @public */ -class RealtimeLayer extends Layer { +class RealtimeLayer extends Layer { allowRenderWhenAnimating?: boolean = false; currentZoom?: number; engine: RealtimeEngine; @@ -98,11 +97,11 @@ class RealtimeLayer extends Layer { return this.engine.canvas; } - get filter(): FilterFunction | undefined { + get filter(): ((item: RealtimeTrajectory) => boolean) | undefined { return this.engine.filter; } - set filter(filter: FilterFunction) { + set filter(filter: (item: RealtimeTrajectory) => boolean) { this.engine.filter = filter; } @@ -114,6 +113,14 @@ class RealtimeLayer extends Layer { this.engine.hoverVehicleId = id; } + get hoverVehicleIds(): RealtimeTrainId[] | undefined { + return this.engine.hoverVehicleIds; + } + + set hoverVehicleIds(ids: RealtimeTrainId[]) { + this.engine.hoverVehicleIds = ids; + } + get mode() { return this.engine.mode; } @@ -134,11 +141,13 @@ class RealtimeLayer extends Layer { this.engine.selectedVehicleId = id; } - get sort(): SortFunction | undefined { + get sort(): + | ((a: RealtimeTrajectory, b: RealtimeTrajectory) => number) + | undefined { return this.engine.sort; } - set sort(sort: SortFunction) { + set sort(sort: (a: RealtimeTrajectory, b: RealtimeTrajectory) => number) { this.engine.sort = sort; } @@ -219,9 +228,9 @@ class RealtimeLayer extends Layer { updateWhileInteracting: true, }); - this.onZoomEndDebounced = debounce(this.onZoomEnd, 100); + this.onZoomEndDebounced = debounce(this.onZoomEnd.bind(this), 100); - this.onMoveEndDebounced = debounce(this.onMoveEnd, 100); + this.onMoveEndDebounced = debounce(this.onMoveEnd.bind(this), 100); } /** @@ -267,23 +276,29 @@ class RealtimeLayer extends Layer { this.onMoveEndDebounced(evt); }, ), - this.on('change:visible', (evt: ObjectEvent) => { - if (evt.target.getVisible()) { - this.engine.start(); - } else { - this.engine.stop(); - } - }), - this.on('propertychange', (evt: ObjectEvent) => { - // We apply every property change event related to visiblity to the vectorlayer - if ( - /(opacity|visible|zIndex|minResolution|maxResolution|minZoom|maxZoom)/.test( - evt.key, - ) - ) { - this.vectorLayer.set(evt.key, evt.target.get(evt.key)); - } - }), + this.on( + 'change:visible', + (evt: { target: RealtimeLayer } & Omit) => { + if (evt.target.getVisible()) { + this.engine.start(); + } else { + this.engine.stop(); + } + }, + ), + this.on( + 'propertychange', + (evt: { target: RealtimeLayer } & Omit) => { + // We apply every property change event related to visiblity to the vectorlayer + if ( + /(opacity|visible|zIndex|minResolution|maxResolution|minZoom|maxZoom)/.test( + evt.key, + ) + ) { + this.vectorLayer.set(evt.key, evt.target.get(evt.key)); + } + }, + ), ); } } @@ -301,7 +316,10 @@ class RealtimeLayer extends Layer { * @public */ clone(newOptions: RealtimeLayerOptions): RealtimeLayer { - return new RealtimeLayer({ ...this.get('options'), ...newOptions }); + return new RealtimeLayer({ + ...(this.get('options') as RealtimeLayerOptions), + ...newOptions, + }); } createRenderer() { @@ -370,7 +388,9 @@ class RealtimeLayer extends Layer { }; } - getVehicles(filterFunc: FilterFunction) { + getVehicles( + filterFunc: (item: RealtimeTrajectory) => boolean, + ): RealtimeTrajectory[] { return this.engine.getVehicles(filterFunc); } @@ -404,10 +424,13 @@ class RealtimeLayer extends Layer { } highlight(features: Feature | Feature[]) { - const feat = Array.isArray(features) ? features[0] : features; - const id: null | string | undefined = feat?.get('train_id') as string; - if (this.hoverVehicleId !== id) { - this.hoverVehicleId = id; + const feats = Array.isArray(features) ? features : [features]; + const ids = feats.map((f) => { + return f.get('train_id') as string; + }); + if (this.hoverVehicleIds?.join() !== ids.join()) { + this.hoverVehicleId = ids[0]; + this.hoverVehicleIds = ids; this.engine.renderTrajectories(true); } } @@ -456,7 +479,7 @@ class RealtimeLayer extends Layer { viewState: ViewState, ) { this.renderedViewState = { ...viewState } as State; - // @ts-expect-error - we are in the same class + // @ts-expect-error - we are in the same classs const { container } = this.getRenderer()!; if (container) { container.style.transform = ''; @@ -494,6 +517,7 @@ class RealtimeLayer extends Layer { select(features: Feature | Feature[]) { const feat = Array.isArray(features) ? features[0] : features; const id: null | string | undefined = feat?.get('train_id') as string; + console.log('selected id', id); if (this.selectedVehicleId !== id) { if (this.selectedVehicleId) { this.api.unsubscribeFullTrajectory(this.selectedVehicleId); diff --git a/src/types/common.d.ts b/src/types/common.d.ts index 038fd5f1..d7253357 100644 --- a/src/types/common.d.ts +++ b/src/types/common.d.ts @@ -32,7 +32,7 @@ export interface ViewState { export interface RealtimeStyleOptions { delayDisplay: number; delayOutlineColor: string; - filter?: FilterFunction; + filter?: (item: RealtimeTrajectory) => boolean; getArrowSize: ( trajectory?: RealtimeTrajectory, viewState?: ViewState, @@ -99,6 +99,7 @@ export interface RealtimeStyleOptions { font: string, ) => number; hoverVehicleId?: RealtimeTrainId; + hoverVehicleIds?: RealtimeTrainId[]; noInterpolate?: boolean; selectedVehicleId?: RealtimeTrainId; showDelayBg: boolean; @@ -119,6 +120,7 @@ export interface RealtimeRenderState { center?: Coordinate; renderedTrajectories?: RealtimeTrajectory[]; rotation?: number; + styleCacheByTrajectoryId?: Record; zoom?: number; } From acb8787319546475dbbc11466d905539ac9e5f67 Mon Sep 17 00:00:00 2001 From: Olivier Terral Date: Tue, 17 Mar 2026 12:34:18 +0100 Subject: [PATCH 6/6] fix: add highlight in example --- dev.js | 69 +++++--- doc/public/static/examples/ol-realtime.js | 184 ++++++++++++++++++++-- src/common/styles/realtimeStyle.ts | 29 ++-- src/common/utils/renderTrajectories.ts | 24 +-- 4 files changed, 242 insertions(+), 64 deletions(-) diff --git a/dev.js b/dev.js index 0d847b0d..c0c236b8 100644 --- a/dev.js +++ b/dev.js @@ -78,8 +78,10 @@ const getPointOnLine = (angleDeg, distance, originX = 0, originY = 0) => { const cacheFirtsAnchor = []; let cacheFirstRotation = 0; +let featuresHighlightedIds = []; const realtimeLayerHover = new VectorLayer({ source: new VectorSource(), + minZoom: 14, style: (feature) => { // const canvas = // realtimeLayer.engine.renderState?.styleCacheByTrajectoryId?.[ @@ -100,12 +102,10 @@ const realtimeLayerHover = new VectorLayer({ showDelayText: false, showDelayBg: true, hoverVehicleId: feature.get('train_id'), - hoverVehicleIds: [feature.get('train_id')], }, ); - const index = realtimeLayer.hoverVehicleIds?.indexOf( - feature.get('train_id'), - ); + const index = featuresHighlightedIds?.indexOf(feature.get('train_id')); + console.log('index', index, feature.get('train_id')); if (index === 0) { cacheFirstRotation = feature.get('rotation') || 0; } @@ -187,12 +187,10 @@ map.on('pointermove', (evt) => { hitTolerance: 15, layerFilter: (l) => l === realtimeLayer, }); - const featuresHovered = map - .getFeaturesAtPixel(pixel, { - hitTolerance: 15, - layerFilter: (l) => l === realtimeLayerHover, - }) - .filter((f) => realtimeLayer.selectedVehicleId !== f.get('train_id')); + + const featuresHovered = map.getFeaturesAtPixel(pixel, { + layerFilter: (l) => l === realtimeLayerHover, + }); console.log(features.map((f) => f.get('train_id'))); const featuresIds = features.map((f) => f.get('train_id')); @@ -200,15 +198,41 @@ map.on('pointermove', (evt) => { const noFeaturesHovered = !featuresHovered.length && !featuresHoveredIds.length; - if (features.length > featuresHovered.length || noFeaturesHovered) { - realtimeLayer.highlight(features); - realtimeLayerHover.getSource().clear(); + if ((map.getView().getZoom() || 0) >= realtimeLayerHover.getMinZoom()) { + realtimeLayer.filter = (feature) => { + return !featuresHighlightedIds?.includes(feature.properties.train_id); + }; + } else { + realtimeLayer.filter = null; + } + + console.log( + 'BEFORE features', + featuresHovered.length, + features.length, + featuresHighlightedIds.length, + ); + + if (!featuresHovered.length && !features.length) { + console.log('CLEAR features', featuresHovered.length, features.length); + realtimeLayerHover.getSource().clear(true); + featuresHighlightedIds = []; + } else if (features.length > 1 && !featuresHighlightedIds.length) { + console.log( + 'ADD features', + featuresHoveredIds, + featuresHovered.length, + features.length, + featuresIds, + ); realtimeLayerHover.getSource().addFeatures(features); - if (features.length) { - console.log(features.map((f) => f.getProperties())); - } - map.getTargetElement().style.cursor = features.length ? 'pointer' : ''; + featuresHighlightedIds = featuresIds; + } else if (!featuresHovered.length && features.length === 1) { + realtimeLayer.highlight(features[0]); } + + map.getTargetElement().style.cursor = + features.length || featuresHovered.length ? 'pointer' : ''; }); map.on('singleclick', (evt) => { @@ -217,17 +241,20 @@ map.on('singleclick', (evt) => { } const pixel = map.getEventPixel(evt.originalEvent); const [feature] = map.getFeaturesAtPixel(pixel, { - hitTolerance: 10, + hitTolerance: 15, layerFilter: (l) => l === realtimeLayer, }); const [featureHover] = map.getFeaturesAtPixel(pixel, { - hitTolerance: 30, + hitTolerance: 15, layerFilter: (l) => l === realtimeLayerHover, }); - realtimeLayerHover.getSource().clear(); - realtimeLayer.select([featureHover || feature]); + realtimeLayer.select(featureHover || feature); + realtimeLayerHover.getSource().clear(); + realtimeLayerHover.changed(); + realtimeLayer.filter = null; }); + map.on('moveend', () => { const zoom = map.getView().getZoom(); console.log('Current zoom level:', zoom); diff --git a/doc/public/static/examples/ol-realtime.js b/doc/public/static/examples/ol-realtime.js index bd0875a7..2cd90971 100644 --- a/doc/public/static/examples/ol-realtime.js +++ b/doc/public/static/examples/ol-realtime.js @@ -2,27 +2,131 @@ import { Map, View } from 'ol'; import { RealtimeLayer, MaplibreLayer } from 'mobility-toolbox-js/ol'; import 'ol/ol.css'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; +import Feature from 'ol/Feature'; +import LineString from 'ol/geom/LineString'; +import { toLonLat, transformExtent } from 'ol/proj'; +import { Icon, Style, Circle, Fill, Stroke } from 'ol/style'; +import { Point } from 'ol/geom'; +import { radiansToDegrees } from '@turf/helpers'; + export default () => { + const getPointOnLine = (angleDeg, distance, originX = 0, originY = 0) => { + // 1. Convert angle from degrees to radians + const angleRad = (angleDeg + 90) * (Math.PI / 180); + + // 2. Calculate the offset from the origin using Cosine (X) and Sine (Y) + const deltaX = Math.cos(angleRad) * distance; + const deltaY = Math.sin(angleRad) * distance; + + // 3. Add the offset to the origin coordinates + const x = originX + deltaX; + const y = originY - deltaY; + + return [ + Math.floor(x), // Rounded for better readability + Math.floor(y), + ]; + }; + // Creates the background layer const layer = new MaplibreLayer({ apiKey: window.apiKey, }); // Creates the Realtime layer - const realtime = new RealtimeLayer({ + const realtimeLayer = new RealtimeLayer({ apiKey: window.apiKey, styleOptions: { showHeading: true, }, + tenant: 'trenord', + }); + const cacheFirtsAnchor = []; + let cacheFirstRotation = 0; + let featuresHighlightedIds = []; + const realtimeLayerHover = new VectorLayer({ + source: new VectorSource(), + minZoom: 14, + style: (feature) => { + // const canvas = + // realtimeLayer.engine.renderState?.styleCacheByTrajectoryId?.[ + // feature.get('train_id') + // ]; + const canvas = realtimeLayer.style( + { + type: 'Feature', + properties: feature.getProperties(), + geometry: { + type: 'LineString', + coordinates: feature.getGeometry()?.getCoordinates() || [], + }, + }, + realtimeLayer.renderedViewState, + { + ...realtimeLayer.styleOptions, + showDelayText: false, + showDelayBg: true, + hoverVehicleId: feature.get('train_id'), + }, + ); + const index = featuresHighlightedIds?.indexOf(feature.get('train_id')); + console.log('index', index, feature.get('train_id')); + if (index === 0) { + cacheFirstRotation = feature.get('rotation') || 0; + } + + if (canvas) { + return new Style({ + image: new Icon({ + img: canvas, + imgSize: [canvas.width, canvas.height], + scale: 1, + anchor: getPointOnLine( + radiansToDegrees(cacheFirstRotation), + (index * canvas.height) / 2, + canvas.width / 2, + canvas.height / 2, + ), + anchorXUnits: 'pixels', + anchorYUnits: 'pixels', + }), + geometry: (feature) => { + const coords = feature.get('coordinate'); + if (coords) { + return new Point(coords); + } + return feature.getGeometry(); + }, + }); + } + return new Style({ + image: new Circle({ + radius: 50, + fill: new Fill({ color: 'rgba(255, 0, 0, 0.5)' }), + stroke: new Stroke({ color: 'red', width: 2 }), + }), + stroke: new Stroke({ color: 'blue', width: 20 }), + geometry: (feature) => { + const coords = feature.get('coordinate'); + if (coords) { + return new Point(coords); + } + return feature.getGeometry(); + }, + }); + }, }); // Creates the map const map = new Map({ target: 'map', - layers: [layer, realtime], + layers: [layer, realtimeLayer, realtimeLayerHover], view: new View({ - center: [831634, 5933959], - zoom: 13, + //center: [831634, 5933959], + center: [1022769, 5698188], + zoom: 14.5, minZoom: 5, }), }); @@ -35,20 +139,78 @@ export default () => { // Change mouse cursor and highlight vehicle if clickable map.on('pointermove', (evt) => { - const [feature] = map.getFeaturesAtPixel(evt.pixel, queryOptions); + const pixel = map.getEventPixel(evt.originalEvent); + const features = map.getFeaturesAtPixel(pixel, { + hitTolerance: 15, + layerFilter: (l) => l === realtimeLayer, + }); + + const featuresHovered = map.getFeaturesAtPixel(pixel, { + layerFilter: (l) => l === realtimeLayerHover, + }); + console.log(features.map((f) => f.get('train_id'))); + + const featuresIds = features.map((f) => f.get('train_id')); + const featuresHoveredIds = featuresHovered.map((f) => f.get('train_id')); + const noFeaturesHovered = + !featuresHovered.length && !featuresHoveredIds.length; + + if ((map.getView().getZoom() || 0) >= realtimeLayerHover.getMinZoom()) { + realtimeLayer.filter = (feature) => { + return !featuresHighlightedIds?.includes(feature.properties.train_id); + }; + } else { + realtimeLayer.filter = null; + } + + console.log( + 'BEFORE features', + featuresHovered.length, + features.length, + featuresHighlightedIds.length, + ); - // Apply the highlight style to the vehicle - realtime.highlight(feature); + if (!featuresHovered.length && !features.length) { + console.log('CLEAR features', featuresHovered.length, features.length); + realtimeLayerHover.getSource().clear(true); + featuresHighlightedIds = []; + } else if (features.length > 1 && !featuresHighlightedIds.length) { + console.log( + 'ADD features', + featuresHoveredIds, + featuresHovered.length, + features.length, + featuresIds, + ); + realtimeLayerHover.getSource().addFeatures(features); + featuresHighlightedIds = featuresIds; + } else if (!featuresHovered.length && features.length === 1) { + realtimeLayer.highlight(features[0]); + } - map.getTargetElement().style.cursor = feature ? 'pointer' : ''; + map.getTargetElement().style.cursor = + features.length || featuresHovered.length ? 'pointer' : ''; }); // Display vehicle informations on click. map.on('singleclick', (evt) => { - const [feature] = map.getFeaturesAtPixel(evt.pixel, queryOptions); + if (evt.dragging) { + return; + } + const pixel = map.getEventPixel(evt.originalEvent); + const [feature] = map.getFeaturesAtPixel(pixel, { + hitTolerance: 15, + layerFilter: (l) => l === realtimeLayer, + }); + const [featureHover] = map.getFeaturesAtPixel(pixel, { + hitTolerance: 15, + layerFilter: (l) => l === realtimeLayerHover, + }); - // Apply the select style to the vehicle - realtime.select(feature); + realtimeLayer.select(featureHover || feature); + realtimeLayerHover.getSource().clear(); + realtimeLayerHover.changed(); + realtimeLayer.filter = null; // Display the realtime feature informations document.getElementById('content').innerHTML = feature diff --git a/src/common/styles/realtimeStyle.ts b/src/common/styles/realtimeStyle.ts index 2368eaa0..9b260385 100644 --- a/src/common/styles/realtimeStyle.ts +++ b/src/common/styles/realtimeStyle.ts @@ -50,8 +50,8 @@ const realtimeStyle: RealtimeStyleFunction = ( getTextColor, getTextFont, getTextSize, - // hoverVehicleId, - hoverVehicleIds, + hoverVehicleId, + // hoverVehicleIds, selectedVehicleId, showDelayBg, showDelayText, @@ -67,21 +67,9 @@ const realtimeStyle: RealtimeStyleFunction = ( state, train_id: id, } = trajectory.properties; - - const name = getText?.(trajectory, viewState) || ''; - - let color = getColor(trajectory, viewState); - let textColor = getTextColor(trajectory, viewState); - const cancelled = state === 'JOURNEY_CANCELLED'; - const hover = hoverVehicleIds?.includes(id); + const hover = !!(hoverVehicleId && hoverVehicleId === id); const selected = !!(selectedVehicleId && selectedVehicleId === id); - // Get the text color of the vehicle - if (useDelayStyle) { - color = getDelayColor(trajectory, viewState, delay, cancelled); - textColor = getDelayTextColor(trajectory, viewState, delay, cancelled); - } - // Calcul the radius of the circle let radius = getRadius(trajectory, viewState) * pixelRatio; const isDisplayStrokeAndDelay = @@ -97,6 +85,17 @@ const realtimeStyle: RealtimeStyleFunction = ( return null; } + const name = getText?.(trajectory, viewState) || ''; + let color = getColor(trajectory, viewState); + let textColor = getTextColor(trajectory, viewState); + const cancelled = state === 'JOURNEY_CANCELLED'; + + // Get the text color of the vehicle + if (useDelayStyle) { + color = getDelayColor(trajectory, viewState, delay, cancelled); + textColor = getDelayTextColor(trajectory, viewState, delay, cancelled); + } + // Calcul if the text should be diplayed or not const isDisplayText = radius > getMaxRadiusForText() * pixelRatio; diff --git a/src/common/utils/renderTrajectories.ts b/src/common/utils/renderTrajectories.ts index 063922b4..10baf673 100644 --- a/src/common/utils/renderTrajectories.ts +++ b/src/common/utils/renderTrajectories.ts @@ -191,10 +191,7 @@ const renderTrajectories = ( // } // } - if ( - (hoverVehicleIds?.length ?? 0) <= 1 || - (!hoverVehicleIds?.includes(id) && selectedVehicleId !== id) - ) { + if (hoverVehicleId !== id && selectedVehicleId !== id) { // To optimize the performance we use integer as pixel coordinate // to avoid an additional work by the browser on zoom level < 12. // See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead @@ -208,9 +205,8 @@ const renderTrajectories = ( if (hoverVehicleId && hoverVehicleId === id) { // Store the canvas to draw it at the end - // hoverVehicleImg = vehicleImg; - // hoverVehiclePx = px; - // console.log(resolution); + hoverVehicleImg = vehicleImg; + hoverVehiclePx = px; } if (selectedVehicleId && selectedVehicleId === id) { @@ -231,17 +227,11 @@ const renderTrajectories = ( } if (hoverVehicleImg && hoverVehiclePx) { - console.log( - 'hoverVehicleId', - hoverVehicleId, - 'hoverVehicleIds', - hoverVehicleIds, + context?.drawImage( + hoverVehicleImg, + Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), + Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2), ); - // context?.drawImage( - // hoverVehicleImg, - // Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), - // Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2), - // ); } return { // isReady: true,