mobility-toolbox-js 3.0.0-beta.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +11 -3
  2. package/api/HttpAPI.d.ts +5 -16
  3. package/api/HttpAPI.js +1 -14
  4. package/api/RealtimeAPI.d.ts +188 -143
  5. package/api/RealtimeAPI.js +265 -206
  6. package/api/RoutingAPI.d.ts +21 -11
  7. package/api/RoutingAPI.js +17 -7
  8. package/api/StopsAPI.d.ts +20 -14
  9. package/api/StopsAPI.js +17 -11
  10. package/api/WebSocketAPI.d.ts +60 -66
  11. package/api/WebSocketAPI.js +164 -165
  12. package/api/index.js +1 -1
  13. package/api/typedefs.d.ts +0 -102
  14. package/api/typedefs.js +27 -42
  15. package/common/controls/StopFinderControlCommon.d.ts +13 -13
  16. package/common/controls/StopFinderControlCommon.js +32 -32
  17. package/common/index.d.ts +1 -1
  18. package/common/index.js +1 -1
  19. package/common/styles/realtimeDefaultStyle.js +6 -11
  20. package/common/styles/realtimeHeadingStyle.js +5 -10
  21. package/common/styles/realtimeSimpleStyle.d.ts +0 -1
  22. package/common/styles/realtimeSimpleStyle.js +0 -1
  23. package/common/typedefs.d.ts +11 -121
  24. package/common/typedefs.js +6 -31
  25. package/common/utils/RealtimeEngine.d.ts +214 -0
  26. package/common/utils/RealtimeEngine.js +554 -0
  27. package/common/utils/compareDepartures.d.ts +2 -2
  28. package/common/utils/compareDepartures.js +2 -2
  29. package/common/utils/debounceWebsocketMessages.d.ts +1 -1
  30. package/common/utils/getLayersAsFlatArray.d.ts +0 -1
  31. package/common/utils/getLayersAsFlatArray.js +0 -1
  32. package/common/utils/getMapGlCopyrights.d.ts +1 -1
  33. package/common/utils/getMapGlCopyrights.js +3 -3
  34. package/common/utils/getRealtimeModeSuffix.d.ts +1 -0
  35. package/common/utils/getRealtimeModeSuffix.js +1 -0
  36. package/common/utils/getVehiclePosition.d.ts +5 -4
  37. package/common/utils/getVehiclePosition.js +6 -3
  38. package/common/utils/realtimeConfig.d.ts +1 -1
  39. package/common/utils/realtimeConfig.js +0 -1
  40. package/common/utils/renderTrajectories.d.ts +2 -1
  41. package/common/utils/renderTrajectories.js +7 -6
  42. package/common/utils/sortAndFilterDepartures.d.ts +2 -1
  43. package/common/utils/sortAndFilterDepartures.js +2 -1
  44. package/common/utils/sortByDelay.d.ts +2 -2
  45. package/common/utils/sortByDelay.js +5 -1
  46. package/maplibre/controls/CopyrightControl.d.ts +9 -6
  47. package/maplibre/controls/CopyrightControl.js +11 -8
  48. package/maplibre/layers/Layer.d.ts +8 -7
  49. package/maplibre/layers/Layer.js +2 -3
  50. package/maplibre/layers/RealtimeLayer.d.ts +82 -118
  51. package/maplibre/layers/RealtimeLayer.js +154 -118
  52. package/maplibre/utils/getSourceCoordinates.d.ts +1 -0
  53. package/maplibre/utils/getSourceCoordinates.js +6 -5
  54. package/mbt.js +14611 -14591
  55. package/mbt.js.map +4 -4
  56. package/mbt.min.js +75 -75
  57. package/mbt.min.js.map +4 -4
  58. package/ol/controls/CopyrightControl.d.ts +13 -5
  59. package/ol/controls/CopyrightControl.js +13 -5
  60. package/ol/controls/RoutingControl.d.ts +105 -101
  61. package/ol/controls/RoutingControl.js +250 -264
  62. package/ol/controls/StopFinderControl.d.ts +24 -5
  63. package/ol/controls/StopFinderControl.js +24 -5
  64. package/ol/layers/Layer.d.ts +26 -0
  65. package/ol/layers/Layer.js +39 -0
  66. package/ol/layers/MaplibreLayer.d.ts +56 -28
  67. package/ol/layers/MaplibreLayer.js +154 -31
  68. package/ol/layers/MaplibreStyleLayer.d.ts +71 -149
  69. package/ol/layers/MaplibreStyleLayer.js +281 -210
  70. package/ol/layers/RealtimeLayer.d.ts +95 -230
  71. package/ol/layers/RealtimeLayer.js +209 -211
  72. package/ol/layers/VectorLayer.d.ts +17 -0
  73. package/ol/layers/VectorLayer.js +33 -0
  74. package/ol/layers/index.d.ts +2 -0
  75. package/ol/layers/index.js +3 -0
  76. package/ol/renderers/MaplibreLayerRenderer.d.ts +0 -20
  77. package/ol/renderers/MaplibreLayerRenderer.js +142 -114
  78. package/ol/renderers/MaplibreStyleLayerRenderer.d.ts +6 -6
  79. package/ol/renderers/MaplibreStyleLayerRenderer.js +20 -23
  80. package/ol/renderers/RealtimeLayerRenderer.d.ts +7 -7
  81. package/ol/renderers/RealtimeLayerRenderer.js +46 -66
  82. package/ol/styles/fullTrajectoryDelayStyle.js +5 -7
  83. package/ol/styles/fullTrajectoryStyle.d.ts +1 -2
  84. package/ol/styles/fullTrajectoryStyle.js +5 -7
  85. package/ol/styles/routingStyle.d.ts +0 -1
  86. package/ol/styles/routingStyle.js +13 -10
  87. package/ol/utils/defineDeprecatedProperties.d.ts +10 -0
  88. package/ol/utils/defineDeprecatedProperties.js +180 -0
  89. package/ol/utils/getFeatureInfoAtCoordinate.d.ts +1 -1
  90. package/ol/utils/getFeatureInfoAtCoordinate.js +11 -17
  91. package/package.json +44 -44
  92. package/setupTests.js +17 -4
  93. package/types/common.d.ts +53 -69
  94. package/types/index.d.ts +1 -1
  95. package/types/realtime.d.ts +98 -95
  96. package/types/routing.d.ts +60 -60
  97. package/types/stops.d.ts +62 -62
  98. package/common/mixins/RealtimeLayerMixin.d.ts +0 -273
  99. package/common/mixins/RealtimeLayerMixin.js +0 -743
  100. package/ol/layers/MapGlLayer.d.ts +0 -144
  101. package/ol/layers/MapGlLayer.js +0 -144
  102. package/ol/mixins/MobilityLayerMixin.d.ts +0 -98
  103. package/ol/mixins/MobilityLayerMixin.js +0 -6
  104. package/ol/mixins/PropertiesLayerMixin.d.ts +0 -127
  105. package/ol/mixins/PropertiesLayerMixin.js +0 -143
