mobility-toolbox-js 1.6.4-beta.1 → 1.6.4

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.
@@ -32,7 +32,7 @@ class RoutingAPI extends API {
32
32
  *
33
33
  * @param {RoutingSearchParams} params Request parameters. See [Routing service documentation](https://developer.geops.io/apis/routing/).
34
34
  * @param {AbortController} abortController Abort controller used to cancel the request.
35
- * @returns {Promise<GeoJSONFeatureCollection>} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).
35
+ * @return {Promise<GeoJSONFeatureCollection>} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).
36
36
  */
37
37
  route(params, abortController = new AbortController()) {
38
38
  return this.fetch('', params, {
@@ -29,7 +29,7 @@ class StopsAPI extends API {
29
29
  *
30
30
  * @param {StopsSearchParams} params Request parameters. See [Stops service documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).
31
31
  * @param {AbortController} abortController Abort controller used to cancel the request.
32
- * @returns {Promise<Array<GeoJSONFeature>>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326).
32
+ * @return {Promise<Array<GeoJSONFeature>>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326).
33
33
  */
34
34
  search(params, abortController = {}) {
35
35
  return this.fetch('', params, {
@@ -33,7 +33,7 @@ class TrajservAPI extends API {
33
33
  *
34
34
  * @param {GetTrajectoryByIdParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajectorybyid).
35
35
  * @param {AbortController} abortController Abort controller used to cancel the request.
36
- * @returns {Promise<TrajservTrajectory>} A trajectory.
36
+ * @return {Promise<TrajservTrajectory>} A trajectory.
37
37
  */
38
38
  fetchTrajectoryById(params, abortController = {}) {
39
39
  return this.fetch(`/trajectorybyid`, params, {
@@ -46,7 +46,7 @@ class TrajservAPI extends API {
46
46
  *
47
47
  * @param {GetTrajectoriesParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajectory_collection).
48
48
  * @param {AbortController} abortController Abort controller used to cancel the request.
49
- * @returns {Promise<Array<Trajectory>>} A list of trajectories.
49
+ * @return {Promise<Array<Trajectory>>} A list of trajectories.
50
50
  */
51
51
  fetchTrajectories(params, abortController = {}) {
52
52
  return this.fetch(`/trajectory_collection`, params, {
@@ -61,7 +61,7 @@ class TrajservAPI extends API {
61
61
  *
62
62
  * @param {GetTrajectoryStationsParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajstations).
63
63
  * @param {AbortController} abortController Abort controller used to cancel the request.
64
- * @returns {Promise<Array<TrajectoryStation>>} A list of stations.
64
+ * @return {Promise<Array<TrajectoryStation>>} A list of stations.
65
65
  */
66
66
  fetchTrajectoryStations(params, abortController = {}) {
67
67
  return this.fetch(`/trajstations`, params, {
@@ -2,7 +2,7 @@ import { LineString } from 'ol/geom';
2
2
 
3
3
  /**
4
4
  * Translate the response date object into a readable object.
5
- * @returns {Date[]}
5
+ * @return {Date[]}
6
6
  * @ignore
7
7
  */
8
8
  const translateDates = (dates = []) => {
@@ -21,7 +21,7 @@ const translateDates = (dates = []) => {
21
21
 
22
22
  /**
23
23
  * Translate the trajstations response into a readable object.
24
- * @returns {Object} returns a readable object
24
+ * @return {Object} returns a readable object
25
25
  * @private
26
26
  */
27
27
  export const translateTrajStationsResp = (data) => {
@@ -125,7 +125,7 @@ export const translateTrajStationsResp = (data) => {
125
125
 
126
126
  /**
127
127
  * Translate the trajectory_collection response into a js usable object.
128
- * @returns {Array} returns an array of trajectories.
128
+ * @return {Array} returns an array of trajectories.
129
129
  * @ignore
130
130
  */
131
131
  export const translateTrajCollResponse = (features = []) => {
@@ -65,7 +65,8 @@ class TralisAPI {
65
65
  /** @ignore */
66
66
  this.prefix = options.prefix || '';
67
67
 
68
- this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd || false;
68
+ /** @ignore */
69
+ this.onOpen = this.onOpen.bind(this);
69
70
  }
70
71
 
71
72
  defineProperties(options) {
@@ -80,7 +81,7 @@ class TralisAPI {
80
81
  const conn = new WebSocketConnector();
81
82
 
82
83
  if (apiKey) {
83
- url = `${url}?key=${apiKey}`;
84
+ url = `${url || 'wss://tralis-tracker-api.geops.io/ws'}?key=${apiKey}`;
84
85
  }
85
86
 
86
87
  Object.defineProperties(this, {
@@ -151,16 +152,8 @@ class TralisAPI {
151
152
 
152
153
  open() {
153
154
  this.close();
154
- this.conn.connect(this.url);
155
-
156
- // Register BBOX and PROJECTION messages on open.
157
- if (this.conn.connecting) {
158
- this.conn.websocket.addEventListener('open', () => {
159
- this.onOpen();
160
- });
161
- } else {
162
- this.onOpen();
163
- }
155
+ // Register BBOX and PROJECTION messages must be send before previous subscriptions.
156
+ this.conn.connect(this.url, this.onOpen);
164
157
 
165
158
  // Register reconnection on close.
166
159
  this.conn.websocket.onclose = () => {
@@ -202,7 +195,7 @@ class TralisAPI {
202
195
  window.clearInterval(this.pingInterval);
203
196
  /** @ignore */
204
197
  this.pingInterval = setInterval(() => {
205
- this.send('PING');
198
+ this.conn.send('PING');
206
199
  }, this.pingIntervalMs);
207
200
  }
208
201
  }
@@ -264,7 +257,7 @@ class TralisAPI {
264
257
  *
265
258
  * @param {Object} depObject The object containing departures by id.
266
259
  * @param {boolean} [sortByMinArrivalTime=false] If true sort departures by arrival time.
267
- * @returns {Array<departure>} Return departures array.
260
+ * @return {Array<departure>} Return departures array.
268
261
  * @private
269
262
  */
270
263
  filterDepartures(depObject, sortByMinArrivalTime = false) {
@@ -396,7 +389,7 @@ class TralisAPI {
396
389
  *
397
390
  * @param {number} uic UIC of the station.
398
391
  * @param {TralisMode} mode Tralis mode.
399
- * @returns {Promise<Station>} A station.
392
+ * @return {Promise<Station>} A station.
400
393
  */
401
394
  getStation(uic, mode) {
402
395
  const params = {
@@ -419,7 +412,7 @@ class TralisAPI {
419
412
  * Update the model's station list for a given mode and a bbox.
420
413
  *
421
414
  * @param {TralisMode} mode Tralis mode.
422
- * @returns {Promise<Array<Station>>} An array of stations.
415
+ * @return {Promise<Array<Station>>} An array of stations.
423
416
  */
424
417
  getStations(mode) {
425
418
  const stations = [];
@@ -448,7 +441,6 @@ class TralisAPI {
448
441
  * One message pro station.
449
442
  *
450
443
  * @param {TralisMode} mode Tralis mode.
451
- * @param {number[4]} bbox The extent where to request.
452
444
  * @param {function(station: Station)} onMessage Function called on each message of the channel.
453
445
  */
454
446
  subscribeStations(mode, onMessage) {
@@ -507,14 +499,15 @@ class TralisAPI {
507
499
  *
508
500
  * @param {TralisMode} mode Tralis mode.
509
501
  * @param {function(trajectory: TralisTrajectory)} onMessage Function called on each message of the channel.
502
+ * @param {boolean} quiet If true, the subscription will not send GET and SUB requests to the websocket.
510
503
  */
511
- subscribeTrajectory(mode, onMessage) {
504
+ subscribeTrajectory(mode, onMessage, quiet = false) {
512
505
  this.unsubscribeTrajectory(onMessage);
513
506
  this.subscribe(
514
507
  `trajectory${getModeSuffix(mode, TralisModes)}`,
515
508
  onMessage,
516
509
  null,
517
- this.isUpdateBboxOnMoveEnd,
510
+ quiet,
518
511
  );
519
512
  }
520
513
 
@@ -531,14 +524,15 @@ class TralisAPI {
531
524
  *
532
525
  * @param {TralisMode} mode Tralis mode.
533
526
  * @param {function(response: { content: Vehicle })} onMessage Function called on each message of the channel.
527
+ * @param {boolean} quiet If true, the subscription will not send GET and SUB requests to the websocket.
534
528
  */
535
- subscribeDeletedVehicles(mode, onMessage) {
529
+ subscribeDeletedVehicles(mode, onMessage, quiet = false) {
536
530
  this.unsubscribeDeletedVehicles(onMessage);
537
531
  this.subscribe(
538
532
  `deleted_vehicles${getModeSuffix(mode, TralisModes)}`,
539
533
  onMessage,
540
534
  null,
541
- this.isUpdateBboxOnMoveEnd,
535
+ quiet,
542
536
  );
543
537
  }
544
538
 
@@ -555,11 +549,21 @@ class TralisAPI {
555
549
  *
556
550
  * @param {string} id A vehicle id.
557
551
  * @param {TralisMode} mode Tralis mode.
558
- * @returns {Promise<FullTrajectory>} Return a full trajectory.
552
+ * @param {string} generalizationLevel The generalization level to request. Can be one of 5 (more generalized), 10, 30, 100, undefined (less generalized).
553
+ * @return {Promise<FullTrajectory>} Return a full trajectory.
559
554
  */
560
- getFullTrajectory(id, mode) {
555
+ getFullTrajectory(id, mode, generalizationLevel) {
556
+ const channel = [`full_trajectory${getModeSuffix(mode, TralisModes)}`];
557
+ if (id) {
558
+ channel.push(id);
559
+ }
560
+
561
+ if ((!mode || mode === TralisModes.TOPOGRAPHIC) && generalizationLevel) {
562
+ channel.push(`gen${generalizationLevel}`);
563
+ }
564
+
561
565
  const params = {
562
- channel: `full_trajectory${getModeSuffix(mode, TralisModes)}_${id}`,
566
+ channel: channel.join('_'),
563
567
  };
564
568
 
565
569
  return new Promise((resolve) => {
@@ -576,11 +580,12 @@ class TralisAPI {
576
580
  *
577
581
  * @param {string[]} ids List of vehicles ids.
578
582
  * @param {TralisMode} mode Tralis mode.
579
- * @returns {Promise<Array<FullTrajectory>>} Return an array of full trajectories.
583
+ * @param {string} generalizationLevel The generalization level to request. Can be one of '', 'gen5', 'gen10', 'gen30', 'gen100'.
584
+ * @return {Promise<Array<FullTrajectory>>} Return an array of full trajectories.
580
585
  */
581
- getFullTrajectories(ids, mode) {
586
+ getFullTrajectories(ids, mode, generalizationLevel) {
582
587
  const promises = ids.map((id) => {
583
- return this.getFullTrajectory(id, mode);
588
+ return this.getFullTrajectory(id, mode, generalizationLevel);
584
589
  });
585
590
  return Promise.all(promises);
586
591
  }
@@ -621,7 +626,7 @@ class TralisAPI {
621
626
  * Get the list of stops for this vehicle.
622
627
  *
623
628
  * @param {string} id A vehicle id.
624
- * @returns {Promise<StopSequence>} Returns a stop sequence object.
629
+ * @return {Promise<StopSequence>} Returns a stop sequence object.
625
630
  */
626
631
  getStopSequence(id) {
627
632
  const params = {
@@ -652,7 +657,7 @@ class TralisAPI {
652
657
  * Get a list of stops for a list of vehicles.
653
658
  *
654
659
  * @param {string[]} ids List of vehicles ids.
655
- * @returns {Promise<Array<StopSequence>>} Return an array of stop sequences.
660
+ * @return {Promise<Array<StopSequence>>} Return an array of stop sequences.
656
661
  */
657
662
  getStopSequences(ids) {
658
663
  const promises = ids.map((id) => {
@@ -0,0 +1,75 @@
1
+ import { TralisAPI, TralisModes } from '..';
2
+
3
+ describe('TralisAPI', () => {
4
+ let tralisAPI;
5
+ let get;
6
+
7
+ beforeEach(() => {
8
+ get = jest.fn((params, cb) => {
9
+ cb({ content: 'content' });
10
+ });
11
+ tralisAPI = new TralisAPI();
12
+ tralisAPI.conn = {
13
+ get,
14
+ };
15
+ });
16
+
17
+ describe('#getFullTrajectory() calls fullTrajectory channel', () => {
18
+ test('without parameters', (done) => {
19
+ tralisAPI.getFullTrajectory().then(() => {
20
+ expect(get.mock.calls.length).toBe(1);
21
+ expect(get.mock.calls[0][0]).toEqual({
22
+ channel: 'full_trajectory',
23
+ });
24
+ done();
25
+ });
26
+ });
27
+
28
+ [null, TralisModes.TOPOGRAPHIC].forEach((mode) => {
29
+ describe(`using mode ${mode}`, () => {
30
+ test('using id', (done) => {
31
+ tralisAPI.getFullTrajectory('foo', mode).then(() => {
32
+ expect(get.mock.calls.length).toBe(1);
33
+ expect(get.mock.calls[0][0]).toEqual({
34
+ channel: 'full_trajectory_foo',
35
+ });
36
+ done();
37
+ });
38
+ });
39
+
40
+ test('using id and generalizationLevel param', (done) => {
41
+ tralisAPI.getFullTrajectory('foo', mode, 5).then(() => {
42
+ expect(get.mock.calls.length).toBe(1);
43
+ expect(get.mock.calls[0][0]).toEqual({
44
+ channel: 'full_trajectory_foo_gen5',
45
+ });
46
+ done();
47
+ });
48
+ });
49
+ });
50
+ });
51
+
52
+ describe('using schematic mode ', () => {
53
+ test('using id', (done) => {
54
+ tralisAPI.getFullTrajectory('foo', TralisModes.SCHEMATIC).then(() => {
55
+ expect(get.mock.calls.length).toBe(1);
56
+ expect(get.mock.calls[0][0]).toEqual({
57
+ channel: 'full_trajectory_schematic_foo',
58
+ });
59
+ done();
60
+ });
61
+ });
62
+ test("doesn't use generalizationLevel param", (done) => {
63
+ tralisAPI
64
+ .getFullTrajectory('foo', TralisModes.SCHEMATIC, 10)
65
+ .then(() => {
66
+ expect(get.mock.calls.length).toBe(1);
67
+ expect(get.mock.calls[0][0]).toEqual({
68
+ channel: 'full_trajectory_schematic_foo',
69
+ });
70
+ done();
71
+ });
72
+ });
73
+ });
74
+ });
75
+ });
@@ -82,7 +82,7 @@ class WebSocketConnector {
82
82
  * @param {string} params.channel Channel name
83
83
  * @param {string} [params.args] Request arguments
84
84
  * @param {Number} [params.id] Request identifier
85
- * @returns {string} request string
85
+ * @return {string} request string
86
86
  * @private
87
87
  */
88
88
  static getRequestString(method, params) {
@@ -95,9 +95,11 @@ class WebSocketConnector {
95
95
  /**
96
96
  * (Re)connect the websocket.
97
97
  *
98
+ * @param {strin} url Websocket url.
99
+ * @param {function} onOpen Callback called when the websocket connection is opened and before subscriptions of previous subscriptions.
98
100
  * @private
99
101
  */
100
- connect(url) {
102
+ connect(url, onOpen = () => {}) {
101
103
  if (this.websocket && !this.closed) {
102
104
  this.websocket.close();
103
105
  }
@@ -107,9 +109,11 @@ class WebSocketConnector {
107
109
 
108
110
  if (!this.open) {
109
111
  this.websocket.addEventListener('open', () => {
112
+ onOpen();
110
113
  this.subscribePreviousSubscriptions();
111
114
  });
112
115
  } else {
116
+ onOpen();
113
117
  this.subscribePreviousSubscriptions();
114
118
  }
115
119
  }
@@ -124,6 +128,7 @@ class WebSocketConnector {
124
128
  this.websocket.onclose = null;
125
129
  this.websocket.close();
126
130
  this.websocket = null;
131
+ this.messagesOnOpen = [];
127
132
  }
128
133
  }
129
134
 
@@ -148,6 +153,9 @@ class WebSocketConnector {
148
153
  this.messagesOnOpen = [];
149
154
  send();
150
155
  });
156
+ this.websocket.addEventListener('close', () => {
157
+ this.messagesOnOpen = [];
158
+ });
151
159
  }
152
160
  } else if (!this.messagesOnOpen.includes(message)) {
153
161
  send();
@@ -160,7 +168,7 @@ class WebSocketConnector {
160
168
  * @param {Object} params Parameters for the websocket get request
161
169
  * @param {function} cb callback on listen
162
170
  * @param {function} errorCb Callback on error
163
- * @returns {{onMessage: function, errorCb: function}} Object with onMessage and error callbacks
171
+ * @return {{onMessage: function, errorCb: function}} Object with onMessage and error callbacks
164
172
  * @private
165
173
  */
166
174
  listen(params, cb, errorCb) {
@@ -260,7 +268,6 @@ class WebSocketConnector {
260
268
  this.send(`GET ${reqStr}`);
261
269
  this.send(`SUB ${reqStr}`);
262
270
  }
263
-
264
271
  this.subscribed[reqStr] = true;
265
272
  }
266
273
  }
@@ -307,6 +314,13 @@ class WebSocketConnector {
307
314
  * After an auto reconnection we need to re-subscribe to the channels.
308
315
  */
309
316
  subscribePreviousSubscriptions() {
317
+ // Before to subscribe previous subscriptions we make sure they
318
+ // are all defined as unsubscribed, because this code is asynchrone
319
+ // and a subscription could have been added in between.
320
+ Object.keys(this.subscribed).forEach((key) => {
321
+ this.subscribed[key] = false;
322
+ });
323
+
310
324
  // Subscribe all previous subscriptions.
311
325
  [...this.subscriptions].forEach((s) => {
312
326
  this.subscribe(s.params, s.cb, s.errorCb, s.quiet);
@@ -28,6 +28,31 @@ describe('WebSocketConnector', () => {
28
28
  });
29
29
  });
30
30
 
31
+ describe('#close', () => {
32
+ test('should close the websocket and clear some property', async () => {
33
+ // eslint-disable-next-line no-unused-vars
34
+ const client = new Connector();
35
+ const subsc2 = {
36
+ params: 'foo',
37
+ cb: () => {},
38
+ errorCb: () => {},
39
+ quiet: false,
40
+ };
41
+ client.subscriptions = [subsc2];
42
+ client.messagesOnOpen = ['GET foo'];
43
+ client.connect(`ws://foo:1234`);
44
+ client.websocket.addEventListener = jest.fn();
45
+ client.websocket.removeEventListener = jest.fn();
46
+ client.websocket.close = jest.fn();
47
+ await server.connected;
48
+ expect(client.websocket).toBeDefined();
49
+ expect(client.messagesOnOpen).toEqual(['GET foo']);
50
+ client.close();
51
+ expect(client.messagesOnOpen).toEqual([]);
52
+ expect(client.websocket).toBeNull();
53
+ });
54
+ });
55
+
31
56
  describe('#connect', () => {
32
57
  test('create a new WebSocket.', async () => {
33
58
  const client = new Connector();
@@ -50,23 +75,44 @@ describe('WebSocketConnector', () => {
50
75
  expect(client.websocket.readyState).toBe(WebSocket.CONNECTING);
51
76
  });
52
77
 
53
- test('subscribe previous subscriptions on open', async () => {
78
+ test('call onOpen function', async () => {
79
+ const onOpen = jest.fn();
54
80
  const client = new Connector();
55
81
  client.subscribe = jest.fn();
56
- client.connect(`ws://foo:1234`);
82
+ client.connect(`ws://foo:1234`, onOpen);
57
83
  await server.connected;
58
84
  expect(client.websocket.readyState).toBe(WebSocket.OPEN);
85
+ expect(onOpen).toHaveBeenCalledTimes(1);
86
+ });
87
+
88
+ test('subscribe previous subscriptions on open (quiet or not)', async () => {
89
+ const client = new Connector();
90
+ client.subscribe = jest.fn();
91
+ client.send = jest.fn();
59
92
  const subsc = {
60
93
  params: 'foo',
61
94
  cb: () => {},
62
95
  errorCb: () => {},
63
96
  quiet: true,
64
97
  };
65
- client.subscriptions = [subsc];
98
+ const subsc2 = {
99
+ params: 'foo',
100
+ cb: () => {},
101
+ errorCb: () => {},
102
+ quiet: false,
103
+ };
104
+ client.subscriptions = [subsc, subsc2];
105
+
106
+ client.connect(`ws://foo:1234`);
107
+ await server.connected;
108
+ expect(client.websocket.readyState).toBe(WebSocket.OPEN);
109
+ expect(client.subscribe).toHaveBeenCalledTimes(2);
110
+ client.subscribe.mockReset();
111
+
66
112
  client.connect(`ws://foo:12345`);
67
113
  await server2.connected;
68
114
  expect(client.websocket.readyState).toBe(WebSocket.OPEN);
69
- expect(client.subscribe).toHaveBeenCalledTimes(1);
115
+ expect(client.subscribe).toHaveBeenCalledTimes(2);
70
116
  expect(client.subscribe).toHaveBeenCalledWith(
71
117
  subsc.params,
72
118
  subsc.cb,
@@ -74,6 +120,66 @@ describe('WebSocketConnector', () => {
74
120
  subsc.quiet,
75
121
  );
76
122
  });
123
+
124
+ test('send GET and SUB for not quiet previous subscriptions', async () => {
125
+ const client = new Connector();
126
+ client.send = jest.fn();
127
+ const subsc = {
128
+ params: { channel: 'foo' },
129
+ cb: () => {},
130
+ errorCb: () => {},
131
+ quiet: false,
132
+ };
133
+ client.subscriptions = [subsc];
134
+
135
+ client.connect(`ws://foo:1234`);
136
+ client.websocket.addEventListener = jest.fn();
137
+ client.websocket.removeEventListener = jest.fn();
138
+ await server.connected;
139
+ expect(client.websocket.readyState).toBe(WebSocket.OPEN);
140
+ expect(client.send).toHaveBeenCalledTimes(2);
141
+ expect(client.send.mock.calls[0]).toEqual(['GET foo']);
142
+ expect(client.send.mock.calls[1]).toEqual(['SUB foo']);
143
+ client.send.mockReset();
144
+
145
+ client.connect(`ws://foo:12345`);
146
+ client.websocket.addEventListener = jest.fn();
147
+ client.websocket.removeEventListener = jest.fn();
148
+ await server2.connected;
149
+ expect(client.websocket.readyState).toBe(WebSocket.OPEN);
150
+ // not quiet subscriptions will send GET and SUB requests.
151
+ expect(client.send).toHaveBeenCalledTimes(2);
152
+ expect(client.send.mock.calls[0]).toEqual(['GET foo']);
153
+ expect(client.send.mock.calls[1]).toEqual(['SUB foo']);
154
+ });
155
+
156
+ test('doesn\t send GET and SUB for quiet previous subscriptions', async () => {
157
+ const client = new Connector();
158
+ client.send = jest.fn();
159
+ const subsc = {
160
+ params: { channel: 'foo' },
161
+ cb: () => {},
162
+ errorCb: () => {},
163
+ quiet: true,
164
+ };
165
+ client.subscriptions = [subsc];
166
+
167
+ client.connect(`ws://foo:1234`);
168
+ client.websocket.addEventListener = jest.fn();
169
+ client.websocket.removeEventListener = jest.fn();
170
+ await server.connected;
171
+ expect(client.websocket.readyState).toBe(WebSocket.OPEN);
172
+ expect(client.send).toHaveBeenCalledTimes(0);
173
+ client.send.mockReset();
174
+
175
+ client.connect(`ws://foo:12345`);
176
+ client.websocket.addEventListener = jest.fn();
177
+ client.websocket.removeEventListener = jest.fn();
178
+ await server2.connected;
179
+ expect(client.websocket.readyState).toBe(WebSocket.OPEN);
180
+ // not quiet subscriptions will send GET and SUB requests.
181
+ expect(client.send).toHaveBeenCalledTimes(0);
182
+ });
77
183
  });
78
184
 
79
185
  describe('#subscribe', () => {
@@ -199,7 +305,11 @@ describe('WebSocketConnector', () => {
199
305
  client.subscribe(params2, cb2);
200
306
  expect(client.subscriptions.length).toBe(3);
201
307
  expect(client.websocket.removeEventListener).toBeCalledTimes(2);
202
- expect(client.websocket.addEventListener).toBeCalledTimes(9);
308
+ expect(
309
+ client.websocket.addEventListener.mock.calls.filter(
310
+ (c) => c[0] === 'message',
311
+ ).length,
312
+ ).toBe(5);
203
313
 
204
314
  client.unsubscribe('foo');
205
315
  expect(client.subscriptions.length).toBe(1);
package/common/Tracker.js CHANGED
@@ -123,7 +123,7 @@ export default class Tracker {
123
123
 
124
124
  /**
125
125
  * Return the trajectories.
126
- * @returns {array<trajectory>} trajectories
126
+ * @return {array<trajectory>} trajectories
127
127
  */
128
128
  getTrajectories() {
129
129
  return this.trajectories || [];
@@ -203,6 +203,8 @@ export default class Tracker {
203
203
  for (let i = (this.trajectories || []).length - 1; i >= 0; i -= 1) {
204
204
  const traj = this.trajectories[i];
205
205
 
206
+ this.trajectories[i].rendered = false;
207
+
206
208
  // We simplify the traj object
207
209
  const { geometry, timeIntervals, timeOffset } = traj;
208
210
 
@@ -293,16 +295,26 @@ export default class Tracker {
293
295
  return p * pixelRatio;
294
296
  });
295
297
 
296
- // Trajectory with pixel (i.e. within map extent) will be in renderedTrajectories.
297
- this.trajectories[i].rendered = true;
298
- this.renderedTrajectories.push(this.trajectories[i]);
299
- const vehicleImg = this.style(traj, viewState);
298
+ if (
299
+ px[0] < 0 ||
300
+ px[0] > this.canvas.width ||
301
+ px[1] < 0 ||
302
+ px[1] > this.canvas.height
303
+ ) {
304
+ // eslint-disable-next-line no-continue
305
+ continue;
306
+ }
300
307
 
308
+ const vehicleImg = this.style(traj, viewState);
301
309
  if (!vehicleImg) {
302
310
  // eslint-disable-next-line no-continue
303
311
  continue;
304
312
  }
305
313
 
314
+ // Trajectory with pixel (i.e. within map extent) will be in renderedTrajectories.
315
+ this.trajectories[i].rendered = true;
316
+ this.renderedTrajectories.push(this.trajectories[i]);
317
+
306
318
  const imgWidth = vehicleImg.width;
307
319
  const imgHeight = vehicleImg.height;
308
320
 
@@ -186,7 +186,7 @@ export default class Layer extends Observable {
186
186
  * Get a layer property.
187
187
  *
188
188
  * @param {string} name Property name.
189
- * @returns {property} Property
189
+ * @return {property} Property
190
190
  */
191
191
  get(name) {
192
192
  return this.properties[name];
@@ -239,7 +239,7 @@ export default class Layer extends Observable {
239
239
  /**
240
240
  * Returns an array with visible child layers
241
241
  *
242
- * @returns {Layer[]} Visible children
242
+ * @return {Layer[]} Visible children
243
243
  */
244
244
  getVisibleChildren() {
245
245
  return this.children.filter((child) => child.visible);
@@ -248,7 +248,7 @@ export default class Layer extends Observable {
248
248
  /**
249
249
  * Checks whether the layer has child layers with visible set to True
250
250
  *
251
- * @returns {boolean} True if the layer has visible child layers
251
+ * @return {boolean} True if the layer has visible child layers
252
252
  * @deprecated
253
253
  */
254
254
  hasVisibleChildren() {
@@ -259,7 +259,7 @@ export default class Layer extends Observable {
259
259
  * Checks whether the layer has any child layers with visible equal to the input parameter
260
260
  *
261
261
  * @param {boolean} visible The state to check the childlayers against
262
- * @returns {boolean} True if the layer has children with the given visibility
262
+ * @return {boolean} True if the layer has children with the given visibility
263
263
  */
264
264
  hasChildren(visible) {
265
265
  return !!this.children.find((child) => child.visible === visible);
@@ -302,7 +302,7 @@ export default class Layer extends Observable {
302
302
  *
303
303
  * @param {ol/coordinate~Coordinate} coordinate Coordinate.
304
304
  * @param {Object} options Some options. See child classes to see which are supported.
305
- * @returns {Promise<FeatureInfo>} An empty response.
305
+ * @return {Promise<FeatureInfo>} An empty response.
306
306
  */
307
307
  // eslint-disable-next-line no-unused-vars
308
308
  getFeatureInfoAtCoordinate(coordinate, options) {
@@ -9,7 +9,7 @@ export class CopyrightInterface {
9
9
  /**
10
10
  * Return an array of layer's copyright.
11
11
  *
12
- * @returns {String[]} A list of copyrights to render.
12
+ * @return {String[]} A list of copyrights to render.
13
13
  */
14
14
  getCopyrights() {}
15
15
  }