diff --git a/doc/pages/example/[example].js b/doc/pages/example/[example].js
index 78b01b2f..b3764fbd 100644
--- a/doc/pages/example/[example].js
+++ b/doc/pages/example/[example].js
@@ -10,6 +10,7 @@ const useStyles = makeStyles({
paddingBottom: 115,
margin: 'auto',
marginTop: 30,
+ maxWidth: '100% !important',
},
});
diff --git a/doc/public/static/examples/ol-tracker-worker.html b/doc/public/static/examples/ol-tracker-worker.html
new file mode 100644
index 00000000..9aba5a6d
--- /dev/null
+++ b/doc/public/static/examples/ol-tracker-worker.html
@@ -0,0 +1 @@
+
diff --git a/doc/public/static/examples/ol-tracker-worker.js b/doc/public/static/examples/ol-tracker-worker.js
new file mode 100644
index 00000000..6411c107
--- /dev/null
+++ b/doc/public/static/examples/ol-tracker-worker.js
@@ -0,0 +1,46 @@
+import { Map, View } from 'ol';
+import {
+ RealtimeLayer,
+ MaplibreLayer,
+ CopyrightControl,
+} from 'mobility-toolbox-js/ol';
+import 'ol/ol.css';
+
+export default () => {
+ const map = new Map({
+ target: 'map',
+ view: new View({
+ center: [831634, 5933959],
+ zoom: 13,
+ minZoom: 5,
+ }),
+ controls: [],
+ });
+
+ const control = new CopyrightControl();
+ control.attachToMap(map);
+
+ const layer = new MaplibreLayer({
+ url: 'https://maps.geops.io/styles/travic_v2/style.json',
+ apiKey: window.apiKey,
+ });
+ layer.attachToMap(map);
+
+ const tracker = new RealtimeLayer({
+ url: 'wss://api.geops.io/tracker-ws/v1/',
+ apiKey: window.apiKey,
+ allowRenderWhenAnimating:
+ new URL(window.location.href)?.searchParams?.get(
+ 'allowRenderWhenAnimating',
+ ) === 'true',
+ useWorker: true,
+ });
+ tracker.attachToMap(map);
+
+ tracker.onClick(([feature]) => {
+ if (feature) {
+ // eslint-disable-next-line no-console
+ console.log(feature.getProperties());
+ }
+ });
+};
diff --git a/doc/public/static/examples/ol-tracker-worker.md b/doc/public/static/examples/ol-tracker-worker.md
new file mode 100644
index 00000000..26a3f627
--- /dev/null
+++ b/doc/public/static/examples/ol-tracker-worker.md
@@ -0,0 +1 @@
+Follow [this link](https://developer.geops.io/) to get information about the API and how to get an API key.
diff --git a/doc/public/static/examples/ol-tracker.js b/doc/public/static/examples/ol-tracker.js
index 2d31b11d..044f410a 100644
--- a/doc/public/static/examples/ol-tracker.js
+++ b/doc/public/static/examples/ol-tracker.js
@@ -29,6 +29,10 @@ export default () => {
const tracker = new RealtimeLayer({
url: 'wss://api.geops.io/tracker-ws/v1/',
apiKey: window.apiKey,
+ allowRenderWhenAnimating:
+ new URL(window.location.href)?.searchParams?.get(
+ 'allowRenderWhenAnimating',
+ ) === 'true',
});
tracker.attachToMap(map);
diff --git a/doc/src/components/CodeSandboxButton.js b/doc/src/components/CodeSandboxButton.js
index 22f457c7..d5357f0f 100644
--- a/doc/src/components/CodeSandboxButton.js
+++ b/doc/src/components/CodeSandboxButton.js
@@ -41,7 +41,7 @@ function CodeSandboxButton({ html, js, extraFiles, ...props }) {
'mapbox-gl': '1',
'maplibre-gl': '2',
'mobility-toolbox-js': 'latest@beta',
- ol: '6.3.1',
+ ol: '6',
},
devDependencies: {
'@babel/core': '7.2.0',
diff --git a/doc/src/components/Esdoc/index.json b/doc/src/components/Esdoc/index.json
index be410ab2..41088ade 100644
--- a/doc/src/components/Esdoc/index.json
+++ b/doc/src/components/Esdoc/index.json
@@ -2311,7 +2311,7 @@
"__docId__": 118,
"kind": "file",
"name": "build/api/RoutingAPI.js",
- "content": "import HttpAPI from '../common/api/HttpAPI';\n/**\n * Access to the [geOps Routing service](https://developer.geops.io/apis/routing).\n *\n * @example\n * import { RoutingAPI } from 'mobility-toolbox-js';\n *\n * const api = new RoutingAPI({\n * apiKey: [yourApiKey]\n * });\n *\n */\nclass RoutingAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {RoutingAPIOptions} options Options.\n * @param {string} [options.url='https://api.geops.io/routing/v1/'] Service url.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).\n */\n constructor(options = {}) {\n super(Object.assign({ url: 'https://api.geops.io/routing/v1/' }, options));\n }\n /**\n * Route.\n *\n * @param {RoutingParameters} params Request parameters. See [Routing service documentation](https://developer.geops.io/apis/routing/).\n * @param {RequestInit} config Options for the fetch request.\n * @return {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).\n */\n route(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default RoutingAPI;\n",
+ "content": "import HttpAPI from '../common/api/HttpAPI';\n/**\n * Access to the [geOps Routing service](https://developer.geops.io/apis/routing).\n *\n * @example\n * import { RoutingAPI } from 'mobility-toolbox-js';\n *\n * const api = new RoutingAPI({\n * apiKey: [yourApiKey]\n * });\n *\n */\nclass RoutingAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {RoutingAPIOptions} options Options.\n * @param {string} [options.url='https://api.geops.io/routing/v1/'] Service url.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).\n */\n constructor(options = {}) {\n super({ url: 'https://api.geops.io/routing/v1/', ...options });\n }\n /**\n * Route.\n *\n * @param {RoutingParameters} params Request parameters. See [Routing service documentation](https://developer.geops.io/apis/routing/).\n * @param {RequestInit} config Options for the fetch request.\n * @return {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).\n */\n route(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default RoutingAPI;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/RoutingAPI.js",
"access": "public",
@@ -2433,7 +2433,7 @@
"__docId__": 122,
"kind": "file",
"name": "build/api/StopsAPI.js",
- "content": "import HttpAPI from '../common/api/HttpAPI';\n/**\n * Access to the [Stops service](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).\n *\n * @example\n * import { StopsAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new StopsAPI({\n * url: 'https://api.geops.io/stops/v1/',\n * apiKey: [yourApiKey]\n * });\n *\n */\nclass StopsAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {StopsAPIOptions} options Options.\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] Service url.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).\n */\n constructor(options = {}) {\n super(Object.assign({ url: 'https://api.geops.io/stops/v1/' }, options));\n }\n /**\n * Search fo stops.\n *\n * @param {StopsParameters} params Request parameters. See [Stops service documentation](https://developer.geops.io/apis/stops).\n * @param {RequestInit} config Options for the fetch request.\n * @return {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).\n */\n search(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default StopsAPI;\n",
+ "content": "import HttpAPI from '../common/api/HttpAPI';\n/**\n * Access to the [Stops service](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).\n *\n * @example\n * import { StopsAPI } from 'mobility-toolbox-js/api';\n *\n * const api = new StopsAPI({\n * url: 'https://api.geops.io/stops/v1/',\n * apiKey: [yourApiKey]\n * });\n *\n */\nclass StopsAPI extends HttpAPI {\n /**\n * Constructor\n *\n * @param {StopsAPIOptions} options Options.\n * @param {string} [options.url='https://api.geops.io/stops/v1/'] Service url.\n * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).\n */\n constructor(options = {}) {\n super({ url: 'https://api.geops.io/stops/v1/', ...options });\n }\n /**\n * Search fo stops.\n *\n * @param {StopsParameters} params Request parameters. See [Stops service documentation](https://developer.geops.io/apis/stops).\n * @param {RequestInit} config Options for the fetch request.\n * @return {Promise} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).\n */\n search(params, config) {\n return this.fetch('', params, config);\n }\n}\nexport default StopsAPI;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/StopsAPI.js",
"access": "public",
@@ -2565,6 +2565,65 @@
{
"__docId__": 127,
"kind": "file",
+ "name": "build/api/trajserv/fetchTrajectories.worker.js",
+ "content": "import { translateTrajCollResponse } from './TrajservAPIUtils';\nlet abortController = new AbortController();\n// eslint-disable-next-line no-restricted-globals, func-names\nself.onmessage = function (evt) {\n // console.log('Worker: Message received from main script', evt.data);\n abortController.abort();\n abortController = new AbortController();\n fetch(evt.data, {\n signal: abortController.signal,\n })\n .then((res) => res.json())\n .then((data) => {\n const a = translateTrajCollResponse(data.features);\n // eslint-disable-next-line no-restricted-globals\n self.postMessage(a);\n })\n .catch(() => {\n // eslint-disable-next-line no-restricted-globals\n // self.postMessage(null);\n });\n};\n",
+ "static": true,
+ "longname": "/home/olivier/GIT/mobility-toolbox-js/build/api/trajserv/fetchTrajectories.worker.js",
+ "access": "public",
+ "description": null,
+ "lineNumber": 1
+ },
+ {
+ "__docId__": 128,
+ "kind": "variable",
+ "name": "abortController",
+ "memberof": "build/api/trajserv/fetchTrajectories.worker.js",
+ "static": true,
+ "longname": "build/api/trajserv/fetchTrajectories.worker.js~abortController",
+ "access": "public",
+ "export": false,
+ "importPath": "mobility-toolbox-js/build/api/trajserv/fetchTrajectories.worker.js",
+ "importStyle": null,
+ "description": null,
+ "lineNumber": 2,
+ "undocument": true,
+ "type": {
+ "types": [
+ "*"
+ ]
+ },
+ "ignore": true
+ },
+ {
+ "__docId__": 129,
+ "kind": "function",
+ "name": "onmessage",
+ "memberof": "build/api/trajserv/fetchTrajectories.worker.js",
+ "generator": false,
+ "async": false,
+ "static": true,
+ "longname": "build/api/trajserv/fetchTrajectories.worker.js~onmessage",
+ "access": "public",
+ "export": false,
+ "importPath": "mobility-toolbox-js/build/api/trajserv/fetchTrajectories.worker.js",
+ "importStyle": null,
+ "description": null,
+ "lineNumber": 4,
+ "undocument": true,
+ "params": [
+ {
+ "name": "evt",
+ "types": [
+ "*"
+ ]
+ }
+ ],
+ "return": null,
+ "ignore": true
+ },
+ {
+ "__docId__": 130,
+ "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/**\n * @typedef {GeoJSONFeature} StopSequence\n */\n/**\n * @typedef {GeoJSONFeature} RealtimeTrajectory\n */\n/**\n * @typedef {GeoJSONFeature} FullTrajectory\n */\n/**\n * @typedef {GeoJSONFeature} Vehicle\n */\n/**\n * @typedef {GeoJSONFeature} ExtraGeom\n */\n// These lines is to block TypeScript to add \"use strict;\" in the outputed file.\nconst dummy = () => { };\nexport default dummy;\n",
"static": true,
@@ -2574,7 +2633,7 @@
"lineNumber": 1
},
{
- "__docId__": 128,
+ "__docId__": 131,
"kind": "typedef",
"name": "Departure",
"memberof": "build/api/typedefs.js",
@@ -2823,7 +2882,7 @@
}
},
{
- "__docId__": 129,
+ "__docId__": 132,
"kind": "typedef",
"name": "Station",
"memberof": "build/api/typedefs.js",
@@ -2862,7 +2921,7 @@
}
},
{
- "__docId__": 130,
+ "__docId__": 133,
"kind": "typedef",
"name": "StationProperties",
"memberof": "build/api/typedefs.js",
@@ -2971,7 +3030,7 @@
}
},
{
- "__docId__": 131,
+ "__docId__": 134,
"kind": "typedef",
"name": "NetworkLine",
"memberof": "build/api/typedefs.js",
@@ -3040,7 +3099,7 @@
}
},
{
- "__docId__": 132,
+ "__docId__": 135,
"kind": "typedef",
"name": "Transfer",
"memberof": "build/api/typedefs.js",
@@ -3079,7 +3138,7 @@
}
},
{
- "__docId__": 133,
+ "__docId__": 136,
"kind": "typedef",
"name": "StopSequence",
"memberof": "build/api/typedefs.js",
@@ -3096,7 +3155,7 @@
}
},
{
- "__docId__": 134,
+ "__docId__": 137,
"kind": "typedef",
"name": "RealtimeTrajectory",
"memberof": "build/api/typedefs.js",
@@ -3113,7 +3172,7 @@
}
},
{
- "__docId__": 135,
+ "__docId__": 138,
"kind": "typedef",
"name": "FullTrajectory",
"memberof": "build/api/typedefs.js",
@@ -3130,7 +3189,7 @@
}
},
{
- "__docId__": 136,
+ "__docId__": 139,
"kind": "typedef",
"name": "Vehicle",
"memberof": "build/api/typedefs.js",
@@ -3147,7 +3206,7 @@
}
},
{
- "__docId__": 137,
+ "__docId__": 140,
"kind": "typedef",
"name": "ExtraGeom",
"memberof": "build/api/typedefs.js",
@@ -3165,10 +3224,10 @@
}
},
{
- "__docId__": 138,
+ "__docId__": 141,
"kind": "file",
"name": "build/common/api/HttpAPI.js",
- "content": "import BaseObject from 'ol/Object';\nimport getUrlWithParams from '../utils/getUrlWithParams';\n/**\n * Common class to access to a geOps api using http.\n *\n * @example\n * import { API } from 'mobility-toolbox-js/api';\n *\n * const api = new HttpApi({\n * url: [yourUrl],\n * apiKey: [yourApiKey]\n * });\n *\n * @classproperty {string} url Url of the service.\n * @classproperty {string} apiKey Api key to access the service.\n */\nclass HttpAPI extends BaseObject {\n constructor(options) {\n super();\n /** @ignore */\n this.url = options.url;\n /** @ignore */\n this.apiKey = options.apiKey;\n }\n /**\n * Append the apiKey before sending the request.\n * @ignore\n */\n fetch(path, params, config) {\n if (!this.url) {\n // eslint-disable-next-line no-console\n return Promise.reject(new Error(`No url defined for request to ${this.url}/${path}`));\n }\n if (!this.url && !this.apiKey && !/key=/.test(this.url)) {\n // eslint-disable-next-line no-console\n return Promise.reject(new Error(`No apiKey defined for request to ${this.url}`));\n }\n // Clean requets parameters, removing undefined and null values.\n const searchParams = params || {};\n const url = getUrlWithParams(`${this.url}${path || ''}`, Object.assign({ key: this.apiKey }, searchParams));\n // We use toString because of TYpeScript bug that only accept a string in fetch method.\n return fetch(url.toString(), config).then((response) => {\n try {\n return response.json().then((data) => {\n if (data.error) {\n throw new Error(data.error);\n }\n return data;\n });\n }\n catch (err) {\n return Promise.reject(new Error(err));\n }\n });\n }\n}\nexport default HttpAPI;\n",
+ "content": "import BaseObject from 'ol/Object';\nimport getUrlWithParams from '../utils/getUrlWithParams';\n/**\n * Common class to access to a geOps api using http.\n *\n * @example\n * import { API } from 'mobility-toolbox-js/api';\n *\n * const api = new HttpApi({\n * url: [yourUrl],\n * apiKey: [yourApiKey]\n * });\n *\n * @classproperty {string} url Url of the service.\n * @classproperty {string} apiKey Api key to access the service.\n */\nclass HttpAPI extends BaseObject {\n constructor(options) {\n super();\n /** @ignore */\n this.url = options.url;\n /** @ignore */\n this.apiKey = options.apiKey;\n }\n /**\n * Append the apiKey before sending the request.\n * @ignore\n */\n fetch(path, params, config) {\n if (!this.url) {\n // eslint-disable-next-line no-console\n return Promise.reject(new Error(`No url defined for request to ${this.url}/${path}`));\n }\n if (!this.url && !this.apiKey && !/key=/.test(this.url)) {\n // eslint-disable-next-line no-console\n return Promise.reject(new Error(`No apiKey defined for request to ${this.url}`));\n }\n // Clean requets parameters, removing undefined and null values.\n const searchParams = params || {};\n const url = getUrlWithParams(`${this.url}${path || ''}`, {\n key: this.apiKey,\n ...searchParams,\n });\n // We use toString because of TYpeScript bug that only accept a string in fetch method.\n return fetch(url.toString(), config).then((response) => {\n try {\n return response.json().then((data) => {\n if (data.error) {\n throw new Error(data.error);\n }\n return data;\n });\n }\n catch (err) {\n return Promise.reject(new Error(err));\n }\n });\n }\n}\nexport default HttpAPI;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/api/HttpAPI.js",
"access": "public",
@@ -3176,7 +3235,7 @@
"lineNumber": 1
},
{
- "__docId__": 139,
+ "__docId__": 142,
"kind": "class",
"name": "HttpAPI",
"memberof": "build/common/api/HttpAPI.js",
@@ -3207,7 +3266,7 @@
]
},
{
- "__docId__": 140,
+ "__docId__": 143,
"kind": "constructor",
"name": "constructor",
"memberof": "build/common/api/HttpAPI.js~HttpAPI",
@@ -3221,7 +3280,7 @@
"undocument": true
},
{
- "__docId__": 141,
+ "__docId__": 144,
"kind": "member",
"name": "url",
"memberof": "build/common/api/HttpAPI.js~HttpAPI",
@@ -3238,7 +3297,7 @@
}
},
{
- "__docId__": 142,
+ "__docId__": 145,
"kind": "member",
"name": "apiKey",
"memberof": "build/common/api/HttpAPI.js~HttpAPI",
@@ -3255,7 +3314,7 @@
}
},
{
- "__docId__": 143,
+ "__docId__": 146,
"kind": "method",
"name": "fetch",
"memberof": "build/common/api/HttpAPI.js~HttpAPI",
@@ -3294,10 +3353,10 @@
}
},
{
- "__docId__": 144,
+ "__docId__": 147,
"kind": "file",
"name": "build/common/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 */\nclass WebSocketAPI {\n constructor() {\n this.defineProperties();\n }\n defineProperties() {\n Object.defineProperties(this, {\n closed: {\n get: () => !!(!this.websocket ||\n this.websocket.readyState === this.websocket.CLOSED),\n },\n closing: {\n get: () => !!(this.websocket &&\n this.websocket.readyState === this.websocket.CLOSING),\n },\n connecting: {\n get: () => !!(this.websocket &&\n this.websocket.readyState === this.websocket.CONNECTING),\n },\n open: {\n get: () => !!(this.websocket && this.websocket.readyState === this.websocket.OPEN),\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 /**\n * Array of subscriptions.\n * @type {Array}\n * @private\n */\n subscriptions: {\n value: [],\n writable: true,\n },\n /**\n * List of channels subscribed.\n * @type {WebSocketSubscribed}\n * @private\n */\n subscribed: {\n value: {},\n writable: true,\n },\n });\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 /**\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 if (this.websocket && !this.closed) {\n if (!this.closing && this.websocket.url !== url) {\n this.websocket.close();\n }\n else if (this.connecting) {\n return;\n }\n }\n /** @ignore */\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 /**\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 * Sends a message to the websocket.\n *\n * @param {message} message Message to send.\n * @private\n */\n send(message) {\n if (!this.websocket) {\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 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 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 * 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 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 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 { onMessageCb: onMessage, onErrorCb: errorCb };\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) => s.params.channel === params.channel && (!cb || s.cb === cb))\n .forEach(({ onMessageCb, onErrorCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\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} onMessage callback on message event\n * @param {function} onError 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 // @ts-ignore: Spread error\n (...args) => {\n // @ts-ignore: Spread error\n callback(...args);\n const index = this.requests.findIndex((request) => requestString === request.requestString && cb === request.cb);\n const { onMessageCb, onErrorCb } = this.requests[index];\n this.removeEvents(onMessageCb, onErrorCb);\n this.requests.splice(index, 1);\n };\n const { onMessageCb, onErrorCb } = 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) => requestString === request.requestString && cb === request.cb);\n const newReq = {\n params,\n requestString,\n cb,\n errorCb,\n onMessageCb,\n onErrorCb,\n };\n if (index > -1) {\n this.requests[index] = newReq;\n }\n else {\n this.requests.push(newReq);\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 { onMessageCb, onErrorCb } = this.listen(params, cb, errorCb);\n const reqStr = WebSocketAPI.getRequestString('', params);\n const index = this.subscriptions.findIndex((subcr) => params.channel === subcr.params.channel && cb === subcr.cb);\n const newSubscr = { params, cb, errorCb, onMessageCb, onErrorCb, quiet };\n if (index > -1) {\n this.subscriptions[index] = newSubscr;\n }\n else {\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 * 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) => s.params.channel === source && (!cb || s.cb === cb));\n toRemove.forEach(({ onMessageCb, onErrorCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n this.subscriptions = this.subscriptions.filter((s) => s.params.channel !== source || (cb && s.cb !== cb));\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) => s.params.channel === source) &&\n toRemove.find((subscr) => !subscr.quiet)) {\n this.send(`DEL ${source}`);\n this.subscribed[source] = false;\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}\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 */\nclass WebSocketAPI {\n constructor() {\n this.defineProperties();\n }\n defineProperties() {\n Object.defineProperties(this, {\n closed: {\n get: () => !!(!this.websocket ||\n this.websocket.readyState === this.websocket.CLOSED),\n },\n closing: {\n get: () => !!(this.websocket &&\n this.websocket.readyState === this.websocket.CLOSING),\n },\n connecting: {\n get: () => !!(this.websocket &&\n this.websocket.readyState === this.websocket.CONNECTING),\n },\n open: {\n get: () => !!(this.websocket && this.websocket.readyState === this.websocket.OPEN),\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 /**\n * Array of subscriptions.\n * @type {Array}\n * @private\n */\n subscriptions: {\n value: [],\n writable: true,\n },\n /**\n * List of channels subscribed.\n * @type {WebSocketSubscribed}\n * @private\n */\n subscribed: {\n value: {},\n writable: true,\n },\n });\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 /**\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 if (this.websocket && !this.closed) {\n if (!this.closing && this.websocket.url !== url) {\n this.websocket.close();\n }\n else if (this.connecting) {\n return;\n }\n }\n /** @ignore */\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 /**\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 * Sends a message to the websocket.\n *\n * @param {message} message Message to send.\n * @private\n */\n send(message) {\n if (!this.websocket) {\n return;\n }\n const send = () => {\n this.websocket?.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 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 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 * 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 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 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?.source === source &&\n (!params.id || params.id === data.client_reference)) {\n cb(content);\n }\n });\n };\n this.addEvents(onMessage, errorCb);\n return { onMessageCb: onMessage, onErrorCb: errorCb };\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) => s.params.channel === params.channel && (!cb || s.cb === cb))\n .forEach(({ onMessageCb, onErrorCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\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} onMessage callback on message event\n * @param {function} onError 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 // @ts-ignore: Spread error\n (...args) => {\n // @ts-ignore: Spread error\n callback(...args);\n const index = this.requests.findIndex((request) => requestString === request.requestString && cb === request.cb);\n const { onMessageCb, onErrorCb } = this.requests[index];\n this.removeEvents(onMessageCb, onErrorCb);\n this.requests.splice(index, 1);\n };\n const { onMessageCb, onErrorCb } = 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) => requestString === request.requestString && cb === request.cb);\n const newReq = {\n params,\n requestString,\n cb,\n errorCb,\n onMessageCb,\n onErrorCb,\n };\n if (index > -1) {\n this.requests[index] = newReq;\n }\n else {\n this.requests.push(newReq);\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 { onMessageCb, onErrorCb } = this.listen(params, cb, errorCb);\n const reqStr = WebSocketAPI.getRequestString('', params);\n const index = this.subscriptions.findIndex((subcr) => params.channel === subcr.params.channel && cb === subcr.cb);\n const newSubscr = { params, cb, errorCb, onMessageCb, onErrorCb, quiet };\n if (index > -1) {\n this.subscriptions[index] = newSubscr;\n }\n else {\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 * 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) => s.params.channel === source && (!cb || s.cb === cb));\n toRemove.forEach(({ onMessageCb, onErrorCb }) => {\n this.removeEvents(onMessageCb, onErrorCb);\n });\n this.subscriptions = this.subscriptions.filter((s) => s.params.channel !== source || (cb && s.cb !== cb));\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) => s.params.channel === source) &&\n toRemove.find((subscr) => !subscr.quiet)) {\n this.send(`DEL ${source}`);\n this.subscribed[source] = false;\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}\nexport default WebSocketAPI;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/api/WebSocketAPI.js",
"access": "public",
@@ -3305,7 +3364,7 @@
"lineNumber": 1
},
{
- "__docId__": 145,
+ "__docId__": 148,
"kind": "class",
"name": "WebSocketAPI",
"memberof": "build/common/api/WebSocketAPI.js",
@@ -3320,7 +3379,7 @@
"interface": false
},
{
- "__docId__": 146,
+ "__docId__": 149,
"kind": "constructor",
"name": "constructor",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3334,7 +3393,7 @@
"undocument": true
},
{
- "__docId__": 147,
+ "__docId__": 150,
"kind": "method",
"name": "defineProperties",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3350,7 +3409,7 @@
"return": null
},
{
- "__docId__": 148,
+ "__docId__": 151,
"kind": "method",
"name": "getRequestString",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3424,7 +3483,7 @@
}
},
{
- "__docId__": 149,
+ "__docId__": 152,
"kind": "method",
"name": "connect",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3460,7 +3519,7 @@
"return": null
},
{
- "__docId__": 150,
+ "__docId__": 153,
"kind": "member",
"name": "websocket",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3477,7 +3536,7 @@
}
},
{
- "__docId__": 151,
+ "__docId__": 154,
"kind": "method",
"name": "close",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3492,7 +3551,7 @@
"return": null
},
{
- "__docId__": 152,
+ "__docId__": 155,
"kind": "member",
"name": "messagesOnOpen",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3509,7 +3568,7 @@
}
},
{
- "__docId__": 153,
+ "__docId__": 156,
"kind": "method",
"name": "send",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3535,7 +3594,7 @@
"return": null
},
{
- "__docId__": 156,
+ "__docId__": 159,
"kind": "method",
"name": "addEvents",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3545,7 +3604,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#addEvents",
"access": "public",
"description": null,
- "lineNumber": 145,
+ "lineNumber": 144,
"undocument": true,
"params": [
{
@@ -3564,7 +3623,7 @@
"return": null
},
{
- "__docId__": 157,
+ "__docId__": 160,
"kind": "method",
"name": "removeEvents",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3574,7 +3633,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#removeEvents",
"access": "public",
"description": null,
- "lineNumber": 154,
+ "lineNumber": 153,
"undocument": true,
"params": [
{
@@ -3593,7 +3652,7 @@
"return": null
},
{
- "__docId__": 158,
+ "__docId__": 161,
"kind": "method",
"name": "listen",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3603,7 +3662,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#listen",
"access": "private",
"description": "Listen to websocket messages.",
- "lineNumber": 172,
+ "lineNumber": 171,
"params": [
{
"nullable": null,
@@ -3646,7 +3705,7 @@
}
},
{
- "__docId__": 159,
+ "__docId__": 162,
"kind": "method",
"name": "unlisten",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3656,7 +3715,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#unlisten",
"access": "private",
"description": "Unlisten websocket messages.",
- "lineNumber": 215,
+ "lineNumber": 214,
"params": [
{
"nullable": null,
@@ -3682,7 +3741,7 @@
"return": null
},
{
- "__docId__": 160,
+ "__docId__": 163,
"kind": "method",
"name": "get",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3692,7 +3751,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#get",
"access": "private",
"description": "Sends a get request to the websocket.\nThe callback is called only once, when the response is received or when the call returns an error.",
- "lineNumber": 231,
+ "lineNumber": 230,
"params": [
{
"nullable": null,
@@ -3728,7 +3787,7 @@
"return": null
},
{
- "__docId__": 161,
+ "__docId__": 164,
"kind": "member",
"name": "requests",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3736,7 +3795,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#requests",
"access": "public",
"description": null,
- "lineNumber": 248,
+ "lineNumber": 247,
"undocument": true,
"type": {
"types": [
@@ -3745,7 +3804,7 @@
}
},
{
- "__docId__": 162,
+ "__docId__": 165,
"kind": "method",
"name": "subscribe",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3755,7 +3814,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#subscribe",
"access": "private",
"description": "Subscribe to a given channel.",
- "lineNumber": 275,
+ "lineNumber": 274,
"params": [
{
"nullable": null,
@@ -3801,7 +3860,7 @@
"return": null
},
{
- "__docId__": 163,
+ "__docId__": 166,
"kind": "method",
"name": "unsubscribe",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3811,7 +3870,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#unsubscribe",
"access": "private",
"description": "Unsubscribe from a channel.",
- "lineNumber": 300,
+ "lineNumber": 299,
"params": [
{
"nullable": null,
@@ -3837,7 +3896,7 @@
"return": null
},
{
- "__docId__": 164,
+ "__docId__": 167,
"kind": "member",
"name": "subscriptions",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3845,7 +3904,7 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#subscriptions",
"access": "public",
"description": null,
- "lineNumber": 305,
+ "lineNumber": 304,
"undocument": true,
"type": {
"types": [
@@ -3854,7 +3913,7 @@
}
},
{
- "__docId__": 165,
+ "__docId__": 168,
"kind": "method",
"name": "subscribePreviousSubscriptions",
"memberof": "build/common/api/WebSocketAPI.js~WebSocketAPI",
@@ -3864,15 +3923,15 @@
"longname": "build/common/api/WebSocketAPI.js~WebSocketAPI#subscribePreviousSubscriptions",
"access": "public",
"description": "After an auto reconnection we need to re-subscribe to the channels.",
- "lineNumber": 319,
+ "lineNumber": 318,
"params": [],
"return": null
},
{
- "__docId__": 166,
+ "__docId__": 169,
"kind": "file",
"name": "build/common/controls/ControlCommon.js",
- "content": "import BaseObject from 'ol/Object';\n/**\n * A class representing a control to display on map.\n *\n * @example\n * const control = new Control();\n *\n * @classproperty {ol/Map~Map|mapboxgl.Map} map - The map which the control refers to.\n * @classproperty {boolean} active - Active the control.\n * @classproperty {HTMLElement} element - The HTML element used to render the control.\n * @classproperty {HTMLElement} target - The HTML element where to render the element property. Default is the map's element. Read only.\n */\nclass ControlCommon extends BaseObject {\n /**\n * Constructor\n *\n * @param {Object} [options] Control options.\n * @param {boolean} [options.active = true] Whether the control is active or not.\n * @param {HTMLElement} [options.element] The HTML element used to render the control.\n * @param {HTMLElement} [options.target] The HTML element where to render the element property. Default is the map's element.\n * @param {function} [options.render] Render function called whenever the control needs to be rerendered.\n */\n constructor(options = {}) {\n super(options);\n this.defineProperties(options);\n const { active } = Object.assign({ active: options.active !== false }, options);\n /**\n * @ignore\n */\n this.active = active;\n }\n /**\n * Define control's properties.\n *\n * @private\n * @ignore\n */\n defineProperties(options) {\n const { target, element, render } = Object.assign({}, options);\n Object.defineProperties(this, {\n active: {\n get: () => this.get('active'),\n set: (newActive) => {\n this.set('active', newActive);\n if (newActive) {\n this.activate();\n }\n else {\n this.deactivate();\n }\n this.render();\n },\n },\n map: {\n get: () => this.get('map'),\n set: (map) => {\n // Remove previous node.\n if (this.map && this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n // Clean listeners\n this.deactivate();\n this.set('map', map);\n if (this.map) {\n // Add new node\n const targett = this.target ||\n (this.map.getTargetElement &&\n this.map.getTargetElement()) ||\n (this.map.getContainer &&\n this.map.getContainer());\n if (!this.element) {\n this.createDefaultElement();\n }\n if (this.element) {\n targett.appendChild(this.element);\n }\n // Add listeners\n if (this.active) {\n this.activate();\n }\n }\n this.render();\n },\n },\n target: {\n value: target,\n },\n element: {\n value: element,\n writable: true,\n },\n render: {\n /** @ignore */\n value: render || this.render,\n writable: true,\n },\n });\n }\n /**\n * Attach the control to the map. Add events, html element ...\n */\n attachToMap(map) {\n this.map = map;\n }\n /**\n * Detach the control From the map. Remove events, html element ..\n */\n detachFromMap() {\n this.map = undefined;\n }\n /**\n * Add listeners then renders the control.\n * To be defined in inherited classes.\n */\n activate() {\n this.deactivate();\n }\n /**\n * Remove listeners added by activate() function then renders the control.\n * To be defined in inherited classes.\n */\n // eslint-disable-next-line class-methods-use-this\n deactivate() {\n // eslint-disable-next-line no-console\n console.error('The function deactivate() must be implemented in subclasses');\n }\n /**\n * The default render function. It renders content in the HTML element.\n * To be defined in inherited classes.\n *\n * @private\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n render(options) {\n // eslint-disable-next-line no-console\n console.error('The function render() must be implemented in subclasses');\n }\n /**\n * The default element to display if this.element is not defined.\n * To be defined in inherited classes.\n *\n * @private\n */\n // eslint-disable-next-line class-methods-use-this\n createDefaultElement() {\n // eslint-disable-next-line no-console\n console.error('The function createDefaultElement() must be implemented in subclasses');\n }\n}\nexport default ControlCommon;\n",
+ "content": "import BaseObject from 'ol/Object';\n/**\n * A class representing a control to display on map.\n *\n * @example\n * const control = new Control();\n *\n * @classproperty {ol/Map~Map|mapboxgl.Map} map - The map which the control refers to.\n * @classproperty {boolean} active - Active the control.\n * @classproperty {HTMLElement} element - The HTML element used to render the control.\n * @classproperty {HTMLElement} target - The HTML element where to render the element property. Default is the map's element. Read only.\n */\nclass ControlCommon extends BaseObject {\n /**\n * Constructor\n *\n * @param {Object} [options] Control options.\n * @param {boolean} [options.active = true] Whether the control is active or not.\n * @param {HTMLElement} [options.element] The HTML element used to render the control.\n * @param {HTMLElement} [options.target] The HTML element where to render the element property. Default is the map's element.\n * @param {function} [options.render] Render function called whenever the control needs to be rerendered.\n */\n constructor(options = {}) {\n super(options);\n this.defineProperties(options);\n const { active } = {\n active: options.active !== false,\n ...options,\n };\n /**\n * @ignore\n */\n this.active = active;\n }\n /**\n * Define control's properties.\n *\n * @private\n * @ignore\n */\n defineProperties(options) {\n const { target, element, render } = {\n ...options,\n };\n Object.defineProperties(this, {\n active: {\n get: () => this.get('active'),\n set: (newActive) => {\n this.set('active', newActive);\n if (newActive) {\n this.activate();\n }\n else {\n this.deactivate();\n }\n this.render();\n },\n },\n map: {\n get: () => this.get('map'),\n set: (map) => {\n // Remove previous node.\n if (this.map && this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n // Clean listeners\n this.deactivate();\n this.set('map', map);\n if (this.map) {\n // Add new node\n const targett = this.target ||\n (this.map.getTargetElement &&\n this.map.getTargetElement()) ||\n (this.map.getContainer &&\n this.map.getContainer());\n if (!this.element) {\n this.createDefaultElement();\n }\n if (this.element) {\n targett.appendChild(this.element);\n }\n // Add listeners\n if (this.active) {\n this.activate();\n }\n }\n this.render();\n },\n },\n target: {\n value: target,\n },\n element: {\n value: element,\n writable: true,\n },\n render: {\n /** @ignore */\n value: render || this.render,\n writable: true,\n },\n });\n }\n /**\n * Attach the control to the map. Add events, html element ...\n */\n attachToMap(map) {\n this.map = map;\n }\n /**\n * Detach the control From the map. Remove events, html element ..\n */\n detachFromMap() {\n this.map = undefined;\n }\n /**\n * Add listeners then renders the control.\n * To be defined in inherited classes.\n */\n activate() {\n this.deactivate();\n }\n /**\n * Remove listeners added by activate() function then renders the control.\n * To be defined in inherited classes.\n */\n // eslint-disable-next-line class-methods-use-this\n deactivate() {\n // eslint-disable-next-line no-console\n console.error('The function deactivate() must be implemented in subclasses');\n }\n /**\n * The default render function. It renders content in the HTML element.\n * To be defined in inherited classes.\n *\n * @private\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n render(options) {\n // eslint-disable-next-line no-console\n console.error('The function render() must be implemented in subclasses');\n }\n /**\n * The default element to display if this.element is not defined.\n * To be defined in inherited classes.\n *\n * @private\n */\n // eslint-disable-next-line class-methods-use-this\n createDefaultElement() {\n // eslint-disable-next-line no-console\n console.error('The function createDefaultElement() must be implemented in subclasses');\n }\n}\nexport default ControlCommon;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/controls/ControlCommon.js",
"access": "public",
@@ -3880,7 +3939,7 @@
"lineNumber": 1
},
{
- "__docId__": 167,
+ "__docId__": 170,
"kind": "class",
"name": "ControlCommon",
"memberof": "build/common/controls/ControlCommon.js",
@@ -3919,7 +3978,7 @@
]
},
{
- "__docId__": 168,
+ "__docId__": 171,
"kind": "constructor",
"name": "constructor",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -3986,7 +4045,7 @@
]
},
{
- "__docId__": 169,
+ "__docId__": 172,
"kind": "member",
"name": "active",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -3994,7 +4053,7 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#active",
"access": "public",
"description": "",
- "lineNumber": 30,
+ "lineNumber": 33,
"ignore": true,
"type": {
"types": [
@@ -4003,7 +4062,7 @@
}
},
{
- "__docId__": 170,
+ "__docId__": 173,
"kind": "method",
"name": "defineProperties",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4013,7 +4072,7 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#defineProperties",
"access": "private",
"description": "Define control's properties.",
- "lineNumber": 38,
+ "lineNumber": 41,
"ignore": true,
"params": [
{
@@ -4026,7 +4085,7 @@
"return": null
},
{
- "__docId__": 171,
+ "__docId__": 174,
"kind": "method",
"name": "attachToMap",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4036,7 +4095,7 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#attachToMap",
"access": "public",
"description": "Attach the control to the map. Add events, html element ...",
- "lineNumber": 102,
+ "lineNumber": 107,
"params": [
{
"name": "map",
@@ -4048,7 +4107,7 @@
"return": null
},
{
- "__docId__": 172,
+ "__docId__": 175,
"kind": "member",
"name": "map",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4056,7 +4115,7 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#map",
"access": "public",
"description": null,
- "lineNumber": 103,
+ "lineNumber": 108,
"undocument": true,
"type": {
"types": [
@@ -4065,7 +4124,7 @@
}
},
{
- "__docId__": 173,
+ "__docId__": 176,
"kind": "method",
"name": "detachFromMap",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4075,12 +4134,12 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#detachFromMap",
"access": "public",
"description": "Detach the control From the map. Remove events, html element ..",
- "lineNumber": 108,
+ "lineNumber": 113,
"params": [],
"return": null
},
{
- "__docId__": 175,
+ "__docId__": 178,
"kind": "method",
"name": "activate",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4090,12 +4149,12 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#activate",
"access": "public",
"description": "Add listeners then renders the control.\nTo be defined in inherited classes.",
- "lineNumber": 115,
+ "lineNumber": 120,
"params": [],
"return": null
},
{
- "__docId__": 176,
+ "__docId__": 179,
"kind": "method",
"name": "deactivate",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4105,12 +4164,12 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#deactivate",
"access": "public",
"description": "Remove listeners added by activate() function then renders the control.\nTo be defined in inherited classes.",
- "lineNumber": 123,
+ "lineNumber": 128,
"params": [],
"return": null
},
{
- "__docId__": 177,
+ "__docId__": 180,
"kind": "method",
"name": "render",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4120,7 +4179,7 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#render",
"access": "private",
"description": "The default render function. It renders content in the HTML element.\nTo be defined in inherited classes.",
- "lineNumber": 134,
+ "lineNumber": 139,
"params": [
{
"name": "options",
@@ -4132,7 +4191,7 @@
"return": null
},
{
- "__docId__": 178,
+ "__docId__": 181,
"kind": "method",
"name": "createDefaultElement",
"memberof": "build/common/controls/ControlCommon.js~ControlCommon",
@@ -4142,12 +4201,12 @@
"longname": "build/common/controls/ControlCommon.js~ControlCommon#createDefaultElement",
"access": "private",
"description": "The default element to display if this.element is not defined.\nTo be defined in inherited classes.",
- "lineNumber": 145,
+ "lineNumber": 150,
"params": [],
"return": null
},
{
- "__docId__": 179,
+ "__docId__": 182,
"kind": "file",
"name": "build/common/controls/CopyrightControlCommon.js",
"content": "/* eslint-disable max-classes-per-file */\nimport ControlCommon from './ControlCommon';\n/**\n * A class representing a copyright control to display on map.\n * This class only draw an html element, with an empty string in it.\n * Use subclasses to use it in an ol or mapbox map.\n */\nclass CopyrightControlCommon extends ControlCommon {\n render() {\n if (!this.element) {\n return;\n }\n this.element.innerHTML = this.active\n ? this.getCopyrights().join(' | ')\n : '';\n }\n createDefaultElement() {\n this.element = document.createElement('div');\n this.element.id = 'mbt-copyright';\n Object.assign(this.element.style, {\n position: 'absolute',\n bottom: 0,\n right: 0,\n fontSize: '.8rem',\n padding: '0 10px',\n });\n }\n getCopyrights() {\n // eslint-disable-next-line no-console\n console.error('The getCopyrights() function must be implemented in subclasses.', this);\n return [];\n }\n}\nexport default CopyrightControlCommon;\n",
@@ -4158,7 +4217,7 @@
"lineNumber": 1
},
{
- "__docId__": 180,
+ "__docId__": 183,
"kind": "class",
"name": "CopyrightControlCommon",
"memberof": "build/common/controls/CopyrightControlCommon.js",
@@ -4176,7 +4235,7 @@
]
},
{
- "__docId__": 181,
+ "__docId__": 184,
"kind": "method",
"name": "render",
"memberof": "build/common/controls/CopyrightControlCommon.js~CopyrightControlCommon",
@@ -4192,7 +4251,7 @@
"return": null
},
{
- "__docId__": 182,
+ "__docId__": 185,
"kind": "method",
"name": "createDefaultElement",
"memberof": "build/common/controls/CopyrightControlCommon.js~CopyrightControlCommon",
@@ -4208,7 +4267,7 @@
"return": null
},
{
- "__docId__": 183,
+ "__docId__": 186,
"kind": "member",
"name": "element",
"memberof": "build/common/controls/CopyrightControlCommon.js~CopyrightControlCommon",
@@ -4225,7 +4284,7 @@
}
},
{
- "__docId__": 184,
+ "__docId__": 187,
"kind": "method",
"name": "getCopyrights",
"memberof": "build/common/controls/CopyrightControlCommon.js~CopyrightControlCommon",
@@ -4245,10 +4304,10 @@
}
},
{
- "__docId__": 185,
+ "__docId__": 188,
"kind": "file",
"name": "build/common/controls/StopFinderControlCommon.js",
- "content": "import { StopsAPI } from '../../api';\nimport ControlCommon from './ControlCommon';\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 */\nclass StopFinderControlCommon extends ControlCommon {\n /**\n * Constructor.\n *\n * @param {Object} options Map options\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/tracker/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 super(options);\n const { apiParams, apiKey, url, placeholder } = 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 }\n deactivate() { }\n render(featureCollection) {\n const suggestions = (featureCollection === null || featureCollection === void 0 ? void 0 : featureCollection.features) || [];\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 = () => {\n // @ts-ignore\n this.onSuggestionClick(suggestion);\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 createDefaultElement() {\n /**\n * Define a default element.\n */\n this.element = document.createElement('div');\n this.element.id = 'mbt-search';\n Object.assign(this.element.style, {\n position: 'absolute',\n top: 0,\n left: '50px',\n margin: '10px',\n display: 'flex',\n flexDirection: 'column',\n width: '320px',\n });\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 // @ts-ignore\n this.search(evt.target.value, this.abortController);\n };\n Object.assign(this.inputElt.style, {\n padding: '10px 30px 10px 10px',\n });\n this.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 overflowY: 'auto',\n cursor: 'pointer',\n });\n this.element.appendChild(this.suggestionsElt);\n this.clearElt = document.createElement('div');\n Object.assign(this.clearElt.style, {\n display: 'none',\n position: 'absolute',\n right: '0',\n padding: '0 10px',\n fontSize: '200%',\n cursor: 'pointer',\n });\n this.clearElt.innerHTML = '×';\n this.clearElt.onclick = () => this.clear();\n this.element.appendChild(this.clearElt);\n }\n /**\n * Launch a search.\n *\n * @param {String} query 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 /**\n * To be defined in inherited class\n */\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n onSuggestionClick(suggestion) { }\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}\nexport default StopFinderControlCommon;\n",
+ "content": "import { StopsAPI } from '../../api';\nimport ControlCommon from './ControlCommon';\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 */\nclass StopFinderControlCommon extends ControlCommon {\n /**\n * Constructor.\n *\n * @param {Object} options Map options\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/tracker/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 super(options);\n const { apiParams, apiKey, url, placeholder } = options || {};\n this.apiParams = { 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 }\n deactivate() { }\n render(featureCollection) {\n const suggestions = featureCollection?.features || [];\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 const suggElt = document.createElement('div');\n suggElt.innerHTML = suggestion?.properties?.name;\n suggElt.onclick = () => {\n // @ts-ignore\n this.onSuggestionClick(suggestion);\n };\n Object.assign(suggElt.style, {\n padding: '5px 12px',\n });\n this.suggestionsElt?.appendChild(suggElt);\n });\n }\n createDefaultElement() {\n /**\n * Define a default element.\n */\n this.element = document.createElement('div');\n this.element.id = 'mbt-search';\n Object.assign(this.element.style, {\n position: 'absolute',\n top: 0,\n left: '50px',\n margin: '10px',\n display: 'flex',\n flexDirection: 'column',\n width: '320px',\n });\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 this.abortController?.abort();\n this.abortController = new AbortController();\n // @ts-ignore\n this.search(evt.target.value, this.abortController);\n };\n Object.assign(this.inputElt.style, {\n padding: '10px 30px 10px 10px',\n });\n this.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 overflowY: 'auto',\n cursor: 'pointer',\n });\n this.element.appendChild(this.suggestionsElt);\n this.clearElt = document.createElement('div');\n Object.assign(this.clearElt.style, {\n display: 'none',\n position: 'absolute',\n right: '0',\n padding: '0 10px',\n fontSize: '200%',\n cursor: 'pointer',\n });\n this.clearElt.innerHTML = '×';\n this.clearElt.onclick = () => this.clear();\n this.element.appendChild(this.clearElt);\n }\n /**\n * Launch a search.\n *\n * @param {String} query 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 /**\n * To be defined in inherited class\n */\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n onSuggestionClick(suggestion) { }\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}\nexport default StopFinderControlCommon;\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/controls/StopFinderControlCommon.js",
"access": "public",
@@ -4256,7 +4315,7 @@
"lineNumber": 1
},
{
- "__docId__": 186,
+ "__docId__": 189,
"kind": "class",
"name": "StopFinderControlCommon",
"memberof": "build/common/controls/StopFinderControlCommon.js",
@@ -4274,7 +4333,7 @@
]
},
{
- "__docId__": 187,
+ "__docId__": 190,
"kind": "constructor",
"name": "constructor",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4345,7 +4404,7 @@
]
},
{
- "__docId__": 188,
+ "__docId__": 191,
"kind": "member",
"name": "apiParams",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4357,12 +4416,12 @@
"undocument": true,
"type": {
"types": [
- "*"
+ "{\"limit\": number, ...undefined: Object}"
]
}
},
{
- "__docId__": 189,
+ "__docId__": 192,
"kind": "member",
"name": "placeholder",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4379,7 +4438,7 @@
}
},
{
- "__docId__": 190,
+ "__docId__": 193,
"kind": "member",
"name": "api",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4396,7 +4455,7 @@
}
},
{
- "__docId__": 191,
+ "__docId__": 194,
"kind": "member",
"name": "abortController",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4413,7 +4472,7 @@
}
},
{
- "__docId__": 192,
+ "__docId__": 195,
"kind": "method",
"name": "deactivate",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4429,7 +4488,7 @@
"return": null
},
{
- "__docId__": 193,
+ "__docId__": 196,
"kind": "method",
"name": "render",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4452,7 +4511,7 @@
"return": null
},
{
- "__docId__": 194,
+ "__docId__": 197,
"kind": "method",
"name": "createDefaultElement",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4462,13 +4521,13 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#createDefaultElement",
"access": "public",
"description": null,
- "lineNumber": 52,
+ "lineNumber": 51,
"undocument": true,
"params": [],
"return": null
},
{
- "__docId__": 195,
+ "__docId__": 198,
"kind": "member",
"name": "element",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4476,7 +4535,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#element",
"access": "public",
"description": "Define a default element.",
- "lineNumber": 56,
+ "lineNumber": 55,
"type": {
"types": [
"*"
@@ -4484,7 +4543,7 @@
}
},
{
- "__docId__": 196,
+ "__docId__": 199,
"kind": "member",
"name": "inputElt",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4492,7 +4551,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#inputElt",
"access": "public",
"description": null,
- "lineNumber": 68,
+ "lineNumber": 67,
"undocument": true,
"type": {
"types": [
@@ -4501,7 +4560,7 @@
}
},
{
- "__docId__": 198,
+ "__docId__": 201,
"kind": "member",
"name": "suggestionsElt",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4509,7 +4568,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#suggestionsElt",
"access": "public",
"description": null,
- "lineNumber": 84,
+ "lineNumber": 82,
"undocument": true,
"type": {
"types": [
@@ -4518,7 +4577,7 @@
}
},
{
- "__docId__": 199,
+ "__docId__": 202,
"kind": "member",
"name": "clearElt",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4526,7 +4585,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#clearElt",
"access": "public",
"description": null,
- "lineNumber": 91,
+ "lineNumber": 89,
"undocument": true,
"type": {
"types": [
@@ -4535,7 +4594,7 @@
}
},
{
- "__docId__": 200,
+ "__docId__": 203,
"kind": "method",
"name": "search",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4545,7 +4604,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#search",
"access": "public",
"description": "Launch a search.",
- "lineNumber": 111,
+ "lineNumber": 109,
"params": [
{
"nullable": null,
@@ -4578,7 +4637,7 @@
}
},
{
- "__docId__": 201,
+ "__docId__": 204,
"kind": "method",
"name": "onSuggestionClick",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4588,7 +4647,7 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#onSuggestionClick",
"access": "public",
"description": "To be defined in inherited class",
- "lineNumber": 131,
+ "lineNumber": 129,
"params": [
{
"name": "suggestion",
@@ -4600,7 +4659,7 @@
"return": null
},
{
- "__docId__": 202,
+ "__docId__": 205,
"kind": "method",
"name": "clear",
"memberof": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon",
@@ -4610,12 +4669,12 @@
"longname": "build/common/controls/StopFinderControlCommon.js~StopFinderControlCommon#clear",
"access": "public",
"description": "Clear the search field and close the control.",
- "lineNumber": 135,
+ "lineNumber": 133,
"params": [],
"return": null
},
{
- "__docId__": 203,
+ "__docId__": 206,
"kind": "file",
"name": "build/common/index.js",
"content": "export * from './utils';\nexport * from './styles';\n",
@@ -4626,10 +4685,10 @@
"lineNumber": 1
},
{
- "__docId__": 204,
+ "__docId__": 207,
"kind": "file",
"name": "build/common/layers/LayerCommon.js",
- "content": "import BaseObject from 'ol/Object';\nimport { v4 as uuid } from 'uuid';\nimport BaseEvent from 'ol/events/Event';\nimport getLayersAsFlatArray from '../utils/getLayersAsFlatArray';\n/**\n * A class representing a layer to display on map.\n *\n * @example\n * const layer = new Layer({\n * name: 'My Layer',\n * });\n *\n * @classproperty {string} key - Identifier of the layer. Must be unique.\n * @classproperty {string} name - Name of the layer\n * @classproperty {string[]} copyrights - Array of copyrights.\n * @classproperty {Layer[]} children - List of children layers.\n * @classproperty {boolean} visible - Define if the layer is currently display on the map.\n * @classproperty {boolean} disabled - Define if the layer is currently display on the map but can't be seen (extent, zoom ,data restrictions).\n * @classproperty {number} hitTolerance - Hit-detection tolerance in css pixels. Pixels inside the radius around the given position will be checked for features.\n * @classproperty {Object} properties - Custom properties.\n * @classproperty {ol/Map~Map|mapboxgl.Map} map - The map where the layer is displayed.\n */\nexport default class Layer extends BaseObject {\n /**\n * Constructor\n *\n * @param {Object} options\n * @param {string} [options.key=uuid()] Identifier of the layer. Muste be unique. Default use a generated uuid.\n * @param {string} [options.name] Name of the layer.\n * @param {string[]} [options.copyrights] Array of copyrights.\n * @param {Array} [options.children=[]] Sublayers, all child layers will have a parent property associated to this layer.\n * @param {boolean} [options.visible=true] Define if the layer is currently display on the map.\n * @param {boolean} [options.disabled=false] Define if the layer is currently display on the map but can't be seen (extent, zoom ,data restrictions).\n * @param {number} [options.hitTolerance=5] Hit-detection tolerance in css pixels. Pixels inside the radius around the given position will be checked for features.\n * @param {Object} [options.properties={}] Application-specific layer properties.\n */\n constructor(options = {}) {\n super();\n this.properties = {};\n this.options = {};\n this.defineProperties(options);\n if (options.properties) {\n this.setProperties(options.properties);\n }\n this.options = options;\n this.visible = options.visible === undefined ? true : !!options.visible;\n this.group = options.group;\n this.copyrights = options.copyrights;\n this.children = options.children;\n // Listen for group visiblity change\n // if a layer from a group is newly visible we hide the others.\n /* @ts-ignore */\n this.on(`change:visible:group`, (evt) => {\n // We hide layer of the same group\n if (this.group === evt.target.group &&\n this !== evt.target &&\n this.visible) {\n this.visible = false;\n // Propagate event to parent\n }\n else if (this.children) {\n this.children.forEach((child) => child.dispatchEvent(evt));\n }\n });\n }\n /**\n * Define layer's properties that needs custom get and set.\n *\n * @ignore\n */\n defineProperties(options = {}) {\n const { name, key, properties, hitTolerance } = Object.assign({}, options);\n const uid = uuid();\n Object.defineProperties(this, {\n /* Layer's information properties */\n name: {\n value: name,\n },\n key: {\n value: key || name || uid,\n },\n group: {\n get: () => this.get('group'),\n set: (newGroup) => {\n this.set('group', newGroup);\n },\n },\n copyrights: {\n get: () => this.get('copyrights'),\n set: (newCopyrights) => {\n const arrValue = newCopyrights && !Array.isArray(newCopyrights)\n ? [newCopyrights]\n : newCopyrights;\n this.set('copyrights', arrValue || []);\n },\n },\n // options is used for clone function.\n options: {\n value: options,\n },\n map: {\n writable: true,\n },\n /* Layer's state properties */\n visible: {\n get: () => this.get('visible'),\n set: (newVisible) => {\n if (newVisible === this.visible) {\n return;\n }\n this.set('visible', newVisible);\n if (this.visible) {\n // We make the parent visible\n if (this.parent) {\n this.parent.visible = true;\n }\n // If children doesn't contain any visible layers, we display all children.\n if (this.children &&\n !this.children.some((child) => child.visible)) {\n this.children.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.visible = true;\n });\n }\n // Warn the same group that a new layer is visible\n if (this.parent && this.group) {\n // We search for the higher parent then it will dispatch to all the tree.\n let higherParent = this.parent;\n while (higherParent.parent) {\n higherParent = higherParent.parent;\n }\n const evt = new BaseEvent(`change:visible:group`);\n evt.target = this;\n higherParent.dispatchEvent(evt);\n }\n }\n else if (!this.visible) {\n // We hide all the children\n if (this.children) {\n this.children.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.visible = false;\n });\n }\n // If the parent has no more visible child we also hide it.\n if (this.parent &&\n this.parent.visible &&\n this.parent.children &&\n !this.parent.children.find((child) => child.visible)) {\n this.parent.visible = false;\n }\n }\n },\n },\n disabled: {\n get: () => this.get('disabled'),\n set: (newValue) => {\n this.set('disabled', newValue);\n },\n },\n /* Layer's hierarchy properties */\n parent: {\n value: null,\n writable: true,\n },\n children: {\n get: () => this.get('children') || [],\n set: (newValue) => {\n (this.children || []).forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.parent = undefined;\n });\n if (Array.isArray(newValue)) {\n newValue.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.parent = this;\n });\n }\n this.set('children', newValue || []);\n },\n },\n /* Layer's query properties */\n hitTolerance: {\n value: hitTolerance || 5,\n writable: true,\n },\n /* Custom app specific properties */\n properties: {\n value: Object.assign({}, (properties || {})),\n },\n });\n }\n /**\n * Initialize the layer with the map passed in parameters.\n *\n * @param {ol/Map~Map|mapboxgl.Map} map A map.\n */\n attachToMap(map) {\n this.detachFromMap();\n /** @ignore */\n this.map = map;\n if (this.children) {\n this.children.forEach((child) => {\n child.attachToMap(map);\n });\n }\n }\n /**\n * Terminate what was initialized in init function. Remove layer, events...\n */\n // eslint-disable-next-line class-methods-use-this\n detachFromMap() {\n /** @ignore */\n this.map = undefined;\n }\n /**\n * Request feature information for a given coordinate.\n * This function must be implemented by inheriting layers.\n *\n * @param {ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {Object} options Some options. See child classes to see which are supported.\n * @return {Promise} An empty response.\n */\n // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars\n getFeatureInfoAtCoordinate(coordinate, \n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n options) {\n // eslint-disable-next-line no-console\n console.error('getFeatureInfoAtCoordinate must be implemented by inheriting layers', this.key);\n // This layer returns no feature info.\n // The function is implemented by inheriting layers.\n return Promise.resolve({\n layer: this,\n features: [],\n coordinate,\n });\n }\n /**\n * Return the an array containing all the descendants of the layer in a flat array. Including the current layer.\n */\n flat() {\n return getLayersAsFlatArray(this);\n }\n}\n",
+ "content": "import BaseObject from 'ol/Object';\nimport { v4 as uuid } from 'uuid';\nimport BaseEvent from 'ol/events/Event';\nimport getLayersAsFlatArray from '../utils/getLayersAsFlatArray';\n/**\n * A class representing a layer to display on map.\n *\n * @example\n * const layer = new Layer({\n * name: 'My Layer',\n * });\n *\n * @classproperty {string} key - Identifier of the layer. Must be unique.\n * @classproperty {string} name - Name of the layer\n * @classproperty {string[]} copyrights - Array of copyrights.\n * @classproperty {Layer[]} children - List of children layers.\n * @classproperty {boolean} visible - Define if the layer is currently display on the map.\n * @classproperty {boolean} disabled - Define if the layer is currently display on the map but can't be seen (extent, zoom ,data restrictions).\n * @classproperty {number} hitTolerance - Hit-detection tolerance in css pixels. Pixels inside the radius around the given position will be checked for features.\n * @classproperty {Object} properties - Custom properties.\n * @classproperty {ol/Map~Map|mapboxgl.Map} map - The map where the layer is displayed.\n */\nexport default class Layer extends BaseObject {\n /**\n * Constructor\n *\n * @param {Object} options\n * @param {string} [options.key=uuid()] Identifier of the layer. Muste be unique. Default use a generated uuid.\n * @param {string} [options.name] Name of the layer.\n * @param {string[]} [options.copyrights] Array of copyrights.\n * @param {Array} [options.children=[]] Sublayers, all child layers will have a parent property associated to this layer.\n * @param {boolean} [options.visible=true] Define if the layer is currently display on the map.\n * @param {boolean} [options.disabled=false] Define if the layer is currently display on the map but can't be seen (extent, zoom ,data restrictions).\n * @param {number} [options.hitTolerance=5] Hit-detection tolerance in css pixels. Pixels inside the radius around the given position will be checked for features.\n * @param {Object} [options.properties={}] Application-specific layer properties.\n */\n constructor(options = {}) {\n super();\n this.properties = {};\n this.options = {};\n this.defineProperties(options);\n if (options.properties) {\n this.setProperties(options.properties);\n }\n this.options = options;\n this.visible = options.visible === undefined ? true : !!options.visible;\n this.group = options.group;\n this.copyrights = options.copyrights;\n this.children = options.children;\n // Listen for group visiblity change\n // if a layer from a group is newly visible we hide the others.\n /* @ts-ignore */\n this.on(`change:visible:group`, (evt) => {\n // We hide layer of the same group\n if (this.group === evt.target.group &&\n this !== evt.target &&\n this.visible) {\n this.visible = false;\n // Propagate event to parent\n }\n else if (this.children) {\n this.children.forEach((child) => child.dispatchEvent(evt));\n }\n });\n }\n /**\n * Define layer's properties that needs custom get and set.\n *\n * @ignore\n */\n defineProperties(options = {}) {\n const { name, key, properties, hitTolerance } = {\n ...options,\n };\n const uid = uuid();\n Object.defineProperties(this, {\n /* Layer's information properties */\n name: {\n value: name,\n },\n key: {\n value: key || name || uid,\n },\n group: {\n get: () => this.get('group'),\n set: (newGroup) => {\n this.set('group', newGroup);\n },\n },\n copyrights: {\n get: () => this.get('copyrights'),\n set: (newCopyrights) => {\n const arrValue = newCopyrights && !Array.isArray(newCopyrights)\n ? [newCopyrights]\n : newCopyrights;\n this.set('copyrights', arrValue || []);\n },\n },\n // options is used for clone function.\n options: {\n value: options,\n },\n map: {\n writable: true,\n },\n /* Layer's state properties */\n visible: {\n get: () => this.get('visible'),\n set: (newVisible) => {\n if (newVisible === this.visible) {\n return;\n }\n this.set('visible', newVisible);\n if (this.visible) {\n // We make the parent visible\n if (this.parent) {\n this.parent.visible = true;\n }\n // If children doesn't contain any visible layers, we display all children.\n if (this.children &&\n !this.children.some((child) => child.visible)) {\n this.children.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.visible = true;\n });\n }\n // Warn the same group that a new layer is visible\n if (this.parent && this.group) {\n // We search for the higher parent then it will dispatch to all the tree.\n let higherParent = this.parent;\n while (higherParent.parent) {\n higherParent = higherParent.parent;\n }\n const evt = new BaseEvent(`change:visible:group`);\n evt.target = this;\n higherParent.dispatchEvent(evt);\n }\n }\n else if (!this.visible) {\n // We hide all the children\n if (this.children) {\n this.children.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.visible = false;\n });\n }\n // If the parent has no more visible child we also hide it.\n if (this.parent &&\n this.parent.visible &&\n this.parent.children &&\n !this.parent.children.find((child) => child.visible)) {\n this.parent.visible = false;\n }\n }\n },\n },\n disabled: {\n get: () => this.get('disabled'),\n set: (newValue) => {\n this.set('disabled', newValue);\n },\n },\n /* Layer's hierarchy properties */\n parent: {\n value: null,\n writable: true,\n },\n children: {\n get: () => this.get('children') || [],\n set: (newValue) => {\n (this.children || []).forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.parent = undefined;\n });\n if (Array.isArray(newValue)) {\n newValue.forEach((child) => {\n // eslint-disable-next-line no-param-reassign\n child.parent = this;\n });\n }\n this.set('children', newValue || []);\n },\n },\n /* Layer's query properties */\n hitTolerance: {\n value: hitTolerance || 5,\n writable: true,\n },\n /* Custom app specific properties */\n properties: {\n value: { ...(properties || {}) },\n },\n });\n }\n /**\n * Initialize the layer with the map passed in parameters.\n *\n * @param {ol/Map~Map|mapboxgl.Map} map A map.\n */\n attachToMap(map) {\n this.detachFromMap();\n /** @ignore */\n this.map = map;\n if (this.children) {\n this.children.forEach((child) => {\n child.attachToMap(map);\n });\n }\n }\n /**\n * Terminate what was initialized in init function. Remove layer, events...\n */\n // eslint-disable-next-line class-methods-use-this\n detachFromMap() {\n /** @ignore */\n this.map = undefined;\n }\n /**\n * Request feature information for a given coordinate.\n * This function must be implemented by inheriting layers.\n *\n * @param {ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {Object} options Some options. See child classes to see which are supported.\n * @return {Promise} An empty response.\n */\n // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars\n getFeatureInfoAtCoordinate(coordinate, \n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n options) {\n // eslint-disable-next-line no-console\n console.error('getFeatureInfoAtCoordinate must be implemented by inheriting layers', this.key);\n // This layer returns no feature info.\n // The function is implemented by inheriting layers.\n return Promise.resolve({\n layer: this,\n features: [],\n coordinate,\n });\n }\n /**\n * Return the an array containing all the descendants of the layer in a flat array. Including the current layer.\n */\n flat() {\n return getLayersAsFlatArray(this);\n }\n}\n",
"static": true,
"longname": "/home/olivier/GIT/mobility-toolbox-js/build/common/layers/LayerCommon.js",
"access": "public",
@@ -4637,7 +4696,7 @@
"lineNumber": 1
},
{
- "__docId__": 205,
+ "__docId__": 208,
"kind": "class",
"name": "Layer",
"memberof": "build/common/layers/LayerCommon.js",
@@ -4696,7 +4755,7 @@
]
},
{
- "__docId__": 206,
+ "__docId__": 209,
"kind": "constructor",
"name": "constructor",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4813,7 +4872,7 @@
]
},
{
- "__docId__": 207,
+ "__docId__": 210,
"kind": "member",
"name": "properties",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4830,7 +4889,7 @@
}
},
{
- "__docId__": 208,
+ "__docId__": 211,
"kind": "member",
"name": "options",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4847,7 +4906,7 @@
}
},
{
- "__docId__": 210,
+ "__docId__": 213,
"kind": "member",
"name": "visible",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4864,7 +4923,7 @@
}
},
{
- "__docId__": 211,
+ "__docId__": 214,
"kind": "member",
"name": "group",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4881,7 +4940,7 @@
}
},
{
- "__docId__": 212,
+ "__docId__": 215,
"kind": "member",
"name": "copyrights",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4898,7 +4957,7 @@
}
},
{
- "__docId__": 213,
+ "__docId__": 216,
"kind": "member",
"name": "children",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4915,7 +4974,7 @@
}
},
{
- "__docId__": 215,
+ "__docId__": 218,
"kind": "method",
"name": "defineProperties",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4941,7 +5000,7 @@
"return": null
},
{
- "__docId__": 216,
+ "__docId__": 219,
"kind": "method",
"name": "attachToMap",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4951,7 +5010,7 @@
"longname": "build/common/layers/LayerCommon.js~Layer#attachToMap",
"access": "public",
"description": "Initialize the layer with the map passed in parameters.",
- "lineNumber": 198,
+ "lineNumber": 200,
"params": [
{
"nullable": null,
@@ -4968,7 +5027,7 @@
"return": null
},
{
- "__docId__": 217,
+ "__docId__": 220,
"kind": "member",
"name": "map",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4976,7 +5035,7 @@
"longname": "build/common/layers/LayerCommon.js~Layer#map",
"access": "public",
"description": null,
- "lineNumber": 201,
+ "lineNumber": 203,
"ignore": true,
"type": {
"types": [
@@ -4985,7 +5044,7 @@
}
},
{
- "__docId__": 218,
+ "__docId__": 221,
"kind": "method",
"name": "detachFromMap",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -4995,12 +5054,12 @@
"longname": "build/common/layers/LayerCommon.js~Layer#detachFromMap",
"access": "public",
"description": "Terminate what was initialized in init function. Remove layer, events...",
- "lineNumber": 212,
+ "lineNumber": 214,
"params": [],
"return": null
},
{
- "__docId__": 220,
+ "__docId__": 223,
"kind": "method",
"name": "getFeatureInfoAtCoordinate",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -5010,7 +5069,7 @@
"longname": "build/common/layers/LayerCommon.js~Layer#getFeatureInfoAtCoordinate",
"access": "public",
"description": "Request feature information for a given coordinate.\nThis function must be implemented by inheriting layers.",
- "lineNumber": 225,
+ "lineNumber": 227,
"params": [
{
"nullable": null,
@@ -5043,7 +5102,7 @@
}
},
{
- "__docId__": 221,
+ "__docId__": 224,
"kind": "method",
"name": "flat",
"memberof": "build/common/layers/LayerCommon.js~Layer",
@@ -5053,7 +5112,7 @@
"longname": "build/common/layers/LayerCommon.js~Layer#flat",
"access": "public",
"description": "Return the an array containing all the descendants of the layer in a flat array. Including the current layer.",
- "lineNumber": 241,
+ "lineNumber": 243,
"params": [],
"return": {
"types": [
@@ -5062,10 +5121,10 @@
}
},
{
- "__docId__": 222,
+ "__docId__": 225,
"kind": "file",
"name": "build/common/mixins/RealtimeLayerMixin.js",
- "content": "/* eslint-disable no-empty-function,@typescript-eslint/no-empty-function */\n/* eslint-disable no-useless-constructor,@typescript-eslint/no-useless-constructor */\n/* eslint-disable no-unused-vars,@typescript-eslint/no-unused-vars */\n/* eslint-disable class-methods-use-this */\n/* eslint-disable max-classes-per-file */\nimport { buffer, containsCoordinate, intersects } from 'ol/extent';\nimport { unByKey } from 'ol/Observable';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport debounce from 'lodash.debounce';\nimport throttle from 'lodash.throttle';\nimport { fromLonLat } from 'ol/proj';\nimport realtimeDefaultStyle from '../styles/realtimeDefaultStyle';\nimport { RealtimeAPI, RealtimeModes } from '../../api';\nimport renderTrajectories from '../utils/renderTrajectories';\nimport * as realtimeConfig from '../utils/realtimeConfig';\n/**\n * RealtimeLayerInterface.\n */\nexport class RealtimeLayerInterface {\n /**\n * Start the clock.\n */\n start() { }\n /**\n * Stop the clock.\n */\n stop() { }\n /**\n * Set the Realtime api's bbox.\n *\n * @param {Array} extent Extent to request, [minX, minY, maxX, maxY, zoom].\n * @param {number} zoom Zoom level to request. Must be an integer.\n */\n setBbox(extent, zoom) { }\n /**\n * Render the trajectories\n */\n renderTrajectories() { }\n /**\n * Request the stopSequence and the fullTrajectory informations for a vehicle.\n *\n * @param {string} id The vehicle identifier (the train_id property).\n * @param {RealtimeMode} mode The mode to request. If not defined, the layer´s mode propetrty will be used.\n * @return {Promise<{stopSequence: StopSequence, fullTrajectory: FullTrajectory>} A promise that will be resolved with the trajectory informations.\n */\n getTrajectoryInfos(id, mode) { }\n}\n/**\n * Mixin for RealtimeLayerInterface.\n *\n * @param {Class} Base A class to extend with {RealtimeLayerInterface} functionnalities.\n * @return {Class} A class that implements {RealtimeLayerInterface} class and extends Base;\n * @private\n */\nfunction RealtimeLayerMixin(Base) {\n // @ts-ignore\n return class Mixin extends Base {\n constructor(options) {\n super(Object.assign({ hitTolerance: 10 }, options));\n this.debug = options.debug || false;\n this.mode = options.mode || RealtimeModes.TOPOGRAPHIC;\n this.api = options.api || new RealtimeAPI(options);\n this.tenant = options.tenant || ''; // sbb,sbh or sbm\n this.minZoomInterpolation = options.minZoomInterpolation || 8; // Min zoom level from which trains positions are not interpolated.\n this.format = new GeoJSON();\n // MOTs by zoom\n const allMots = [\n 'tram',\n 'subway',\n 'rail',\n 'bus',\n 'ferry',\n 'cablecar',\n 'gondola',\n 'funicular',\n 'coach',\n ];\n const onlyRail = ['rail'];\n const withoutCable = ['tram', 'subway', 'rail', 'bus'];\n // Server will block non train before zoom 9\n this.motsByZoom = options.motsByZoom || [\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n onlyRail,\n withoutCable,\n withoutCable,\n allMots,\n allMots,\n allMots,\n allMots,\n ];\n this.getMotsByZoom = (zoom) => {\n return ((options.getMotsByZoom &&\n options.getMotsByZoom(zoom, this.motsByZoom)) ||\n this.motsByZoom[zoom] ||\n this.motsByZoom[this.motsByZoom.length - 1]);\n };\n // Generalization levels by zoom\n this.generalizationLevelByZoom = options.generalizationLevelByZoom || [\n 5, 5, 5, 5, 5, 5, 5, 5, 10, 30, 30, 100, 100, 100,\n ];\n this.getGeneralizationLevelByZoom = (zoom) => {\n return ((options.getGeneralizationLevelByZoom &&\n options.getGeneralizationLevelByZoom(zoom, this.generalizationLevelByZoom)) ||\n this.generalizationLevelByZoom[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 return ((options.getRenderTimeIntervalByZoom &&\n options.getRenderTimeIntervalByZoom(zoom, this.renderTimeIntervalByZoom)) ||\n 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, trailing: true, maxWait: 5000 });\n // Bind callbacks\n this.onFeatureHover = this.onFeatureHover.bind(this);\n this.onFeatureClick = this.onFeatureClick.bind(this);\n this.renderTrajectoriesInternal =\n this.renderTrajectoriesInternal.bind(this);\n this.onTrajectoryMessage = this.onTrajectoryMessage.bind(this);\n this.onDeleteTrajectoryMessage =\n this.onDeleteTrajectoryMessage.bind(this);\n this.onDocumentVisibilityChange =\n this.onDocumentVisibilityChange.bind(this);\n }\n /**\n * Define layer's properties.\n *\n * @ignore\n */\n defineProperties(options) {\n const { style, speed, pixelRatio, hoverVehicleId, selectedVehicleId, filter, sort, time, live, canvas, styleOptions, mode, } = options;\n let currCanvas = canvas;\n let currSpeed = speed || 1;\n let currTime = time || new Date();\n let currMode = mode || RealtimeModes.TOPOGRAPHIC;\n let currStyle = style || realtimeDefaultStyle;\n super.defineProperties(options);\n Object.defineProperties(this, {\n isTrackerLayer: { value: true },\n canvas: {\n get: () => {\n if (!currCanvas) {\n currCanvas = document.createElement('canvas');\n }\n return currCanvas;\n },\n set: (cnvas) => {\n currCanvas = cnvas;\n },\n },\n /**\n * Style function used to render a vehicle.\n */\n mode: {\n get: () => currMode,\n set: (newMode) => {\n var _a, _b;\n if (newMode === currMode) {\n return;\n }\n currMode = 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 },\n /**\n * Style function used to render a vehicle.\n */\n style: {\n get: () => currStyle,\n set: (newStyle) => {\n currStyle = newStyle;\n // @ts-ignore function without parameters is defined in subclasses\n this.renderTrajectories();\n },\n },\n /**\n * Custom options to pass as last parameter of the style function.\n */\n styleOptions: {\n value: Object.assign(Object.assign({}, realtimeConfig), (styleOptions || {})),\n },\n /**\n * Speed of the wheel of time.\n * If live property is true. The speed is ignored.\n */\n speed: {\n get: () => currSpeed,\n set: (newSpeed) => {\n currSpeed = newSpeed;\n this.start();\n },\n },\n /**\n * Function to filter which vehicles to display.\n */\n filter: {\n value: filter,\n writable: true,\n },\n /**\n * Function to sort the vehicles to display.\n */\n sort: {\n value: sort,\n writable: true,\n },\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 live: {\n value: live === false ? live : true,\n writable: true,\n },\n /**\n * Time used to display the trajectories. Can be a Date or a number in ms representing a Date.\n * If live property is true. The setter does nothing.\n */\n time: {\n get: () => currTime,\n set: (newTime) => {\n currTime = newTime && newTime.getTime ? newTime : new Date(newTime);\n // @ts-ignore function without parameters is defined in subclasses\n this.renderTrajectories();\n },\n },\n /**\n * Keep track of which trajectories are stored.\n */\n trajectories: {\n value: {},\n writable: true,\n },\n /**\n * Id of the hovered vehicle.\n */\n hoverVehicleId: {\n value: hoverVehicleId,\n writable: true,\n },\n /**\n * Id of the selected vehicle.\n */\n selectedVehicleId: {\n value: selectedVehicleId,\n writable: true,\n },\n /**\n * Id of the selected vehicle.\n */\n pixelRatio: {\n value: pixelRatio ||\n (typeof window !== 'undefined' ? window.devicePixelRatio : 1),\n writable: true,\n },\n /**\n * If true, encapsulates the renderTrajectories calls in a requestAnimationFrame.\n */\n useRequestAnimationFrame: {\n value: options.useRequestAnimationFrame || false,\n writable: true,\n },\n /**\n * If true, encapsulates the renderTrajectories calls in a throttle function. Default to true.\n */\n useThrottle: {\n value: options.useThrottle !== false,\n writable: true,\n },\n /**\n * If true, encapsulates the renderTrajectories calls in a debounce function.\n */\n useDebounce: {\n value: options.useDebounce || false,\n writable: true,\n },\n /**\n * Debug properties.\n */\n // Not used anymore, but could be useful for debugging.\n // showVehicleTraj: {\n // value:\n // options.showVehicleTraj !== undefined\n // ? options.showVehicleTraj\n // : true,\n // writable: true,\n // },\n });\n }\n attachToMap(map) {\n super.attachToMap(map);\n // If the layer is visible we start the rendering clock\n if (this.visible) {\n this.start();\n }\n // On change of visibility we start/stop the rendering clock\n this.visibilityRef = this.on('change:visible', (evt) => {\n if (evt.target.visible) {\n this.start();\n }\n else {\n this.stop();\n }\n });\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 unByKey(this.visibilityRef);\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 super.detachFromMap();\n }\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 // @ts-ignore function without parameters must be define in subclasses\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 if (this.isUpdateBboxOnMoveEnd) {\n // Update the bbox on each move end\n // @ts-ignore function without parameters defined by subclasses\n this.setBbox();\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 }\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 /**\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.map || !this.trajectories) {\n return false;\n }\n const time = this.live ? Date.now() : (_a = this.time) === null || _a === void 0 ? void 0 : _a.getTime();\n const trajectories = Object.values(this.trajectories);\n // console.time('sort');\n if (this.sort) {\n // @ts-ignore\n trajectories.sort(this.sort);\n }\n // console.timeEnd('sort');\n if (!this.canvas || !this.style) {\n return true;\n }\n // console.time('render');\n this.renderState = renderTrajectories(this.canvas, trajectories, this.style, Object.assign(Object.assign({}, viewState), { pixelRatio: this.pixelRatio || 1, time }), Object.assign({ filter: this.filter, noInterpolate: (viewState.zoom || 0) < this.minZoomInterpolation\n ? true\n : noInterpolate, hoverVehicleId: this.hoverVehicleId, selectedVehicleId: this.selectedVehicleId }, this.styleOptions));\n // console.timeEnd('render');\n return true;\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 {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 renderTrajectories(viewState, noInterpolate) {\n if (this.requestId) {\n cancelAnimationFrame(this.requestId);\n this.requestId = undefined;\n }\n if (!viewState) {\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 setBbox(extent, zoom) {\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]], extent, zoom);\n }\n }\n if (!extent) {\n return;\n }\n const bbox = [...extent];\n if (this.isUpdateBboxOnMoveEnd && zoom) {\n bbox.push(zoom);\n if (this.tenant) {\n bbox.push(`tenant=${this.tenant}`);\n }\n /* @ignore */\n this.generalizationLevel = this.getGeneralizationLevelByZoom(zoom);\n if (this.generalizationLevel) {\n bbox.push(`gen=${this.generalizationLevel}`);\n }\n /* @ignore */\n this.mots = this.getMotsByZoom(zoom);\n if (this.mots) {\n bbox.push(`mots=${this.mots}`);\n }\n }\n this.api.bbox = bbox;\n }\n /**\n * Get the duration before the next update depending on zoom level.\n *\n * @private\n * @param {number} zoom\n */\n getRefreshTimeInMs(zoom = 0) {\n var _a;\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, trailing: true, maxWait: 5000 });\n }\n if ((_a = this.api) === null || _a === void 0 ? void 0 : _a.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