@@ -1,15 +1,15 @@
1
1
  import { Feature } from 'ol';
2
+ import Control from 'ol/control/Control';
3
+ import { click } from 'ol/events/condition';
4
+ import BaseEvent from 'ol/events/Event';
5
+ import { buffer } from 'ol/extent';
6
+ import { GeoJSON } from 'ol/format';
2
7
  import { LineString, Point } from 'ol/geom';
3
8
  import { Modify } from 'ol/interaction';
9
+ import VectorLayer from 'ol/layer/Vector';
4
10
  import { unByKey } from 'ol/Observable';
5
- import { click } from 'ol/events/condition';
6
- import { GeoJSON } from 'ol/format';
7
- import { buffer } from 'ol/extent';
8
11
  import { fromLonLat, toLonLat } from 'ol/proj';
9
- import BaseEvent from 'ol/events/Event';
10
- import VectorLayer from 'ol/layer/Vector';
11
12
  import VectorSource from 'ol/source/Vector';
12
- import Control from 'ol/control/Control';
13
13
  import { RoutingAPI } from '../../api';
14
14
  // Examples for a single hop:
15
15
  // basel sbb a station named "basel sbb"
@@ -18,27 +18,22 @@ import { RoutingAPI } from '../../api';
18
18
  // @47.37811,8.53935 a station at position 47.37811, 8.53935
19
19
  // @47.37811,8.53935$4 track 4 in a station at position 47.37811, 8.53935
20
20
  // zürich hb@47.37811,8.53935$8 track 8 in station "Zürich HB" at position 47.37811, 8.53935
21
- /** @private */
22
21
  const REGEX_VIA_POINT = /^([^@$!\n]*)(@?([\d.]+),([\d.]+))?(\$?([a-zA-Z0-9]{0,2}))$/;
23
22
  // Examples for a single hop:
24
23
  //
25
24
  // 47.37811,8.53935 a position 47.37811, 8.53935
26
- /** @private */
27
25
  const REGEX_VIA_POINT_COORD = /^([\d.]+),([\d.]+)$/;
28
26
  // Examples for a single hop:
29
27
  //
30
28
  // !8596126 a station with id 8596126
31
29
  // !8596126$4 a station with id 8596126
32
- /** @private */
33
30
  const REGEX_VIA_POINT_STATION_ID = /^!([^$]*)(\$?([a-zA-Z0-9]{0,2}))$/;
34
- /** @private */
35
31
  const STOP_FETCH_ABORT_CONTROLLER_KEY = 'stop-fetch';
36
- /** @private */
37
32
  const getFlatCoordinatesFromSegments = (segmentArray) => {
38
33
  const coords = [];
39
34
  segmentArray.forEach((seg) => {
40
35
  var _a;
41
- // @ts-ignore
36
+ // @ts-expect-error missing type
42
37
  const coordArr = (_a = seg.getGeometry()) === null || _a === void 0 ? void 0 : _a.getCoordinates();
43
38
  if (coordArr === null || coordArr === void 0 ? void 0 : coordArr.length) {
44
39
  coords.push(...coordArr);
@@ -47,7 +42,8 @@ const getFlatCoordinatesFromSegments = (segmentArray) => {
47
42
  return coords;
48
43
  };
49
44
  /**
50
- * Display a route of a specified mean of transport.
45
+ * This OpenLayers control allows the user to add and modifiy via points to
46
+ * a map and request a route from the [geOps Routing API](https://developer.geops.io/apis/routing/).
51
47
  *
52
48
  * @example
53
49
  * import { Map } from 'ol';
@@ -59,96 +55,68 @@ const getFlatCoordinatesFromSegments = (segmentArray) => {
59
55
  *
60
56
  * const control = new RoutingControl();
61
57
  *
62
- * control.attachToMap(map)
58
+ * map.addControl(control);
63
59
  *
64
- * @classproperty {string} apiKey - Key used for RoutingApi requests.
65
- * @classproperty {string} stopsApiKey - Key used for Stop lookup requests (defaults to apiKey).
66
- * @classproperty {string} stopsApiUrl - Url used for Stop lookup requests (defaults to https://api.geops.io/stops/v1/lookup/).
67
- * @classproperty {Array.<Array<graph="osm", minZoom=0, maxZoom=99>>} graphs - Array of routing graphs and min/max zoom levels. If you use the control in combination with the [geOps Maps API](https://developer.geops.io/apis/maps/), you may want to use the optimal level of generalizations: "[['gen4', 0, 8], ['gen3', 8, 9], ['gen2', 9, 11], ['gen1', 11, 13], ['osm', 13, 99]]"
68
60
  * @classproperty {string} mot - Mean of transport to be used for routing.
69
- * @classproperty {object} routingApiParams - object of additional parameters to pass to the routing api request.
70
- * @classproperty {object} snapToClosestStation - If true, the routing will snap the coordinate to the closest station. Default to false.
71
- * @classproperty {boolean} useRawViaPoints - Experimental property. Wen true, it allows the user to add via points using different kind of string. See "via" parameter defined by the [geOps Routing API](https://developer.geops.io/apis/routing/). Default to false, only array of coordinates and station's id are supported as via points.
72
61
  * @classproperty {VectorLayer} routingLayer - Layer for adding route features.
73
- * @classproperty {function} onRouteError - Callback on error.
74
62
  * @classproperty {boolean} loading - True if the control is requesting the backend.
63
+ *
75
64
  * @see <a href="/example/ol-routing">Openlayers routing example</a>
76
65
  *
77
- * @extends {Control}
78
- * @implements {RoutingInterface}
66
+ * @extends {ol/control/Control~Control}
67
+ *
79
68
  * @public
80
69
  */
81
70
  class RoutingControl extends Control {
82
- get active() {
83
- return this.get('active');
84
- }
85
- set active(newValue) {
86
- this.set('active', newValue);
87
- }
88
- get loading() {
89
- return this.get('loading');
90
- }
91
- set loading(newValue) {
92
- this.set('loading', newValue);
93
- }
94
- get modify() {
95
- return this.get('modify');
96
- }
97
- set modify(newValue) {
98
- this.set('modify', newValue);
99
- }
100
- get mot() {
101
- return this.get('mot');
102
- }
103
- set mot(newValue) {
104
- this.set('mot', newValue);
105
- }
71
+ /**
72
+ * Constructor.
73
+ *
74
+ * @param {Object} options
75
+ * @param {string} options.apiKey Access key for [geOps APIs](https://developer.geops.io/).
76
+ * @param {Object} options.apiParams Request parameters. See [geOps Routing API documentation](https://developer.geops.io/apis/routing/).
77
+ * @param {Array.<Array<graph="osm", minZoom=0, maxZoom=99>>} [options.graphs=[['osm', 0, 99]]] - Array of routing graphs and min/max zoom levels. If you use the control in combination with the [geOps Maps API](https://developer.geops.io/apis/maps/), you may want to use the optimal level of generalizations: "[['gen4', 0, 8], ['gen3', 8, 9], ['gen2', 9, 11], ['gen1', 11, 13], ['osm', 13, 99]]".
78
+ * @param {string} [options.mot="bus"] Mean of transport to be used for routing.
79
+ * @param {function} options.onRouteError Callback on request errors.
80
+ * @param {VectorLayer} [options.routingLayer=new VectorLayer()] Vector layer for adding route features.
81
+ * @param {boolean} [options.snapToClosestStation=false] If true, the routing will snap the coordinate to the closest station. Default to false.
82
+ * @param {StyleLike} options.style Style of the default vector layer.
83
+ * @param {boolean} [options.useRawViaPoints=fale] Experimental property. If true, it allows the user to add via points using different kind of string. See "via" parameter defined by the [geOps Routing API](https://developer.geops.io/apis/routing/). Default to false, only array of coordinates and station's id are supported as via points.
84
+ * @param {string} [options.url='https://api.geops.io/routing/v1/'] [geOps Realtime API](https://developer.geops.io/apis/realtime/) url.
85
+ * @public
86
+ */
106
87
  constructor(options = {}) {
107
88
  super(options);
108
- this.viaPoints = [];
109
- this.graphs = [];
110
- this.useRawViaPoints = false;
111
- this.snapToClosestStation = false;
112
- this.cacheStationData = {};
113
89
  this.abortControllers = {};
114
- this.segments = [];
90
+ this.cacheStationData = {};
115
91
  this.format = new GeoJSON({ featureProjection: 'EPSG:3857' });
92
+ this.graphs = [];
116
93
  this.initialRouteDrag = {};
94
+ this.segments = [];
95
+ this.snapToClosestStation = false;
96
+ this.useRawViaPoints = false;
97
+ this.viaPoints = [];
117
98
  if (!this.element) {
118
99
  this.createDefaultElement();
119
100
  }
120
101
  /** True if the control is requesting the backend. */
121
102
  this.loading = false;
122
- /** @private */
123
103
  this.active = options.active || true;
124
- /** @private */
125
104
  this.graphs = options.graphs || [['osm', 0, 99]];
126
- /** @private */
127
105
  this.mot = options.mot || 'bus';
128
- /** @private */
129
106
  this.modify = options.modify !== false;
130
- /** @private */
131
- this.routingApiParams = options.routingApiParams;
132
- /** @private */
107
+ this.apiParams = options.apiParams;
133
108
  this.useRawViaPoints = options.useRawViaPoints || false;
134
- /** @private */
135
109
  this.snapToClosestStation = options.snapToClosestStation || false;
136
- /** @private */
137
110
  this.apiKey = options.apiKey;
138
- /** @private */
139
111
  this.stopsApiKey = options.stopsApiKey || this.apiKey;
140
- /** @private */
141
112
  this.stopsApiUrl = options.stopsApiUrl || 'https://api.geops.io/stops/v1/';
142
- /** @private */
143
113
  this.api = new RoutingAPI(Object.assign({}, options));
144
- /** @private */
145
114
  this.routingLayer =
146
115
  options.routingLayer ||
147
116
  new VectorLayer({
148
117
  source: new VectorSource(),
149
118
  style: options.style,
150
119
  });
151
- /** @private */
152
120
  this.onRouteError =
153
121
  options.onRouteError ||
154
122
  ((error) => {
@@ -157,13 +125,9 @@ class RoutingControl extends Control {
157
125
  // eslint-disable-next-line no-console
158
126
  console.error(error);
159
127
  });
160
- /** @private */
161
128
  this.onMapClick = this.onMapClick.bind(this);
162
- /** @private */
163
129
  this.onModifyEnd = this.onModifyEnd.bind(this);
164
- /** @private */
165
130
  this.onModifyStart = this.onModifyStart.bind(this);
166
- /** @private */
167
131
  this.createModifyInteraction();
168
132
  this.on('propertychange', (evt) => {
169
133
  if (evt.key === 'active') {
@@ -189,17 +153,57 @@ class RoutingControl extends Control {
189
153
  ]);
190
154
  }
191
155
  /**
192
- * Activet7deactivate the control when activ eproperty changes
156
+ * Aborts viapoint and route requests
193
157
  * @private
194
158
  */
195
- onActiveChange() {
196
- if (this.get('active')) {
197
- this.activate();
159
+ abortRequests() {
160
+ var _a;
161
+ // Abort Routing API requests
162
+ this.graphs.forEach((graph) => {
163
+ const graphName = graph[0];
164
+ if (this.abortControllers[graphName]) {
165
+ this.abortControllers[graphName].abort();
166
+ }
167
+ this.abortControllers[graphName] = new AbortController();
168
+ });
169
+ // Abort Stops API requests
170
+ (_a = this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]) === null || _a === void 0 ? void 0 : _a.abort();
171
+ this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY] =
172
+ new AbortController();
173
+ this.loading = false;
174
+ }
175
+ activate() {
176
+ var _a;
177
+ const map = this.getMap();
178
+ if (map) {
179
+ this.format = new GeoJSON({
180
+ featureProjection: map.getView().getProjection(),
181
+ });
182
+ this.graphsResolutions = RoutingControl.getGraphsResolutions(this.graphs, map);
183
+ // Clean the modifyInteraction if present
184
+ if (this.modifyInteraction) {
185
+ map.removeInteraction(this.modifyInteraction);
186
+ }
187
+ // Add modify interaction, RoutingLayer and listeners
188
+ // this.routingLayer?.attachToMap(this.getMap());
189
+ if (this.modifyInteraction) {
190
+ map.addInteraction(this.modifyInteraction);
191
+ }
192
+ (_a = this.modifyInteraction) === null || _a === void 0 ? void 0 : _a.setActive(this.modify);
193
+ this.addListeners();
198
194
  }
199
- else {
200
- this.deactivate();
195
+ }
196
+ /**
197
+ * Add click listener to map.
198
+ * @private
199
+ */
200
+ addListeners() {
201
+ var _a;
202
+ if (!this.modify) {
203
+ return;
201
204
  }
202
- this.render();
205
+ this.removeListeners();
206
+ this.onMapClickKey = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.on('singleclick', this.onMapClick);
203
207
  }
204
208
  /**
205
209
  * Adds/Replaces a viaPoint to the viaPoints array and redraws route:
@@ -207,7 +211,7 @@ class RoutingControl extends Control {
207
211
  * If an index is passed a viaPoint is added at the specified index.
208
212
  * If an index is passed and overwrite x is > 0, x viaPoints at the specified
209
213
  * index are replaced with a single new viaPoint.
210
- * @param {number[]|string} coordinates Array of coordinates
214
+ * @param {string | Coordinate} coordinatesOrString Array of coordinates or a string representing a station
211
215
  * @param {number} [index=-1] Integer representing the index of the added viaPoint. If not specified, the viaPoint is added at the end of the array.
212
216
  * @param {number} [overwrite=0] Marks the number of viaPoints that are removed at the specified index on add.
213
217
  * @public
@@ -219,60 +223,65 @@ class RoutingControl extends Control {
219
223
  this.dispatchEvent(new BaseEvent('change:route'));
220
224
  }
221
225
  /**
222
- * Removes a viaPoint at the passed array index and redraws route
223
- * By default the last viaPoint is removed.
224
- * @param {number} index Integer representing the index of the viaPoint to delete.
225
- * @public
226
- */
227
- removeViaPoint(index = (this.viaPoints || []).length - 1) {
228
- /* Remove viapoint and redraw route */
229
- if (this.viaPoints.length && this.viaPoints[index]) {
230
- this.viaPoints.splice(index, 1);
231
- }
232
- this.drawRoute();
233
- this.dispatchEvent(new BaseEvent('change:route'));
234
- }
235
- /**
236
- * Replaces the current viaPoints with a new coordinate array.
237
- * @param {Array<Array<number>>} coordinateArray Array of nested coordinates
238
- * @public
239
- */
240
- setViaPoints(coordinateArray) {
241
- this.viaPoints = [...coordinateArray];
242
- this.drawRoute();
243
- this.dispatchEvent(new BaseEvent('change:route'));
244
- }
245
- /**
246
- * Removes all viaPoints, clears the source and triggers a change event
247
- * @public
226
+ * Define a default element.
227
+ *
228
+ * @private
248
229
  */
249
- reset() {
250
- var _a, _b;
251
- // Clear viaPoints and source
252
- this.abortRequests();
253
- this.viaPoints = [];
254
- (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
255
- this.dispatchEvent(new BaseEvent('change:route'));
230
+ createDefaultElement() {
231
+ this.element = document.createElement('button');
232
+ this.element.id = 'ol-toggle-routing';
233
+ this.element.innerHTML = 'Toggle Route Control';
234
+ this.element.onclick = () => this.active ? this.deactivate() : this.activate();
235
+ Object.assign(this.element.style, {
236
+ position: 'absolute',
237
+ right: '10px',
238
+ top: '10px',
239
+ });
256
240
  }
257
241
  /**
258
- * Aborts viapoint and route requests
242
+ * Create the interaction used to modify vertexes of features.
259
243
  * @private
260
244
  */
261
- abortRequests() {
245
+ createModifyInteraction() {
262
246
  var _a;
263
- // Abort Routing API requests
264
- this.graphs.forEach((graph) => {
265
- const graphName = graph[0];
266
- if (this.abortControllers[graphName]) {
267
- this.abortControllers[graphName].abort();
268
- }
269
- this.abortControllers[graphName] = new AbortController();
247
+ /**
248
+ * @type {ol.interaction.Modify}
249
+ * @private
250
+ */
251
+ // Define and add modify interaction
252
+ this.modifyInteraction = new Modify({
253
+ // hitDetection: this.routingLayer, // TODO: wait for ol, fixed in https://github.com/openlayers/openlayers/pull/16393
254
+ deleteCondition: (e) => {
255
+ var _a;
256
+ const feats = ((_a = e.target) === null || _a === void 0 ? void 0 : _a.getFeaturesAtPixel(e.pixel, {
257
+ hitTolerance: 5,
258
+ })) || [];
259
+ const viaPoint = feats.find((feat) => { var _a; return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' && feat.get('index'); });
260
+ if (click(e) && viaPoint) {
261
+ // Remove node & viaPoint if an existing viaPoint was clicked
262
+ this.removeViaPoint(viaPoint.get('index'));
263
+ return true;
264
+ }
265
+ return false;
266
+ },
267
+ pixelTolerance: 6,
268
+ source: ((_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) || undefined,
270
269
  });
271
- // Abort Stops API requests
272
- (_a = this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]) === null || _a === void 0 ? void 0 : _a.abort();
273
- this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY] =
274
- new AbortController();
275
- this.loading = false;
270
+ this.modifyInteraction.on('modifystart', this.onModifyStart);
271
+ this.modifyInteraction.on('modifyend', this.onModifyEnd);
272
+ this.modifyInteraction.setActive(false);
273
+ }
274
+ deactivate() {
275
+ const map = this.getMap();
276
+ if (map) {
277
+ // Remove modify interaction, RoutingLayer, listeners and viaPoints
278
+ // this.routingLayer?.detachFromMap();
279
+ if (this.modifyInteraction) {
280
+ map.removeInteraction(this.modifyInteraction);
281
+ }
282
+ this.removeListeners();
283
+ this.reset();
284
+ }
276
285
  }
277
286
  /**
278
287
  * Draws route on map using an array of coordinates:
@@ -285,7 +294,7 @@ class RoutingControl extends Control {
285
294
  var _a, _b;
286
295
  /* Calls RoutingAPI to draw a route using the viaPoints array */
287
296
  this.abortRequests();
288
- (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear(true);
297
+ (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
289
298
  if (!this.viaPoints.length) {
290
299
  return null;
291
300
  }
@@ -307,16 +316,18 @@ class RoutingControl extends Control {
307
316
  });
308
317
  this.loading = true;
309
318
  // Create point features for the viaPoints
310
- this.viaPoints.forEach((viaPoint, idx) => this.drawViaPoint(viaPoint, idx, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]));
319
+ this.viaPoints.forEach((viaPoint, idx) => {
320
+ this.drawViaPoint(viaPoint, idx, this.abortControllers[STOP_FETCH_ABORT_CONTROLLER_KEY]);
321
+ });
311
322
  return Promise.all(this.graphs.map(([graph], index) => {
312
323
  const { signal } = this.abortControllers[graph];
313
324
  if (!this.api) {
314
325
  return Promise.resolve([]);
315
326
  }
316
327
  return this.api
317
- .route(Object.assign({ graph, via: `${formattedViaPoints.join('|')}`, mot: this.mot,
318
- // @ts-ignore missing property in swagger
319
- 'resolve-hops': false, elevation: false, 'coord-radius': 100.0, 'coord-punish': 1000.0 }, (this.routingApiParams || {})), { signal })
328
+ .route(Object.assign({ 'coord-punish': 1000.0, 'coord-radius': 100.0,
329
+ // @ts-expect-error missing property in swagger
330
+ elevation: false, graph, mot: this.mot, 'resolve-hops': false, via: `${formattedViaPoints.join('|')}` }, (this.apiParams || {})), { signal })
320
331
  .then((featureCollection) => {
321
332
  var _a, _b, _c;
322
333
  this.segments = this.format.readFeatures(featureCollection);
@@ -356,8 +367,7 @@ class RoutingControl extends Control {
356
367
  this.loading = false;
357
368
  })
358
369
  .catch((error) => {
359
- var _a, _b;
360
- if (/AbortError/.test(error.message)) {
370
+ if (/AbortError/.test(error.name)) {
361
371
  // Ignore abort error
362
372
  return;
363
373
  }
@@ -365,7 +375,6 @@ class RoutingControl extends Control {
365
375
  // Dispatch error event and execute error function
366
376
  this.dispatchEvent(new BaseEvent('error'));
367
377
  this.onRouteError(error, this);
368
- (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
369
378
  this.loading = false;
370
379
  });
371
380
  }));
@@ -402,15 +411,19 @@ class RoutingControl extends Control {
402
411
  return fetch(`${this.stopsApiUrl}lookup/${stationId}?key=${this.stopsApiKey}`, { signal: abortController.signal })
403
412
  .then((res) => res.json())
404
413
  .then((stationData) => {
405
- var _a, _b;
406
- const { coordinates } = stationData.features[0].geometry;
414
+ var _a, _b, _c, _d;
415
+ const { coordinates } = ((_b = (_a = stationData === null || stationData === void 0 ? void 0 : stationData.features) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.geometry) || {};
416
+ if (!coordinates) {
417
+ console.log('No coordinates found for station ' + stationId, stationData);
418
+ }
407
419
  this.cacheStationData[viaPoint] = fromLonLat(coordinates);
408
420
  pointFeature.set('viaPointTrack', track);
409
421
  pointFeature.setGeometry(new Point(fromLonLat(coordinates)));
410
- (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.addFeature(pointFeature);
422
+ (_d = (_c = this.routingLayer) === null || _c === void 0 ? void 0 : _c.getSource()) === null || _d === void 0 ? void 0 : _d.addFeature(pointFeature);
411
423
  return pointFeature;
412
424
  })
413
425
  .catch((error) => {
426
+ var _a, _b;
414
427
  if (/AbortError/.test(error.message)) {
415
428
  // Ignore abort error
416
429
  return;
@@ -418,6 +431,7 @@ class RoutingControl extends Control {
418
431
  // Dispatch error event and execute error function
419
432
  this.dispatchEvent(new BaseEvent('error'));
420
433
  this.onRouteError(error, this);
434
+ (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
421
435
  this.loading = false;
422
436
  });
423
437
  }
@@ -474,6 +488,19 @@ class RoutingControl extends Control {
474
488
  }
475
489
  return Promise.resolve(null);
476
490
  }
491
+ /**
492
+ * Activet7deactivate the control when activ eproperty changes
493
+ * @private
494
+ */
495
+ onActiveChange() {
496
+ if (this.get('active')) {
497
+ this.activate();
498
+ }
499
+ else {
500
+ this.deactivate();
501
+ }
502
+ this.render();
503
+ }
477
504
  /**
478
505
  * Used on click on map while control is active:
479
506
  * By default adds a viaPoint to the end of array.
@@ -482,8 +509,8 @@ class RoutingControl extends Control {
482
509
  */
483
510
  onMapClick(evt) {
484
511
  const feats = evt.target.getFeaturesAtPixel(evt.pixel, {
485
- layerFilter: (layer) => layer === this.routingLayer,
486
512
  hitTolerance: 5,
513
+ layerFilter: (layer) => layer === this.routingLayer,
487
514
  });
488
515
  const viaPoint = feats.find((feat) => {
489
516
  var _a;
@@ -497,6 +524,30 @@ class RoutingControl extends Control {
497
524
  }
498
525
  this.addViaPoint(evt.coordinate);
499
526
  }
527
+ /**
528
+ * Used on end of the modify interaction. Resolves feature modification:
529
+ * Line drag creates new viaPoint at the final coordinate of drag.
530
+ * Point drag replaces old viaPoint.
531
+ * @private
532
+ */
533
+ onModifyEnd(evt) {
534
+ const coord = evt.mapBrowserEvent.coordinate;
535
+ const { oldRoute, segmentIndex, viaPoint } = this.initialRouteDrag || {};
536
+ // If viaPoint is being relocated overwrite the old viaPoint
537
+ if (viaPoint) {
538
+ return this.addViaPoint(coord, viaPoint.get('viaPointIdx'), 1);
539
+ }
540
+ // In case there is no route overwrite first coordinate
541
+ if (!oldRoute) {
542
+ return this.addViaPoint(coord, 0, 1);
543
+ }
544
+ // We can't add a via point because we haven't found which segment has been modified.
545
+ if (segmentIndex === -1) {
546
+ return Promise.reject(new Error('No segment found'));
547
+ }
548
+ // Insert new viaPoint at the modified segment index + 1
549
+ return this.addViaPoint(coord, (segmentIndex || 0) + 1);
550
+ }
500
551
  /**
501
552
  * Used on start of the modify interaction. Stores relevant data
502
553
  * in this.initialRouteDrag object
@@ -510,10 +561,10 @@ class RoutingControl extends Control {
510
561
  .getArray()
511
562
  .find((feat) => { var _a; return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'LineString'; });
512
563
  // Find the segment index that is being modified
513
- if (route && route.getGeometry() && evt.mapBrowserEvent.coordinate) {
564
+ if ((route === null || route === void 0 ? void 0 : route.getGeometry()) && evt.mapBrowserEvent.coordinate) {
514
565
  // We use a buff extent to fix floating issues , see https://github.com/openlayers/openlayers/issues/7130#issuecomment-535856422
515
566
  const closestExtent = buffer(new Point(
516
- // @ts-ignore
567
+ // @ts-expect-error bad def
517
568
  (_a = route.getGeometry()) === null || _a === void 0 ? void 0 : _a.getClosestPoint(evt.mapBrowserEvent.coordinate)).getExtent(), 0.001);
518
569
  segmentIndex = this.segments.findIndex((segment) => { var _a; return (_a = segment.getGeometry()) === null || _a === void 0 ? void 0 : _a.intersectsExtent(closestExtent); });
519
570
  }
@@ -523,108 +574,47 @@ class RoutingControl extends Control {
523
574
  .filter((feat) => { var _a; return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point'; }) ||
524
575
  [])[0];
525
576
  // Write object with modify info
526
- /** @private */
527
577
  this.initialRouteDrag = {
528
- viaPoint,
529
- oldRoute: route && route.clone(),
578
+ oldRoute: route === null || route === void 0 ? void 0 : route.clone(),
530
579
  segmentIndex,
580
+ viaPoint,
531
581
  };
532
582
  }
533
583
  /**
534
- * Used on end of the modify interaction. Resolves feature modification:
535
- * Line drag creates new viaPoint at the final coordinate of drag.
536
- * Point drag replaces old viaPoint.
584
+ * Remove click listener from map.
537
585
  * @private
538
586
  */
539
- onModifyEnd(evt) {
540
- const coord = evt.mapBrowserEvent.coordinate;
541
- const { oldRoute, viaPoint, segmentIndex } = this.initialRouteDrag || {};
542
- // If viaPoint is being relocated overwrite the old viaPoint
543
- if (viaPoint) {
544
- return this.addViaPoint(coord, viaPoint.get('viaPointIdx'), 1);
545
- }
546
- // In case there is no route overwrite first coordinate
547
- if (!oldRoute) {
548
- return this.addViaPoint(coord, 0, 1);
549
- }
550
- // We can't add a via point because we haven't found which segment has been modified.
551
- if (segmentIndex === -1) {
552
- return Promise.reject(new Error('No segment found'));
587
+ removeListeners() {
588
+ if (this.onMapClickKey) {
589
+ unByKey(this.onMapClickKey);
553
590
  }
554
- // Insert new viaPoint at the modified segment index + 1
555
- return this.addViaPoint(coord, (segmentIndex || 0) + 1);
556
- }
557
- /**
558
- * Define a default element.
559
- *
560
- * @private
561
- */
562
- createDefaultElement() {
563
- /** @private */
564
- this.element = document.createElement('button');
565
- this.element.id = 'ol-toggle-routing';
566
- this.element.innerHTML = 'Toggle Route Control';
567
- this.element.onclick = () => this.active ? this.deactivate() : this.activate();
568
- Object.assign(this.element.style, {
569
- position: 'absolute',
570
- right: '10px',
571
- top: '10px',
572
- });
573
- }
574
- /**
575
- * Create the interaction used to modify vertexes of features.
576
- * @private
577
- */
578
- createModifyInteraction() {
579
- var _a;
580
- /**
581
- * @type {ol.interaction.Modify}
582
- * @private
583
- */
584
- // Define and add modify interaction
585
- this.modifyInteraction = new Modify({
586
- source: ((_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) || undefined,
587
- pixelTolerance: 6,
588
- // hitDetection: this.routingLayer, // Create a bug, the first point is always selected even if the mous eis far away
589
- deleteCondition: (e) => {
590
- var _a;
591
- const feats = (_a = e.target) === null || _a === void 0 ? void 0 : _a.getFeaturesAtPixel(e.pixel, {
592
- hitTolerance: 5,
593
- } || []);
594
- const viaPoint = feats.find((feat) => { var _a; return ((_a = feat.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType()) === 'Point' && feat.get('index'); });
595
- if (click(e) && viaPoint) {
596
- // Remove node & viaPoint if an existing viaPoint was clicked
597
- this.removeViaPoint(viaPoint.get('index'));
598
- return true;
599
- }
600
- return false;
601
- },
602
- });
603
- this.modifyInteraction.on('modifystart', this.onModifyStart);
604
- this.modifyInteraction.on('modifyend', this.onModifyEnd);
605
- this.modifyInteraction.setActive(false);
606
591
  }
607
592
  /**
608
- * Add click listener to map.
609
- * @private
593
+ * Removes a viaPoint at the passed array index and redraws route
594
+ * By default the last viaPoint is removed.
595
+ * @param {number} index Integer representing the index of the viaPoint to delete.
596
+ * @public
610
597
  */
611
- addListeners() {
612
- var _a;
613
- if (!this.modify) {
614
- return;
598
+ removeViaPoint(index = (this.viaPoints || []).length - 1) {
599
+ /* Remove viapoint and redraw route */
600
+ if (this.viaPoints.length && this.viaPoints[index]) {
601
+ this.viaPoints.splice(index, 1);
615
602
  }
616
- this.removeListeners();
617
- /** @private */
618
- this.onMapClickKey = (_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.on('singleclick', this.onMapClick);
603
+ this.drawRoute();
604
+ this.dispatchEvent(new BaseEvent('change:route'));
619
605
  }
606
+ render() { }
620
607
  /**
621
- * Remove click listener from map.
622
- * @private
608
+ * Removes all viaPoints, clears the source and triggers a change event
609
+ * @public
623
610
  */
624
- removeListeners() {
625
- if (this.onMapClickKey) {
626
- unByKey(this.onMapClickKey);
627
- }
611
+ reset() {
612
+ var _a, _b;
613
+ // Clear viaPoints and source
614
+ this.abortRequests();
615
+ this.viaPoints = [];
616
+ (_b = (_a = this.routingLayer) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
617
+ this.dispatchEvent(new BaseEvent('change:route'));
628
618
  }
629
619
  setMap(map) {
630
620
  super.setMap(map);
@@ -635,43 +625,39 @@ class RoutingControl extends Control {
635
625
  this.active = false;
636
626
  }
637
627
  }
638
- activate() {
639
- var _a;
640
- const map = this.getMap();
641
- if (map) {
642
- /** @private */
643
- this.format = new GeoJSON({
644
- featureProjection: map.getView().getProjection(),
645
- });
646
- /** @private */
647
- this.graphsResolutions = RoutingControl.getGraphsResolutions(this.graphs, map);
648
- // Clean the modifyInteraction if present
649
- if (this.modifyInteraction) {
650
- map.removeInteraction(this.modifyInteraction);
651
- }
652
- // Add modify interaction, RoutingLayer and listeners
653
- // @ts-ignore
654
- // this.routingLayer?.attachToMap(this.getMap());
655
- if (this.modifyInteraction) {
656
- map.addInteraction(this.modifyInteraction);
657
- }
658
- (_a = this.modifyInteraction) === null || _a === void 0 ? void 0 : _a.setActive(this.modify);
659
- this.addListeners();
660
- }
628
+ /**
629
+ * Replaces the current viaPoints with a new coordinate array.
630
+ * @param {Array<Array<number>>} coordinateArray Array of nested coordinates
631
+ * @public
632
+ */
633
+ setViaPoints(coordinateArray) {
634
+ this.viaPoints = [...coordinateArray];
635
+ this.drawRoute();
636
+ this.dispatchEvent(new BaseEvent('change:route'));
661
637
  }
662
- deactivate() {
663
- const map = this.getMap();
664
- if (map) {
665
- // Remove modify interaction, RoutingLayer, listeners and viaPoints
666
- // @ts-ignore
667
- // this.routingLayer?.detachFromMap();
668
- if (this.modifyInteraction) {
669
- map.removeInteraction(this.modifyInteraction);
670
- }
671
- this.removeListeners();
672
- this.reset();
673
- }
638
+ get active() {
639
+ return this.get('active');
640
+ }
641
+ set active(newValue) {
642
+ this.set('active', newValue);
643
+ }
644
+ get loading() {
645
+ return this.get('loading');
646
+ }
647
+ set loading(newValue) {
648
+ this.set('loading', newValue);
649
+ }
650
+ get modify() {
651
+ return this.get('modify');
652
+ }
653
+ set modify(newValue) {
654
+ this.set('modify', newValue);
655
+ }
656
+ get mot() {
657
+ return this.get('mot');
658
+ }
659
+ set mot(newValue) {
660
+ this.set('mot', newValue);
674
661
  }
675
- render() { }
676
662
  }
677
663
  export default RoutingControl;