@fleetbase/fleetops-engine 0.2.8 → 0.3.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.
- package/addon/components/context-panel.hbs +5 -0
- package/addon/components/context-panel.js +6 -0
- package/addon/components/driver-card-mini.js +34 -13
- package/addon/components/driver-form-panel.hbs +23 -23
- package/addon/components/driver-form-panel.js +96 -13
- package/addon/components/driver-panel.hbs +12 -12
- package/addon/components/driver-panel.js +125 -21
- package/addon/components/fleet-vehicle-listing.hbs +1 -1
- package/addon/components/live-map.hbs +20 -9
- package/addon/components/live-map.js +1255 -353
- package/addon/components/map-container/toolbar/visibility-control-panel.hbs +66 -0
- package/addon/components/map-container/toolbar/visibility-control-panel.js +74 -0
- package/addon/components/map-container/toolbar/zones-panel.hbs +10 -10
- package/addon/components/map-container/toolbar/zones-panel.js +90 -61
- package/addon/components/map-container/toolbar.hbs +12 -7
- package/addon/components/modals/vehicle-form.hbs +35 -35
- package/addon/components/settings-window.hbs +1 -1
- package/addon/components/vehicle-form-panel.hbs +25 -26
- package/addon/components/vehicle-form-panel.js +95 -12
- package/addon/components/vehicle-panel.hbs +12 -13
- package/addon/components/vehicle-panel.js +130 -20
- package/addon/controllers/management/drivers/index/details.js +53 -0
- package/addon/controllers/management/drivers/index/edit.js +77 -46
- package/addon/controllers/management/drivers/index/new.js +39 -79
- package/addon/controllers/management/drivers/index.js +17 -221
- package/addon/controllers/management/fleets/index/edit.js +1 -1
- package/addon/controllers/management/fleets/index/new.js +1 -1
- package/addon/controllers/management/fuel-reports/index.js +2 -2
- package/addon/controllers/management/vehicles/index/details.js +49 -0
- package/addon/controllers/management/vehicles/index/edit.js +104 -1
- package/addon/controllers/management/vehicles/index/new.js +71 -0
- package/addon/controllers/operations/orders/index/new.js +4 -6
- package/addon/controllers/operations/orders/index/view.js +22 -14
- package/addon/controllers/operations/orders/index.js +124 -50
- package/addon/controllers/operations/service-rates/index/edit.js +1 -1
- package/addon/controllers/operations/service-rates/index/new.js +1 -1
- package/addon/engine.js +6 -0
- package/addon/helpers/is-visibility-control-visible.js +18 -0
- package/addon/routes/application.js +1 -1
- package/addon/routes/home.js +1 -1
- package/addon/routes/management/drivers/index/details.js +5 -0
- package/addon/routes/operations/orders/index/view.js +4 -2
- package/addon/routes/operations/orders/index.js +5 -1
- package/addon/routes/operations/service-rates/index.js +1 -1
- package/addon/routes/operations/zones/index.js +1 -1
- package/addon/services/context-panel.js +173 -0
- package/addon/services/leaflet-contextmenu-manager.js +311 -0
- package/addon/services/leaflet-map-manager.js +61 -0
- package/addon/services/service-areas.js +242 -32
- package/addon/templates/application.hbs +2 -1
- package/addon/templates/management/drivers/index/details.hbs +1 -1
- package/addon/templates/management/drivers/index/edit.hbs +1 -1
- package/addon/templates/management/drivers/index/new.hbs +1 -1
- package/addon/templates/management/vehicles/index/details.hbs +1 -1
- package/addon/templates/management/vehicles/index/edit.hbs +1 -1
- package/addon/templates/management/vehicles/index/new.hbs +1 -1
- package/addon/templates/operations/orders/index/view.hbs +2 -2
- package/addon/templates/operations/orders/index.hbs +1 -1
- package/addon/utils/apply-context-component-arguments.js +31 -0
- package/addon/utils/context-component-callback.js +16 -0
- package/addon/utils/find-leaflet-layer.js +13 -0
- package/addon/utils/fly-to-leaflet-layer.js +25 -0
- package/addon/utils/get-leaflet-layer-by-id.js +12 -0
- package/addon/utils/layer-can-bind-contextmenu.js +3 -0
- package/app/components/context-panel.js +1 -0
- package/app/components/map-container/toolbar/visibility-control-panel.js +1 -0
- package/app/helpers/is-visibility-control-visible.js +1 -0
- package/app/services/context-panel.js +1 -0
- package/app/services/leaflet-contextmenu-manager.js +1 -0
- package/app/services/leaflet-map-manager.js +1 -0
- package/app/utils/apply-context-component-arguments.js +1 -0
- package/app/utils/context-component-callback.js +1 -0
- package/app/utils/find-leaflet-layer.js +1 -0
- package/app/utils/fly-to-leaflet-layer.js +1 -0
- package/app/utils/get-leaflet-layer-by-id.js +1 -0
- package/app/utils/layer-can-bind-contextmenu.js +1 -0
- package/composer.json +11 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/server/migrations/2023_09_14_074512_update_vehicles_table.php +89 -88
- package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +56 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +7 -4
- package/server/src/Http/Filter/VehicleFilter.php +7 -0
- package/server/src/Http/Resources/v1/Vehicle.php +52 -39
- package/server/src/Models/VehicleDevice.php +17 -3
- package/server/src/Models/VehicleDeviceEvent.php +90 -0
- package/addon/services/map-manager.js +0 -3
- package/app/services/map-manager.js +0 -1
|
@@ -1,67 +1,262 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
|
-
import { action,
|
|
4
|
+
import { action, set } from '@ember/object';
|
|
5
5
|
import { isArray } from '@ember/array';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { dasherize, camelize, classify } from '@ember/string';
|
|
7
|
+
import { singularize } from 'ember-inflector';
|
|
8
8
|
import { alias } from '@ember/object/computed';
|
|
9
|
-
import { guidFor } from '@ember/object/internals';
|
|
10
9
|
import { later } from '@ember/runloop';
|
|
11
10
|
import { allSettled } from 'rsvp';
|
|
11
|
+
import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
|
|
12
12
|
|
|
13
13
|
const DEFAULT_LATITUDE = 1.369;
|
|
14
14
|
const DEFAULT_LONGITUDE = 103.8864;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Component which displays live activity.
|
|
18
|
+
*
|
|
19
|
+
* @class
|
|
20
|
+
*/
|
|
16
21
|
export default class LiveMapComponent extends Component {
|
|
22
|
+
/**
|
|
23
|
+
* Inject the `store` service.
|
|
24
|
+
*
|
|
25
|
+
* @memberof LiveMapComponent
|
|
26
|
+
*/
|
|
17
27
|
@service store;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Inject the `fetch` service.
|
|
31
|
+
*
|
|
32
|
+
* @memberof LiveMapComponent
|
|
33
|
+
*/
|
|
18
34
|
@service fetch;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Inject the `socket` service.
|
|
38
|
+
*
|
|
39
|
+
* @memberof LiveMapComponent
|
|
40
|
+
*/
|
|
19
41
|
@service socket;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Inject the `currentUser` service.
|
|
45
|
+
*
|
|
46
|
+
* @memberof LiveMapComponent
|
|
47
|
+
*/
|
|
20
48
|
@service currentUser;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Inject the `notifications` service.
|
|
52
|
+
*
|
|
53
|
+
* @memberof LiveMapComponent
|
|
54
|
+
*/
|
|
21
55
|
@service notifications;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Inject the `serviceAreas` service.
|
|
59
|
+
*
|
|
60
|
+
* @memberof LiveMapComponent
|
|
61
|
+
*/
|
|
22
62
|
@service serviceAreas;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Inject the `appCache` service.
|
|
66
|
+
*
|
|
67
|
+
* @memberof LiveMapComponent
|
|
68
|
+
*/
|
|
23
69
|
@service appCache;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Inject the `universe` service.
|
|
73
|
+
*
|
|
74
|
+
* @memberof LiveMapComponent
|
|
75
|
+
*/
|
|
24
76
|
@service universe;
|
|
25
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Inject the `crud` service.
|
|
80
|
+
*
|
|
81
|
+
* @memberof LiveMapComponent
|
|
82
|
+
*/
|
|
83
|
+
@service crud;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Inject the `contextPanel` service.
|
|
87
|
+
*
|
|
88
|
+
* @memberof LiveMapComponent
|
|
89
|
+
*/
|
|
90
|
+
@service contextPanel;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Inject the `leafletMapManager` service.
|
|
94
|
+
*
|
|
95
|
+
* @memberof LiveMapComponent
|
|
96
|
+
*/
|
|
97
|
+
@service leafletMapManager;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Inject the `leafletContextmenuManager` service.
|
|
101
|
+
*
|
|
102
|
+
* @memberof LiveMapComponent
|
|
103
|
+
*/
|
|
104
|
+
@service leafletContextmenuManager;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* An array of routes.
|
|
108
|
+
* @type {Array}
|
|
109
|
+
* @memberof LiveMapComponent
|
|
110
|
+
*/
|
|
26
111
|
@tracked routes = [];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* An array of drivers.
|
|
115
|
+
* @type {Array}
|
|
116
|
+
* @memberof LiveMapComponent
|
|
117
|
+
*/
|
|
27
118
|
@tracked drivers = [];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* An array of vehicles.
|
|
122
|
+
* @type {Array}
|
|
123
|
+
* @memberof LiveMapComponent
|
|
124
|
+
*/
|
|
125
|
+
@tracked vehicles = [];
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* An array of places.
|
|
129
|
+
* @type {Array}
|
|
130
|
+
* @memberof LiveMapComponent
|
|
131
|
+
*/
|
|
28
132
|
@tracked places = [];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* An array of channels.
|
|
136
|
+
* @type {Array}
|
|
137
|
+
* @memberof LiveMapComponent
|
|
138
|
+
*/
|
|
29
139
|
@tracked channels = [];
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Indicates if data is loading.
|
|
143
|
+
* @type {boolean}
|
|
144
|
+
* @memberof LiveMapComponent
|
|
145
|
+
*/
|
|
30
146
|
@tracked isLoading = true;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Indicates if the component is ready.
|
|
150
|
+
* @type {boolean}
|
|
151
|
+
* @memberof LiveMapComponent
|
|
152
|
+
*/
|
|
31
153
|
@tracked isReady = false;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@tracked
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Controls for visibility.
|
|
157
|
+
* @type {Object}
|
|
158
|
+
* @memberof LiveMapComponent
|
|
159
|
+
*/
|
|
160
|
+
@tracked visibilityControls = {
|
|
161
|
+
vehicles: true,
|
|
162
|
+
onlineVehicles: true,
|
|
163
|
+
offlineVehicles: true,
|
|
164
|
+
drivers: true,
|
|
165
|
+
onlineDrivers: true,
|
|
166
|
+
offlineDrivers: true,
|
|
167
|
+
places: true,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* An array of active service areas.
|
|
172
|
+
* @type {Array}
|
|
173
|
+
* @memberof LiveMapComponent
|
|
174
|
+
*/
|
|
39
175
|
@tracked activeServiceAreas = [];
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* An array of editable map layers.
|
|
179
|
+
* @type {Array}
|
|
180
|
+
* @memberof LiveMapComponent
|
|
181
|
+
*/
|
|
40
182
|
@tracked editableLayers = [];
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The Leaflet map instance.
|
|
186
|
+
* @type {Object}
|
|
187
|
+
* @memberof LiveMapComponent
|
|
188
|
+
*/
|
|
41
189
|
@tracked leafletMap;
|
|
42
|
-
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The map's zoom level.
|
|
193
|
+
* @type {number}
|
|
194
|
+
* @memberof LiveMapComponent
|
|
195
|
+
*/
|
|
196
|
+
@tracked zoom = 12;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* The feature group for drawing on the map.
|
|
200
|
+
* @type {Object}
|
|
201
|
+
* @memberof LiveMapComponent
|
|
202
|
+
*/
|
|
43
203
|
@tracked drawFeatureGroup;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The draw control for the map.
|
|
207
|
+
* @type {Object}
|
|
208
|
+
* @memberof LiveMapComponent
|
|
209
|
+
*/
|
|
44
210
|
@tracked drawControl;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The URL for the map's tile source.
|
|
214
|
+
* @type {string}
|
|
215
|
+
* @memberof LiveMapComponent
|
|
216
|
+
*/
|
|
217
|
+
@tracked tileSourceUrl = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png';
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The latitude for the map view.
|
|
221
|
+
* @type {number}
|
|
222
|
+
* @memberof LiveMapComponent
|
|
223
|
+
*/
|
|
45
224
|
@tracked latitude = DEFAULT_LATITUDE;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The longitude for the map view.
|
|
228
|
+
* @type {number}
|
|
229
|
+
* @memberof LiveMapComponent
|
|
230
|
+
*/
|
|
46
231
|
@tracked longitude = DEFAULT_LONGITUDE;
|
|
47
|
-
@tracked skipSetCoordinates = false;
|
|
48
|
-
@tracked mapId = guidFor(this);
|
|
49
|
-
@alias('currentUser.latitude') userLatitude;
|
|
50
|
-
@alias('currentUser.longitude') userLongitude;
|
|
51
232
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Indicates if coordinate setting should be skipped.
|
|
235
|
+
* @type {boolean}
|
|
236
|
+
* @memberof LiveMapComponent
|
|
237
|
+
*/
|
|
238
|
+
@tracked skipSetCoordinates = false;
|
|
55
239
|
|
|
56
|
-
|
|
57
|
-
|
|
240
|
+
/**
|
|
241
|
+
* Cache for storing original state of resource arrays.
|
|
242
|
+
* @type {Object.<string, Array>}
|
|
243
|
+
* @memberof LiveMapComponent
|
|
244
|
+
*/
|
|
245
|
+
originalResources = {};
|
|
58
246
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
247
|
+
/**
|
|
248
|
+
* The user's latitude from the currentUser.
|
|
249
|
+
* @type {number}
|
|
250
|
+
* @memberof LiveMapComponent
|
|
251
|
+
*/
|
|
252
|
+
@alias('currentUser.latitude') userLatitude;
|
|
62
253
|
|
|
63
|
-
|
|
64
|
-
|
|
254
|
+
/**
|
|
255
|
+
* The user's longitude from the currentUser.
|
|
256
|
+
* @type {number}
|
|
257
|
+
* @memberof LiveMapComponent
|
|
258
|
+
*/
|
|
259
|
+
@alias('currentUser.longitude') userLongitude;
|
|
65
260
|
|
|
66
261
|
/**
|
|
67
262
|
* Creates an instance of LiveMapComponent.
|
|
@@ -69,26 +264,85 @@ export default class LiveMapComponent extends Component {
|
|
|
69
264
|
*/
|
|
70
265
|
constructor() {
|
|
71
266
|
super(...arguments);
|
|
267
|
+
this.skipSetCoordinates = getWithDefault(this.args, 'skipSetCoordinates', false);
|
|
268
|
+
this.zoom = getWithDefault(this.args, 'zoom', 12);
|
|
269
|
+
this.tileSourceUrl = getWithDefault(this.args, 'tileSourceUrl', 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png');
|
|
72
270
|
|
|
73
|
-
|
|
271
|
+
if (this.args.darkMode === true) {
|
|
272
|
+
this.tileSourceUrl = 'https://{s}.tile.jawg.io/jawg-matrix/{z}/{x}/{y}{r}.png?access-token=';
|
|
273
|
+
}
|
|
74
274
|
}
|
|
75
275
|
|
|
76
276
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* ----------------------------------------------------------------------------
|
|
277
|
+
* Initializes the LiveMapComponent by triggering events, setting initial coordinates,
|
|
278
|
+
* and loading required live data.
|
|
80
279
|
*
|
|
81
|
-
*
|
|
280
|
+
* @memberof LiveMapComponent
|
|
281
|
+
* @action
|
|
282
|
+
* @function
|
|
82
283
|
*/
|
|
83
|
-
@action
|
|
284
|
+
@action setupComponent() {
|
|
84
285
|
// trigger that initial coordinates have been set
|
|
85
|
-
this.universe.trigger('livemap.loaded', this);
|
|
286
|
+
this.universe.trigger('fleetops.livemap.loaded', this);
|
|
287
|
+
|
|
288
|
+
// set initial coordinates
|
|
289
|
+
this.setInitialCoordinates();
|
|
86
290
|
|
|
291
|
+
// load required live data
|
|
292
|
+
this.fetchLiveData('routes');
|
|
293
|
+
this.fetchLiveData('vehicles', {
|
|
294
|
+
onLoaded: (vehicles) => {
|
|
295
|
+
this.watchMovingObjects('vehicles', vehicles);
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
this.fetchLiveData('drivers', {
|
|
299
|
+
onLoaded: (drivers) => {
|
|
300
|
+
this.watchMovingObjects('drivers', drivers);
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
this.fetchLiveData('places');
|
|
304
|
+
this.listen();
|
|
305
|
+
this.ready();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Marks the LiveMapComponent as ready by setting the "isReady" property and triggering
|
|
310
|
+
* the "onReady" action and a "fleetops.livemap.ready" event.
|
|
311
|
+
*
|
|
312
|
+
* @memberof LiveMapComponent
|
|
313
|
+
* @function
|
|
314
|
+
*/
|
|
315
|
+
ready() {
|
|
316
|
+
this.isReady = true;
|
|
317
|
+
this.triggerAction('onReady');
|
|
318
|
+
this.universe.trigger('fleetops.livemap.ready', this);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Sets the initial coordinates for the LiveMapComponent.
|
|
323
|
+
*
|
|
324
|
+
* This function checks if initial coordinates are available in the appCache, and if not,
|
|
325
|
+
* it fetches the coordinates using the "getInitialCoordinates" function. It sets the
|
|
326
|
+
* latitude and longitude properties and triggers an event to notify that coordinates
|
|
327
|
+
* have been set.
|
|
328
|
+
*
|
|
329
|
+
* @memberof LiveMapComponent
|
|
330
|
+
* @async
|
|
331
|
+
* @function
|
|
332
|
+
* @returns {Promise<[number, number] | null>} An array containing the latitude and longitude
|
|
333
|
+
* if available, or null if the function is skipped.
|
|
334
|
+
*/
|
|
335
|
+
async setInitialCoordinates() {
|
|
87
336
|
if (this.skipSetCoordinates === false) {
|
|
88
337
|
if (this.appCache.has(['map_latitude', 'map_longitude'])) {
|
|
89
338
|
this.latitude = this.appCache.get('map_latitude');
|
|
90
339
|
this.longitude = this.appCache.get('map_longitude');
|
|
91
340
|
this.isReady = true;
|
|
341
|
+
|
|
342
|
+
// trigger that initial coordinates is set to livemap component
|
|
343
|
+
this.universe.trigger('fleetops.livemap.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
|
|
344
|
+
|
|
345
|
+
return [this.latitude, this.longitude];
|
|
92
346
|
}
|
|
93
347
|
|
|
94
348
|
const { latitude, longitude } = await this.getInitialCoordinates();
|
|
@@ -100,39 +354,49 @@ export default class LiveMapComponent extends Component {
|
|
|
100
354
|
|
|
101
355
|
this.latitude = latitude;
|
|
102
356
|
this.longitude = longitude;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// trigger that initial coordinates have been set
|
|
106
|
-
this.universe.trigger('livemap.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
|
|
107
|
-
|
|
108
|
-
this.routes = await this.fetchActiveRoutes();
|
|
109
|
-
this.drivers = await this.fetchActiveDrivers();
|
|
110
|
-
this.places = await this.fetchActivePlaces();
|
|
111
|
-
this.serviceAreaRecords = await this.fetchServiceAreas();
|
|
112
|
-
this.isReady = true;
|
|
357
|
+
this.isReady = true;
|
|
113
358
|
|
|
114
|
-
|
|
115
|
-
|
|
359
|
+
// trigger that initial coordinates is set to livemap component
|
|
360
|
+
this.universe.trigger('fleetops.livemap.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
|
|
116
361
|
|
|
117
|
-
|
|
118
|
-
this.args.onReady(this);
|
|
362
|
+
return [this.latitude, this.longitude];
|
|
119
363
|
}
|
|
120
364
|
|
|
121
|
-
|
|
122
|
-
this.universe.trigger('livemap.ready', this);
|
|
365
|
+
return null;
|
|
123
366
|
}
|
|
124
367
|
|
|
125
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Sets up the LiveMap component and the Leaflet map instance.
|
|
370
|
+
*
|
|
371
|
+
* This function initializes the LiveMap component, associates it with the Leaflet map instance,
|
|
372
|
+
* triggers the "fleetops.livemap.leaflet_ready" event, and performs additional setup tasks like
|
|
373
|
+
* configuring context menus, hiding draw controls, and associating the map with the "serviceAreas"
|
|
374
|
+
* service. It also triggers the "onLoad" action with the provided event and target.
|
|
375
|
+
*
|
|
376
|
+
* @action
|
|
377
|
+
* @function
|
|
378
|
+
* @param {Event} event - The event object.
|
|
379
|
+
*/
|
|
380
|
+
@action setupMap(event) {
|
|
126
381
|
const { target } = event;
|
|
127
382
|
|
|
128
383
|
// set liveMapComponent component to instance
|
|
129
|
-
set(
|
|
384
|
+
set(target, 'liveMap', this);
|
|
130
385
|
|
|
131
386
|
// set map instance
|
|
132
387
|
this.leafletMap = target;
|
|
133
388
|
|
|
389
|
+
// trigger liveMap ready through universe
|
|
390
|
+
this.universe.trigger('fleetops.livemap.leaflet_ready', event, target);
|
|
391
|
+
|
|
392
|
+
// make fleetops map globally available on the window
|
|
393
|
+
window.FleetOpsLeafletMap = target;
|
|
394
|
+
|
|
395
|
+
// store this component to universe
|
|
396
|
+
this.universe.set('FleetOpsLiveMap', this);
|
|
397
|
+
|
|
134
398
|
// setup context menu
|
|
135
|
-
this.
|
|
399
|
+
this.createMapContextMenu(target);
|
|
136
400
|
|
|
137
401
|
// hide draw controls by default
|
|
138
402
|
this.hideDrawControls();
|
|
@@ -140,98 +404,433 @@ export default class LiveMapComponent extends Component {
|
|
|
140
404
|
// set instance to service areas service
|
|
141
405
|
this.serviceAreas.setMapInstance(target);
|
|
142
406
|
|
|
143
|
-
|
|
144
|
-
|
|
407
|
+
// trigger map loaded event
|
|
408
|
+
this.triggerAction('onLoad', ...arguments);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Invokes an action by name on the current component and its arguments (if defined).
|
|
413
|
+
*
|
|
414
|
+
* This function checks if an action with the specified name exists on the current component.
|
|
415
|
+
* If found, it invokes the action with the provided parameters. It also checks the component's
|
|
416
|
+
* arguments for the action and invokes it if defined.
|
|
417
|
+
*
|
|
418
|
+
* @action
|
|
419
|
+
* @function
|
|
420
|
+
* @param {string} actionName - The name of the action to trigger.
|
|
421
|
+
* @param {...any} params - Optional parameters to pass to the action.
|
|
422
|
+
*/
|
|
423
|
+
@action triggerAction(actionName, ...params) {
|
|
424
|
+
if (typeof this[actionName] === 'function') {
|
|
425
|
+
this[actionName](...params);
|
|
145
426
|
}
|
|
427
|
+
|
|
428
|
+
if (typeof this.args[actionName] === 'function') {
|
|
429
|
+
this.args[actionName](...params);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Fetches live data from the specified path and updates the component state accordingly.
|
|
435
|
+
*
|
|
436
|
+
* @memberof LiveMapComponent
|
|
437
|
+
* @function
|
|
438
|
+
* @param {string} path - The path to fetch live data from.
|
|
439
|
+
* @param {Object} [options={}] - Optional configuration options.
|
|
440
|
+
* @param {Object} [options.params={}] - Additional parameters to include in the request.
|
|
441
|
+
* @param {Function} [options.onLoaded] - A callback function to execute when the data is loaded.
|
|
442
|
+
* @returns {Promise} A promise that resolves with the fetched data.
|
|
443
|
+
*/
|
|
444
|
+
fetchLiveData(path, options = {}) {
|
|
445
|
+
this.isLoading = true;
|
|
446
|
+
|
|
447
|
+
const internalName = camelize(path);
|
|
448
|
+
const callbackFnName = `on${internalName}Loaded`;
|
|
449
|
+
const params = getWithDefault(options, 'params', {});
|
|
450
|
+
|
|
451
|
+
return this.fetch
|
|
452
|
+
.get(`fleet-ops/live/${path}`, params, { normalizeToEmberData: true, normalizeModelType: singularize(internalName) })
|
|
453
|
+
.then((data) => {
|
|
454
|
+
this.triggerAction(callbackFnName);
|
|
455
|
+
this.createVisibilityControl(internalName);
|
|
456
|
+
this[internalName] = data;
|
|
457
|
+
// cache as resource
|
|
458
|
+
this.cacheOriginalResources(internalName);
|
|
459
|
+
|
|
460
|
+
if (typeof options.onLoaded === 'function') {
|
|
461
|
+
options.onLoaded(data);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return data;
|
|
465
|
+
})
|
|
466
|
+
.finally(() => {
|
|
467
|
+
this.isLoading = false;
|
|
468
|
+
});
|
|
146
469
|
}
|
|
147
470
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
471
|
+
/**
|
|
472
|
+
* Creates or updates a visibility control for a specific element by name.
|
|
473
|
+
*
|
|
474
|
+
* @function
|
|
475
|
+
* @param {string} name - The name or identifier for the visibility control.
|
|
476
|
+
* @param {boolean} [visible=true] - A boolean value indicating whether the element is initially visible (default is true).
|
|
477
|
+
*/
|
|
478
|
+
createVisibilityControl(name, visible = true) {
|
|
479
|
+
this.visibilityControls = {
|
|
480
|
+
...this.visibilityControls,
|
|
481
|
+
[name]: visible,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Hide all visibility controls associated with the current instance.
|
|
487
|
+
*/
|
|
488
|
+
hideAll() {
|
|
489
|
+
const controls = Object.keys(this.visibilityControls);
|
|
490
|
+
|
|
491
|
+
for (let i = 0; i < controls.length; i++) {
|
|
492
|
+
const control = controls.objectAt(i);
|
|
493
|
+
this.hide(control);
|
|
151
494
|
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Show all visibility controls associated with the current instance.
|
|
499
|
+
*/
|
|
500
|
+
showAll() {
|
|
501
|
+
const controls = Object.keys(this.visibilityControls);
|
|
152
502
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
503
|
+
for (let i = 0; i < controls.length; i++) {
|
|
504
|
+
const control = controls.objectAt(i);
|
|
505
|
+
this.show(control);
|
|
156
506
|
}
|
|
507
|
+
}
|
|
157
508
|
|
|
158
|
-
|
|
159
|
-
|
|
509
|
+
/**
|
|
510
|
+
* Hides a specific element by name using a visibility control.
|
|
511
|
+
*
|
|
512
|
+
* @function
|
|
513
|
+
* @param {string} name - The name or identifier of the element to hide.
|
|
514
|
+
*/
|
|
515
|
+
hide(name) {
|
|
516
|
+
if (isArray(name)) {
|
|
517
|
+
return name.forEach(this.hide.bind(this));
|
|
518
|
+
}
|
|
160
519
|
|
|
161
|
-
|
|
520
|
+
this.createVisibilityControl(name, false);
|
|
521
|
+
}
|
|
162
522
|
|
|
163
|
-
|
|
164
|
-
|
|
523
|
+
/**
|
|
524
|
+
* Shows a specific element by name using a visibility control.
|
|
525
|
+
*
|
|
526
|
+
* @function
|
|
527
|
+
* @param {string} name - The name or identifier of the element to show.
|
|
528
|
+
*/
|
|
529
|
+
show(name) {
|
|
530
|
+
if (isArray(name)) {
|
|
531
|
+
return name.forEach(this.show.bind(this));
|
|
165
532
|
}
|
|
166
533
|
|
|
167
|
-
|
|
534
|
+
this.createVisibilityControl(name, true);
|
|
168
535
|
}
|
|
169
536
|
|
|
170
|
-
|
|
171
|
-
|
|
537
|
+
/**
|
|
538
|
+
* Toggles the visibility of a control by its name.
|
|
539
|
+
* Calls `hide()` if the control is currently visible, and `show()` otherwise.
|
|
540
|
+
*
|
|
541
|
+
* @param {string} name - The name of the control to toggle.
|
|
542
|
+
* @memberof LiveMapComponent
|
|
543
|
+
*/
|
|
544
|
+
toggleVisibility(name) {
|
|
545
|
+
if (this.isVisible(name)) {
|
|
546
|
+
this.hide(name);
|
|
547
|
+
} else {
|
|
548
|
+
this.show(name);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
172
551
|
|
|
173
|
-
|
|
174
|
-
|
|
552
|
+
/**
|
|
553
|
+
* Check if a specific element or feature is currently visible based on its name.
|
|
554
|
+
*
|
|
555
|
+
* @param {string} name - The name of the element or feature to check visibility for.
|
|
556
|
+
* @returns {boolean} Returns `true` if the element or feature is currently visible, `false` otherwise.
|
|
557
|
+
* @memberof LiveMapComponent
|
|
558
|
+
*/
|
|
559
|
+
isVisible(name) {
|
|
560
|
+
return this.visibilityControls[name] === true;
|
|
561
|
+
}
|
|
175
562
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
563
|
+
/**
|
|
564
|
+
* Caches the original state of a resource array.
|
|
565
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
566
|
+
* @memberof LiveMapComponent
|
|
567
|
+
*/
|
|
568
|
+
cacheOriginalResources(name) {
|
|
569
|
+
if (!this.originalResources[name]) {
|
|
570
|
+
this.originalResources[name] = [...this[name]];
|
|
571
|
+
}
|
|
572
|
+
}
|
|
179
573
|
|
|
180
|
-
|
|
181
|
-
|
|
574
|
+
/**
|
|
575
|
+
* Retrieves the original resources array for a given name.
|
|
576
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
577
|
+
* @returns {Array} - The original array of resources; an empty array if not set.
|
|
578
|
+
* @memberof LiveMapComponent
|
|
579
|
+
*/
|
|
580
|
+
getOriginalResources(name) {
|
|
581
|
+
if (isArray(this.originalResources[name])) {
|
|
582
|
+
return this.originalResources[name];
|
|
182
583
|
}
|
|
584
|
+
|
|
585
|
+
return [];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Shows all online and offline resources for a given name.
|
|
590
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
591
|
+
* @memberof LiveMapComponent
|
|
592
|
+
*/
|
|
593
|
+
showAllOnlineOffline(name) {
|
|
594
|
+
this.show(name);
|
|
595
|
+
this.showOnline(name);
|
|
596
|
+
this.showOffline(name);
|
|
183
597
|
}
|
|
184
598
|
|
|
185
|
-
|
|
186
|
-
|
|
599
|
+
/**
|
|
600
|
+
* Hides all online and offline resources for a given name.
|
|
601
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
602
|
+
* @memberof LiveMapComponent
|
|
603
|
+
*/
|
|
604
|
+
hideAllOnlineOffline(name) {
|
|
605
|
+
this.hide(name);
|
|
606
|
+
this.hideOnline(name);
|
|
607
|
+
this.hideOffline(name);
|
|
608
|
+
}
|
|
187
609
|
|
|
188
|
-
|
|
189
|
-
|
|
610
|
+
/**
|
|
611
|
+
* Toggles the visibility of all online and offline resources for a given name.
|
|
612
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
613
|
+
* @memberof LiveMapComponent
|
|
614
|
+
*/
|
|
615
|
+
toggleAllOnlineOffline(name) {
|
|
616
|
+
if (this.isVisible(name)) {
|
|
617
|
+
this.hideAllOnlineOffline(name);
|
|
618
|
+
} else {
|
|
619
|
+
this.showAllOnlineOffline(name);
|
|
190
620
|
}
|
|
191
621
|
}
|
|
192
622
|
|
|
193
|
-
|
|
194
|
-
|
|
623
|
+
/**
|
|
624
|
+
* Toggles the visibility of online resources for a given array.
|
|
625
|
+
* @method toggleOnline
|
|
626
|
+
* @param {string} name - The name of the resource array (e.g., 'vehicles', 'drivers').
|
|
627
|
+
* @memberof LiveMapComponent
|
|
628
|
+
*/
|
|
629
|
+
toggleOnline(name) {
|
|
630
|
+
const visibilityControlName = `online${classify(name)}`;
|
|
195
631
|
|
|
196
|
-
if (
|
|
197
|
-
this.
|
|
632
|
+
if (this.isVisible(visibilityControlName)) {
|
|
633
|
+
this.hideOnline(name);
|
|
634
|
+
} else {
|
|
635
|
+
this.showOnline(name);
|
|
198
636
|
}
|
|
199
637
|
}
|
|
200
638
|
|
|
201
|
-
|
|
202
|
-
|
|
639
|
+
/**
|
|
640
|
+
* Toggles the visibility of offline resources for a given array.
|
|
641
|
+
* @method toggleOffline
|
|
642
|
+
* @param {string} name - The name of the resource array (e.g., 'vehicles', 'drivers').
|
|
643
|
+
* @memberof LiveMapComponent
|
|
644
|
+
*/
|
|
645
|
+
toggleOffline(name) {
|
|
646
|
+
const visibilityControlName = `offline${classify(name)}`;
|
|
647
|
+
|
|
648
|
+
if (this.isVisible(visibilityControlName)) {
|
|
649
|
+
this.hideOffline(name);
|
|
650
|
+
} else {
|
|
651
|
+
this.showOffline(name);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Hides online resources from a given array and updates it.
|
|
657
|
+
* @method hideOnline
|
|
658
|
+
* @param {string} name - The name of the resource array (e.g., 'vehicles', 'drivers').
|
|
659
|
+
* @memberof LiveMapComponent
|
|
660
|
+
*/
|
|
661
|
+
hideOnline(name) {
|
|
662
|
+
this[name] = this.getOriginalResources(name).filter((resource) => !resource.online);
|
|
663
|
+
|
|
664
|
+
// track with visibility controls
|
|
665
|
+
this.createVisibilityControl(`online${classify(name)}`, false);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Shows online resources from a given array and updates it.
|
|
670
|
+
* @method showOnline
|
|
671
|
+
* @param {string} name - The name of the resource array (e.g., 'vehicles', 'drivers').
|
|
672
|
+
* @memberof LiveMapComponent
|
|
673
|
+
*/
|
|
674
|
+
showOnline(name) {
|
|
675
|
+
this[name] = this.getOriginalResources(name).filter((resource) => resource.online);
|
|
676
|
+
|
|
677
|
+
// track with visibility controls
|
|
678
|
+
this.createVisibilityControl(`online${classify(name)}`, true);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Hides offline resources from a specified array.
|
|
683
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
684
|
+
* @memberof LiveMapComponent
|
|
685
|
+
*/
|
|
686
|
+
hideOffline(name) {
|
|
687
|
+
this[name] = this.getOriginalResources(name).filter((resource) => resource.online);
|
|
688
|
+
|
|
689
|
+
// track with visibility controls
|
|
690
|
+
this.createVisibilityControl(`offline${classify(name)}`, false);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Shows offline resources from a specified array.
|
|
695
|
+
* @param {string} name - Name of the resource array (e.g., 'vehicles', 'drivers').
|
|
696
|
+
* @memberof LiveMapComponent
|
|
697
|
+
*/
|
|
698
|
+
showOffline(name) {
|
|
699
|
+
this[name] = this.getOriginalResources(name).filter((resource) => !resource.online);
|
|
700
|
+
|
|
701
|
+
// track with visibility controls
|
|
702
|
+
this.createVisibilityControl(`offline${classify(name)}`, true);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Toggles the context menu item for enabling/disabling draw controls.
|
|
707
|
+
*
|
|
708
|
+
* @param {Object} [options] - Optional settings for the context menu item.
|
|
709
|
+
* @param {string} [options.onText='Hide draw controls...'] - Text to display when enabling draw controls.
|
|
710
|
+
* @param {string} [options.offText='Enable draw controls...'] - Text to display when disabling draw controls.
|
|
711
|
+
* @param {string} [options.callback=function] - Callback function to trigger after toggle.
|
|
712
|
+
* @memberof LiveMapComponent
|
|
713
|
+
*/
|
|
714
|
+
toggleDrawControlContextMenuItem(options = {}) {
|
|
715
|
+
const toggle = !this.isVisible('drawControls');
|
|
716
|
+
|
|
717
|
+
this.leafletContextmenuManager.toggleContextMenuItem('map', 'draw controls', {
|
|
718
|
+
onText: 'Hide draw controls...',
|
|
719
|
+
offText: 'Enable draw controls...',
|
|
720
|
+
toggle,
|
|
721
|
+
callback: (isToggled) => {
|
|
722
|
+
if (isToggled) {
|
|
723
|
+
this.showDrawControls();
|
|
724
|
+
} else {
|
|
725
|
+
this.hideDrawControls();
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
...options,
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Removes a specific service area from the context menu.
|
|
734
|
+
*
|
|
735
|
+
* @param {Object} serviceArea - The service area to be removed from the context menu.
|
|
736
|
+
* @memberof LiveMapComponent
|
|
737
|
+
*/
|
|
738
|
+
removeServiceAreaFromContextMenu(serviceArea) {
|
|
739
|
+
this.leafletContextmenuManager.removeItemFromContextMenu('map', `Focus Service Area: ${serviceArea.name}`);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Get a Leaflet layer from the map based on its ID.
|
|
744
|
+
*
|
|
745
|
+
* @param {string} id - The ID of the Leaflet layer to retrieve.
|
|
746
|
+
* @returns {Object|null} The found Leaflet layer or `null` if not found.
|
|
747
|
+
* @memberof LiveMapComponent
|
|
748
|
+
*/
|
|
749
|
+
getLeafletLayerById(id) {
|
|
750
|
+
return this.leafletMapManager.getLeafletLayerById(this.leafletMap, id);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Find a specific Leaflet layer on the map using a callback function.
|
|
755
|
+
*
|
|
756
|
+
* @param {Function} callback - A callback function that defines the condition for finding the layer.
|
|
757
|
+
* @returns {Object|null} The found Leaflet layer or `null` if not found.
|
|
758
|
+
* @memberof LiveMapComponent
|
|
759
|
+
*/
|
|
760
|
+
findLeafletLayer(callback) {
|
|
761
|
+
return this.leafletMapManager.findLeafletLayer(this.leafletMap, callback);
|
|
203
762
|
}
|
|
204
763
|
|
|
205
|
-
|
|
206
|
-
|
|
764
|
+
/**
|
|
765
|
+
* Find an editable layer in the collection by its record ID.
|
|
766
|
+
*
|
|
767
|
+
* @param {Object} record - The record with the ID used for lookup.
|
|
768
|
+
* @returns {Layer|null} The found editable layer, or null if not found.
|
|
769
|
+
* @memberof LiveMapComponent
|
|
770
|
+
*/
|
|
771
|
+
getLeafletLayerByRecordId(record) {
|
|
772
|
+
const id = getWithDefault(record, 'id', record);
|
|
773
|
+
let targetLayer = null;
|
|
774
|
+
|
|
775
|
+
this.leafletMap.eachLayer((layer) => {
|
|
776
|
+
// Check if the layer has an ID property
|
|
777
|
+
if (layer.record_id === id) {
|
|
778
|
+
targetLayer = layer;
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
return targetLayer;
|
|
207
783
|
}
|
|
208
784
|
|
|
209
785
|
/**
|
|
210
|
-
*
|
|
211
|
-
* TRACKED LAYER UTILITIES
|
|
212
|
-
* ----------------------------------------------------------------------------
|
|
786
|
+
* Push an editable layer to the collection of editable layers.
|
|
213
787
|
*
|
|
214
|
-
*
|
|
788
|
+
* @param {Layer} layer - The layer to be added to the collection.
|
|
789
|
+
* @memberof LiveMapComponent
|
|
215
790
|
*/
|
|
216
|
-
|
|
791
|
+
pushEditableLayer(layer) {
|
|
217
792
|
if (!this.editableLayers.includes(layer)) {
|
|
218
793
|
this.editableLayers.pushObject(layer);
|
|
219
794
|
}
|
|
220
795
|
}
|
|
221
796
|
|
|
222
|
-
|
|
223
|
-
|
|
797
|
+
/**
|
|
798
|
+
* Remove an editable layer from the collection by its record ID.
|
|
799
|
+
*
|
|
800
|
+
* @param {Object} record - The record with the ID used for removal.
|
|
801
|
+
* @memberof LiveMapComponent
|
|
802
|
+
*/
|
|
803
|
+
removeEditableLayerByRecordId(record) {
|
|
804
|
+
const id = getWithDefault(record, 'id', record);
|
|
805
|
+
const index = this.editableLayers.findIndex((layer) => layer.record_id === id);
|
|
224
806
|
const layer = this.editableLayers.objectAt(index);
|
|
225
807
|
|
|
226
|
-
this.drawFeatureGroup
|
|
227
|
-
|
|
808
|
+
if (this.drawFeatureGroup) {
|
|
809
|
+
this.drawFeatureGroup.addLayer(layer);
|
|
810
|
+
this.editableLayers.removeAt(index);
|
|
811
|
+
}
|
|
228
812
|
}
|
|
229
813
|
|
|
230
|
-
|
|
231
|
-
|
|
814
|
+
/**
|
|
815
|
+
* Find an editable layer in the collection by its record ID.
|
|
816
|
+
*
|
|
817
|
+
* @param {Object} record - The record with the ID used for lookup.
|
|
818
|
+
* @returns {Layer|null} The found editable layer, or null if not found.
|
|
819
|
+
* @memberof LiveMapComponent
|
|
820
|
+
*/
|
|
821
|
+
findEditableLayerByRecordId(record) {
|
|
822
|
+
const id = getWithDefault(record, 'id', record);
|
|
823
|
+
return this.editableLayers.find((layer) => layer.record_id === id);
|
|
232
824
|
}
|
|
233
825
|
|
|
234
|
-
|
|
826
|
+
/**
|
|
827
|
+
* Peek a record for a given layer by its record ID and type.
|
|
828
|
+
*
|
|
829
|
+
* @param {Layer} layer - The layer associated with a record.
|
|
830
|
+
* @returns {Object|null} The peeked record, or null if not found.
|
|
831
|
+
* @memberof LiveMapComponent
|
|
832
|
+
*/
|
|
833
|
+
peekRecordForLayer(layer) {
|
|
235
834
|
if (layer.record_id && layer.record_type) {
|
|
236
835
|
return this.store.peekRecord(dasherize(layer.record_type), layer.record_id);
|
|
237
836
|
}
|
|
@@ -240,27 +839,22 @@ export default class LiveMapComponent extends Component {
|
|
|
240
839
|
}
|
|
241
840
|
|
|
242
841
|
/**
|
|
243
|
-
*
|
|
244
|
-
* LAYER EVENTS
|
|
245
|
-
* ----------------------------------------------------------------------------
|
|
842
|
+
* Handle the 'drawstop' event.
|
|
246
843
|
*
|
|
247
|
-
*
|
|
844
|
+
* @param {Event} event - The 'drawstop' event object.
|
|
845
|
+
* @param {Layer} layer - The layer associated with the event.
|
|
846
|
+
* @memberof LiveMapComponent
|
|
248
847
|
*/
|
|
249
|
-
|
|
250
|
-
@action onAction(actionName, ...params) {
|
|
251
|
-
if (typeof this[actionName] === 'function') {
|
|
252
|
-
this[actionName](...params);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (typeof this.args[actionName] === 'function') {
|
|
256
|
-
this.args[actionName](...params);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
848
|
@action onDrawDrawstop(event, layer) {
|
|
261
849
|
this.serviceAreas.createGenericLayer(event, layer);
|
|
262
850
|
}
|
|
263
851
|
|
|
852
|
+
/**
|
|
853
|
+
* Handle the 'deleted' event for drawn elements.
|
|
854
|
+
*
|
|
855
|
+
* @param {Event} event - The 'deleted' event object.
|
|
856
|
+
* @memberof LiveMapComponent
|
|
857
|
+
*/
|
|
264
858
|
@action onDrawDeleted(event) {
|
|
265
859
|
/** @var {L.LayerGroup} layers */
|
|
266
860
|
const { layers } = event;
|
|
@@ -278,6 +872,12 @@ export default class LiveMapComponent extends Component {
|
|
|
278
872
|
});
|
|
279
873
|
}
|
|
280
874
|
|
|
875
|
+
/**
|
|
876
|
+
* Handle the 'edited' event for drawn elements.
|
|
877
|
+
*
|
|
878
|
+
* @param {Event} event - The 'edited' event object.
|
|
879
|
+
* @memberof LiveMapComponent
|
|
880
|
+
*/
|
|
281
881
|
@action onDrawEdited(event) {
|
|
282
882
|
/** @var {L.LayerGroup} layers */
|
|
283
883
|
const { layers } = event;
|
|
@@ -301,89 +901,219 @@ export default class LiveMapComponent extends Component {
|
|
|
301
901
|
allSettled(requests);
|
|
302
902
|
}
|
|
303
903
|
|
|
904
|
+
/**
|
|
905
|
+
* Handle the addition of a service area layer.
|
|
906
|
+
*
|
|
907
|
+
* @param {ServiceAreaModel} serviceArea - The service area object.
|
|
908
|
+
* @param {Event} event - The event object associated with the addition.
|
|
909
|
+
* @memberof LiveMapComponent
|
|
910
|
+
*/
|
|
304
911
|
@action onServiceAreaLayerAdded(serviceArea, event) {
|
|
305
912
|
const { target } = event;
|
|
306
913
|
|
|
307
914
|
set(target, 'record_id', serviceArea.id);
|
|
308
915
|
set(target, 'record_type', 'service-area');
|
|
309
916
|
|
|
310
|
-
//
|
|
311
|
-
|
|
917
|
+
// set the layer instance to the serviceArea model
|
|
918
|
+
set(serviceArea, '_layer', target);
|
|
919
|
+
|
|
920
|
+
if (this.drawFeatureGroup) {
|
|
921
|
+
// add to draw feature group
|
|
922
|
+
this.drawFeatureGroup.addLayer(target);
|
|
923
|
+
}
|
|
312
924
|
|
|
313
925
|
// this.flyToBoundsOnly(target);
|
|
314
|
-
this.
|
|
926
|
+
this.createServiceAreaContextMenu(serviceArea, target);
|
|
315
927
|
this.pushEditableLayer(target);
|
|
316
928
|
}
|
|
317
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Handle the addition of a zone layer.
|
|
932
|
+
*
|
|
933
|
+
* @param {ZoneModel} zone - The zone object.
|
|
934
|
+
* @param {Event} event - The event object associated with the addition.
|
|
935
|
+
* @memberof LiveMapComponent
|
|
936
|
+
*/
|
|
318
937
|
@action onZoneLayerAdd(zone, event) {
|
|
319
938
|
const { target } = event;
|
|
320
939
|
|
|
321
940
|
set(target, 'record_id', zone.id);
|
|
322
941
|
set(target, 'record_type', 'zone');
|
|
323
942
|
|
|
324
|
-
//
|
|
325
|
-
|
|
943
|
+
// set the layer instance to the zone model
|
|
944
|
+
set(zone, '_layer', target);
|
|
945
|
+
|
|
946
|
+
if (this.drawFeatureGroup) {
|
|
947
|
+
// add to draw feature group
|
|
948
|
+
this.drawFeatureGroup.addLayer(target);
|
|
949
|
+
}
|
|
326
950
|
|
|
327
|
-
this.
|
|
951
|
+
this.createZoneContextMenu(zone, target);
|
|
328
952
|
this.pushEditableLayer(target);
|
|
329
953
|
}
|
|
330
954
|
|
|
955
|
+
/**
|
|
956
|
+
* Handle the creation of the draw feature group.
|
|
957
|
+
*
|
|
958
|
+
* @param {DrawFeatureGroup} drawFeatureGroup - The draw feature group instance.
|
|
959
|
+
* @memberof LiveMapComponent
|
|
960
|
+
*/
|
|
331
961
|
@action onDrawFeatureGroupCreated(drawFeatureGroup) {
|
|
332
962
|
this.drawFeatureGroup = drawFeatureGroup;
|
|
333
963
|
}
|
|
334
964
|
|
|
335
|
-
|
|
336
|
-
|
|
965
|
+
/**
|
|
966
|
+
* Handle the addition of a driver marker.
|
|
967
|
+
*
|
|
968
|
+
* @param {DriverModel} driver - The driver object.
|
|
969
|
+
* @param {Event} event - The event object associated with the addition.
|
|
970
|
+
* @memberof LiveMapComponent
|
|
971
|
+
*/
|
|
972
|
+
@action onDriverAdded(driver, event) {
|
|
973
|
+
const { target } = event;
|
|
974
|
+
|
|
975
|
+
set(target, 'record_id', driver.id);
|
|
976
|
+
set(target, 'record_type', 'driver');
|
|
977
|
+
|
|
978
|
+
// set the marker instance to the driver model
|
|
979
|
+
set(driver, '_marker', target);
|
|
980
|
+
|
|
981
|
+
this.createDriverContextMenu(driver, target);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Handle the click event of a driver marker.
|
|
986
|
+
*
|
|
987
|
+
* @param {DriverModel} driver - The driver object.
|
|
988
|
+
* @param {Event} event - The event object associated with the addition.
|
|
989
|
+
* @memberof LiveMapComponent
|
|
990
|
+
*/
|
|
991
|
+
@action onDriverClicked(driver) {
|
|
992
|
+
this.contextPanel.focus(driver);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Handle the addition of a vehicle marker.
|
|
997
|
+
*
|
|
998
|
+
* @param {VehicleModel} vehicle - The vehicle object.
|
|
999
|
+
* @param {Event} event - The event object associated with the addition.
|
|
1000
|
+
* @memberof LiveMapComponent
|
|
1001
|
+
*/
|
|
1002
|
+
@action onVehicleAdded(vehicle, event) {
|
|
1003
|
+
const { target } = event;
|
|
1004
|
+
|
|
1005
|
+
set(target, 'record_id', vehicle.id);
|
|
1006
|
+
set(target, 'record_type', 'vehicle');
|
|
1007
|
+
|
|
1008
|
+
// set the marker instance to the vehicle model
|
|
1009
|
+
set(vehicle, '_marker', target);
|
|
1010
|
+
|
|
1011
|
+
this.createVehicleContextMenu(vehicle, target);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Handle the click event of a vehicle marker.
|
|
1016
|
+
*
|
|
1017
|
+
* @param {VehicleModel} vehicle - The vehicle object.
|
|
1018
|
+
* @param {Event} event - The event object associated with the addition.
|
|
1019
|
+
* @memberof LiveMapComponent
|
|
1020
|
+
*/
|
|
1021
|
+
@action onVehicleClicked(vehicle) {
|
|
1022
|
+
this.contextPanel.focus(vehicle);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Handle the creation of the draw control.
|
|
1027
|
+
*
|
|
1028
|
+
* @param {DrawControl} drawControl - The draw control instance.
|
|
1029
|
+
* @memberof LiveMapComponent
|
|
1030
|
+
*/
|
|
1031
|
+
@action onDrawControlCreated(drawControl) {
|
|
1032
|
+
this.drawControl = drawControl;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Hide the draw controls on the map.
|
|
1037
|
+
*
|
|
1038
|
+
* @param {Object} [options={}] - Additional options.
|
|
1039
|
+
* @param {string|boolean} [options.text] - Text to set for the menu item or `true` to set the default text.
|
|
1040
|
+
* @param {function} [options.callback] - A callback function to execute.
|
|
1041
|
+
* @memberof LiveMapComponent
|
|
1042
|
+
*/
|
|
1043
|
+
@action hideDrawControls(options = {}) {
|
|
1044
|
+
this.hide('drawControls');
|
|
1045
|
+
|
|
1046
|
+
const text = getWithDefault(options, 'text');
|
|
1047
|
+
const callback = getWithDefault(options, 'callback');
|
|
337
1048
|
|
|
338
|
-
|
|
339
|
-
|
|
1049
|
+
if (typeof callback === 'function') {
|
|
1050
|
+
callback();
|
|
1051
|
+
}
|
|
340
1052
|
|
|
341
|
-
|
|
1053
|
+
if (typeof text === 'string') {
|
|
1054
|
+
this.leafletContextmenuManager.changeMenuItemText('map', 'draw controls', text);
|
|
1055
|
+
}
|
|
342
1056
|
|
|
343
|
-
|
|
344
|
-
|
|
1057
|
+
if (text === true) {
|
|
1058
|
+
this.leafletContextmenuManager.changeMenuItemText('map', 'draw controls', 'Enable draw controls...');
|
|
1059
|
+
}
|
|
345
1060
|
|
|
346
|
-
|
|
347
|
-
|
|
1061
|
+
if (this.drawControl) {
|
|
1062
|
+
this.leafletMap.removeControl(this.drawControl);
|
|
1063
|
+
}
|
|
348
1064
|
}
|
|
349
1065
|
|
|
350
1066
|
/**
|
|
351
|
-
*
|
|
352
|
-
* LEAFLET UTILITIES
|
|
353
|
-
* ----------------------------------------------------------------------------
|
|
354
|
-
*
|
|
355
|
-
* Functions are used to help or utilize on Leaflet Layers/ Controls.
|
|
1067
|
+
* Show the draw controls on the map.
|
|
356
1068
|
*
|
|
1069
|
+
* @param {Object} [options={}] - Additional options.
|
|
1070
|
+
* @param {string|boolean} [options.text] - Text to set for the menu item or `true` to set the default text.
|
|
1071
|
+
* @param {function} [options.callback] - A callback function to execute.
|
|
1072
|
+
* @memberof LiveMapComponent
|
|
357
1073
|
*/
|
|
358
|
-
@action
|
|
359
|
-
|
|
360
|
-
|
|
1074
|
+
@action showDrawControls(options = {}) {
|
|
1075
|
+
this.show('drawControls');
|
|
1076
|
+
|
|
1077
|
+
const text = getWithDefault(options, 'text');
|
|
1078
|
+
const callback = getWithDefault(options, 'callback');
|
|
1079
|
+
|
|
1080
|
+
if (typeof callback === 'function') {
|
|
1081
|
+
callback();
|
|
361
1082
|
}
|
|
362
1083
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
1084
|
+
if (typeof text === 'string') {
|
|
1085
|
+
this.leafletContextmenuManager.changeMenuItemText('map', 'draw controls', text);
|
|
1086
|
+
}
|
|
367
1087
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
1088
|
+
if (text === true) {
|
|
1089
|
+
this.leafletContextmenuManager.changeMenuItemText('map', 'draw controls', 'Hide draw controls...');
|
|
1090
|
+
}
|
|
372
1091
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
this.toggleDrawControlContextMenuItem();
|
|
1092
|
+
if (this.drawControl) {
|
|
1093
|
+
this.leafletMap.addControl(this.drawControl);
|
|
1094
|
+
}
|
|
377
1095
|
}
|
|
378
1096
|
|
|
379
|
-
|
|
380
|
-
|
|
1097
|
+
/**
|
|
1098
|
+
* Focus on a layer associated with a record.
|
|
1099
|
+
*
|
|
1100
|
+
* @param {Object} record - The record to focus on.
|
|
1101
|
+
* @memberof LiveMapComponent
|
|
1102
|
+
*/
|
|
1103
|
+
@action focusLayerBoundsByRecord(record) {
|
|
1104
|
+
const layer = this.getLeafletLayerByRecordId(record);
|
|
381
1105
|
|
|
382
1106
|
if (layer) {
|
|
383
1107
|
this.flyToBoundsOnly(layer);
|
|
384
1108
|
}
|
|
385
1109
|
}
|
|
386
1110
|
|
|
1111
|
+
/**
|
|
1112
|
+
* Fly to a service area layer on the map.
|
|
1113
|
+
*
|
|
1114
|
+
* @param {ServiceAreaModel} serviceArea - The service area object to fly to.
|
|
1115
|
+
* @memberof LiveMapComponent
|
|
1116
|
+
*/
|
|
387
1117
|
@action flyToServiceArea(serviceArea) {
|
|
388
1118
|
const layer = this.findEditableLayerByRecordId(serviceArea);
|
|
389
1119
|
|
|
@@ -392,11 +1122,12 @@ export default class LiveMapComponent extends Component {
|
|
|
392
1122
|
}
|
|
393
1123
|
}
|
|
394
1124
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
1125
|
+
/**
|
|
1126
|
+
* Focus on a service area by activating it and then flying to it on the map.
|
|
1127
|
+
*
|
|
1128
|
+
* @param {ServiceArea} serviceArea - The service area to focus on.
|
|
1129
|
+
* @memberof LiveMapComponent
|
|
1130
|
+
*/
|
|
400
1131
|
@action focusServiceArea(serviceArea) {
|
|
401
1132
|
this.activateServiceArea(serviceArea);
|
|
402
1133
|
|
|
@@ -409,7 +1140,13 @@ export default class LiveMapComponent extends Component {
|
|
|
409
1140
|
);
|
|
410
1141
|
}
|
|
411
1142
|
|
|
412
|
-
|
|
1143
|
+
/**
|
|
1144
|
+
* Blur all service areas except for those specified in the 'except' array.
|
|
1145
|
+
*
|
|
1146
|
+
* @param {Array} except - An array of records to exclude from blurring.
|
|
1147
|
+
* @memberof LiveMapComponent
|
|
1148
|
+
*/
|
|
1149
|
+
blurAllServiceAreas(except = []) {
|
|
413
1150
|
if (!isArray(except)) {
|
|
414
1151
|
except = [];
|
|
415
1152
|
}
|
|
@@ -441,7 +1178,13 @@ export default class LiveMapComponent extends Component {
|
|
|
441
1178
|
}
|
|
442
1179
|
}
|
|
443
1180
|
|
|
444
|
-
|
|
1181
|
+
/**
|
|
1182
|
+
* Focus on all service areas except for those specified in the 'except' array by activating them.
|
|
1183
|
+
*
|
|
1184
|
+
* @param {Array} except - An array of records to exclude from activation.
|
|
1185
|
+
* @memberof LiveMapComponent
|
|
1186
|
+
*/
|
|
1187
|
+
focusAllServiceAreas(except = []) {
|
|
445
1188
|
if (!isArray(except)) {
|
|
446
1189
|
except = [];
|
|
447
1190
|
}
|
|
@@ -463,93 +1206,143 @@ export default class LiveMapComponent extends Component {
|
|
|
463
1206
|
}
|
|
464
1207
|
}
|
|
465
1208
|
|
|
466
|
-
|
|
1209
|
+
/**
|
|
1210
|
+
* Blur a specific service area by removing it from the active service areas.
|
|
1211
|
+
*
|
|
1212
|
+
* @param {ServiceAreaModel} serviceArea - The service area to blur.
|
|
1213
|
+
* @memberof LiveMapComponent
|
|
1214
|
+
*/
|
|
1215
|
+
blurServiceArea(serviceArea) {
|
|
467
1216
|
if (this.activeServiceAreas.includes(serviceArea)) {
|
|
468
1217
|
this.activeServiceAreas.removeObject(serviceArea);
|
|
469
1218
|
}
|
|
470
1219
|
}
|
|
471
1220
|
|
|
472
|
-
|
|
1221
|
+
/**
|
|
1222
|
+
* Activate a service area by adding it to the active service areas.
|
|
1223
|
+
*
|
|
1224
|
+
* @param {ServiceAreaModel} serviceArea - The service area to activate.
|
|
1225
|
+
* @memberof LiveMapComponent
|
|
1226
|
+
*/
|
|
1227
|
+
activateServiceArea(serviceArea) {
|
|
473
1228
|
if (!this.activeServiceAreas.includes(serviceArea)) {
|
|
474
1229
|
this.activeServiceAreas.pushObject(serviceArea);
|
|
475
1230
|
}
|
|
476
1231
|
}
|
|
477
1232
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
@action toggleDrivers() {
|
|
487
|
-
this.isDriversVisible = !this.isDriversVisible;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
@action hidePlaces() {
|
|
491
|
-
this.isPlacesVisible = false;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
@action showPlaces() {
|
|
495
|
-
this.isPlacesVisible = true;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
@action togglePlaces() {
|
|
499
|
-
this.isPlacesVisible = !this.isPlacesVisible;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
@action hideRoutes() {
|
|
503
|
-
this.isRoutesVisible = false;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
@action showRoutes() {
|
|
507
|
-
this.isRoutesVisible = true;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
@action toggleRoutes() {
|
|
511
|
-
this.isRoutesVisible = !this.isRoutesVisible;
|
|
512
|
-
}
|
|
513
|
-
|
|
1233
|
+
/**
|
|
1234
|
+
* Show coordinates information by displaying them as an info notification.
|
|
1235
|
+
*
|
|
1236
|
+
* @param {Event} event - The event containing latitude and longitude information.
|
|
1237
|
+
* @memberof LiveMapComponent
|
|
1238
|
+
*/
|
|
514
1239
|
@action showCoordinates(event) {
|
|
515
1240
|
this.notifications.info(event.latlng);
|
|
516
1241
|
}
|
|
517
1242
|
|
|
1243
|
+
/**
|
|
1244
|
+
* Center the map on a specific location provided in the event.
|
|
1245
|
+
*
|
|
1246
|
+
* @param {Event} event - The event containing the target location (latlng).
|
|
1247
|
+
* @memberof LiveMapComponent
|
|
1248
|
+
*/
|
|
518
1249
|
@action centerMap(event) {
|
|
519
|
-
this.leafletMap
|
|
1250
|
+
this.leafletMap.panTo(event.latlng);
|
|
520
1251
|
}
|
|
521
1252
|
|
|
1253
|
+
/**
|
|
1254
|
+
* Zoom in on the map.
|
|
1255
|
+
*
|
|
1256
|
+
* @memberof LiveMapComponent
|
|
1257
|
+
*/
|
|
522
1258
|
@action zoomIn() {
|
|
523
|
-
this.leafletMap
|
|
1259
|
+
this.leafletMap.zoomIn();
|
|
524
1260
|
}
|
|
525
1261
|
|
|
1262
|
+
/**
|
|
1263
|
+
* Zoom out on the map.
|
|
1264
|
+
*
|
|
1265
|
+
* @memberof LiveMapComponent
|
|
1266
|
+
*/
|
|
526
1267
|
@action zoomOut() {
|
|
527
|
-
this.leafletMap
|
|
1268
|
+
this.leafletMap.zoomOut();
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Set the maximum bounds of the map based on the provided layer's bounds.
|
|
1273
|
+
*
|
|
1274
|
+
* @param {Layer} layer - The layer used to determine the map's maximum bounds.
|
|
1275
|
+
* @memberof LiveMapComponent
|
|
1276
|
+
*/
|
|
1277
|
+
setMaxBoundsFromLayer(layer) {
|
|
1278
|
+
if (layer && typeof layer.getBounds === 'function') {
|
|
1279
|
+
const bounds = layer.getBounds();
|
|
1280
|
+
|
|
1281
|
+
this.leafletMap.flyToBounds(bounds);
|
|
1282
|
+
this.leafletMap.setMaxBounds(bounds);
|
|
1283
|
+
}
|
|
528
1284
|
}
|
|
529
1285
|
|
|
530
|
-
|
|
531
|
-
|
|
1286
|
+
/**
|
|
1287
|
+
* Fly to and focus on a specific layer's bounds on the map.
|
|
1288
|
+
*
|
|
1289
|
+
* @param {Layer} layer - The layer to focus on.
|
|
1290
|
+
* @memberof LiveMapComponent
|
|
1291
|
+
*/
|
|
1292
|
+
flyToBoundsOnly(layer) {
|
|
1293
|
+
if (layer && typeof layer.getBounds === 'function') {
|
|
1294
|
+
const bounds = layer.getBounds();
|
|
532
1295
|
|
|
533
|
-
|
|
534
|
-
|
|
1296
|
+
this.leafletMap.flyToBounds(bounds);
|
|
1297
|
+
}
|
|
535
1298
|
}
|
|
536
1299
|
|
|
537
|
-
|
|
538
|
-
|
|
1300
|
+
/**
|
|
1301
|
+
* Focus on a specific layer and optionally zoom in/out on it.
|
|
1302
|
+
*
|
|
1303
|
+
* @param {Layer} layer - The layer to focus on.
|
|
1304
|
+
* @param {number} zoom - The zoom level for the focus operation.
|
|
1305
|
+
* @param {Object} options - Additional options for the focus operation.
|
|
1306
|
+
* @memberof LiveMapComponent
|
|
1307
|
+
*/
|
|
1308
|
+
@action focusLayer(layer, zoom, options = {}) {
|
|
1309
|
+
this.leafletMapManager.flyToLayer(this.leafletMap, layer, zoom, options);
|
|
539
1310
|
|
|
540
|
-
|
|
1311
|
+
if (typeof options.onAfterFocus === 'function') {
|
|
1312
|
+
options.onAfterFocus(layer);
|
|
1313
|
+
}
|
|
541
1314
|
}
|
|
542
1315
|
|
|
543
1316
|
/**
|
|
544
|
-
*
|
|
545
|
-
* CONTEXT MENU INITIALIZERS
|
|
546
|
-
* ----------------------------------------------------------------------------
|
|
1317
|
+
* Focuses the Leaflet map on a specific layer associated with a record.
|
|
547
1318
|
*
|
|
548
|
-
*
|
|
1319
|
+
* @param {Object} record - The record associated with the target layer.
|
|
1320
|
+
* @param {number} zoom - The desired zoom level for the map.
|
|
1321
|
+
* @param {Object} [options={}] - Additional options for the map focus.
|
|
1322
|
+
* @returns {void}
|
|
549
1323
|
*
|
|
1324
|
+
* @example
|
|
1325
|
+
* focusLayerByRecord(recordData, 12, { animate: true });
|
|
550
1326
|
*/
|
|
1327
|
+
@action focusLayerByRecord(record, zoom, options = {}) {
|
|
1328
|
+
const layer = this.getLeafletLayerByRecordId(record);
|
|
1329
|
+
|
|
1330
|
+
if (layer) {
|
|
1331
|
+
this.focusLayer(layer, zoom, options);
|
|
1332
|
+
}
|
|
551
1333
|
|
|
552
|
-
|
|
1334
|
+
if (typeof options.onAfterFocusWithRecord === 'function') {
|
|
1335
|
+
options.onAfterFocusWithRecord(record, layer);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Create a context menu for the map with various options.
|
|
1341
|
+
*
|
|
1342
|
+
* @param {L.Map} map - The map to which the context menu is attached.
|
|
1343
|
+
* @memberof LiveMapComponent
|
|
1344
|
+
*/
|
|
1345
|
+
@action createMapContextMenu(map) {
|
|
553
1346
|
const contextmenuItems = [
|
|
554
1347
|
{
|
|
555
1348
|
text: 'Show coordinates...',
|
|
@@ -572,8 +1365,8 @@ export default class LiveMapComponent extends Component {
|
|
|
572
1365
|
index: 3,
|
|
573
1366
|
},
|
|
574
1367
|
{
|
|
575
|
-
text: this.
|
|
576
|
-
callback:
|
|
1368
|
+
text: this.isVisible('drawControls') ? `Hide draw controls...` : `Enable draw controls...`,
|
|
1369
|
+
callback: this.toggleDrawControlContextMenuItem.bind(this),
|
|
577
1370
|
index: 4,
|
|
578
1371
|
},
|
|
579
1372
|
{
|
|
@@ -586,68 +1379,172 @@ export default class LiveMapComponent extends Component {
|
|
|
586
1379
|
},
|
|
587
1380
|
];
|
|
588
1381
|
|
|
589
|
-
//
|
|
590
|
-
const serviceAreas = this.serviceAreas.getFromCache()
|
|
1382
|
+
// Add Service Area Context Menu Items
|
|
1383
|
+
const serviceAreas = this.serviceAreas.getFromCache();
|
|
591
1384
|
|
|
592
|
-
if (serviceAreas
|
|
1385
|
+
if (isArray(serviceAreas) && serviceAreas.length) {
|
|
593
1386
|
contextmenuItems.pushObject({
|
|
594
1387
|
separator: true,
|
|
595
1388
|
});
|
|
596
|
-
}
|
|
597
1389
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
1390
|
+
// Add for each Service Area
|
|
1391
|
+
for (let i = 0; i < serviceAreas.length; i++) {
|
|
1392
|
+
const serviceArea = serviceAreas.objectAt(i);
|
|
1393
|
+
const nextIndex = contextmenuItems.length + 2;
|
|
601
1394
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
1395
|
+
contextmenuItems.pushObject({
|
|
1396
|
+
text: `Focus Service Area: ${serviceArea.name}`,
|
|
1397
|
+
callback: () => this.focusServiceArea(serviceArea),
|
|
1398
|
+
index: nextIndex,
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
607
1401
|
}
|
|
608
1402
|
|
|
609
|
-
|
|
1403
|
+
// create contextmenu registry
|
|
1404
|
+
const contextmenuRegistry = this.leafletContextmenuManager.createContextMenu('map', map, contextmenuItems);
|
|
610
1405
|
|
|
611
|
-
|
|
1406
|
+
// trigger that contextmenu registry was created
|
|
1407
|
+
this.universe.createRegistryEvent('contextmenu:map', 'created', contextmenuRegistry, this.leafletContextmenuManager);
|
|
1408
|
+
|
|
1409
|
+
return contextmenuRegistry;
|
|
612
1410
|
}
|
|
613
1411
|
|
|
614
|
-
|
|
615
|
-
|
|
1412
|
+
/**
|
|
1413
|
+
* Rebuild the context menu for the map.
|
|
1414
|
+
* This function calls the `createMapContextMenu` method.
|
|
1415
|
+
* @memberof LiveMapComponent
|
|
1416
|
+
*/
|
|
1417
|
+
rebuildMapContextMenu() {
|
|
1418
|
+
this.createMapContextMenu(this.leafletMap);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* Create a context menu for a driver marker on the map.
|
|
1423
|
+
*
|
|
1424
|
+
* @param {DriverModel} driver - The driver associated with the marker.
|
|
1425
|
+
* @param {L.Layer} layer - The layer representing the driver marker.
|
|
1426
|
+
* @memberof LiveMapComponent
|
|
1427
|
+
*/
|
|
1428
|
+
@action createDriverContextMenu(driver, layer) {
|
|
1429
|
+
let contextmenuItems = [
|
|
616
1430
|
{
|
|
617
1431
|
separator: true,
|
|
618
1432
|
},
|
|
619
1433
|
{
|
|
620
1434
|
text: `View Driver: ${driver.name}`,
|
|
621
|
-
|
|
1435
|
+
callback: () => this.contextPanel.focus(driver),
|
|
622
1436
|
},
|
|
623
1437
|
{
|
|
624
1438
|
text: `Edit Driver: ${driver.name}`,
|
|
625
|
-
|
|
1439
|
+
callback: () => this.contextPanel.focus(driver, 'editing'),
|
|
626
1440
|
},
|
|
627
1441
|
{
|
|
628
1442
|
text: `Delete Driver: ${driver.name}`,
|
|
629
|
-
|
|
1443
|
+
callback: () => this.crud.delete(driver),
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
text: `View Vehicle for: ${driver.name}`,
|
|
1447
|
+
callback: () => this.contextPanel.focus(driver.vehicle),
|
|
1448
|
+
},
|
|
1449
|
+
];
|
|
1450
|
+
|
|
1451
|
+
// append items from universe registry
|
|
1452
|
+
const registeredContextMenuItems = this.universe.getMenuItemsFromRegistry('contextmenu:driver');
|
|
1453
|
+
if (isArray(registeredContextMenuItems)) {
|
|
1454
|
+
contextmenuItems = [
|
|
1455
|
+
...contextmenuItems,
|
|
1456
|
+
...registeredContextMenuItems.map((menuItem) => {
|
|
1457
|
+
return {
|
|
1458
|
+
text: menuItem.title,
|
|
1459
|
+
callback: () => {
|
|
1460
|
+
const callbackContext = {
|
|
1461
|
+
driver,
|
|
1462
|
+
layer,
|
|
1463
|
+
contextmenuService: this.leafletContextmenuManager,
|
|
1464
|
+
menuItem,
|
|
1465
|
+
};
|
|
1466
|
+
return menuItem.onClick(callbackContext);
|
|
1467
|
+
},
|
|
1468
|
+
};
|
|
1469
|
+
}),
|
|
1470
|
+
];
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// create contextmenu registry
|
|
1474
|
+
const contextmenuRegistry = this.leafletContextmenuManager.createContextMenu(`driver:${driver.public_id}`, layer, contextmenuItems, { driver });
|
|
1475
|
+
|
|
1476
|
+
// trigger that contextmenu registry was created
|
|
1477
|
+
this.universe.createRegistryEvent('contextmenu:driver', 'created', contextmenuRegistry, this.leafletContextmenuManager);
|
|
1478
|
+
|
|
1479
|
+
return contextmenuRegistry;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
/**
|
|
1483
|
+
* Create a context menu for a vehicle marker on the map.
|
|
1484
|
+
*
|
|
1485
|
+
* @param {Vehicle} vehicle - The vehicle associated with the marker.
|
|
1486
|
+
* @param {Layer} layer - The layer representing the vehicle marker.
|
|
1487
|
+
* @memberof LiveMapComponent
|
|
1488
|
+
*/
|
|
1489
|
+
@action createVehicleContextMenu(vehicle, layer) {
|
|
1490
|
+
let contextmenuItems = [
|
|
1491
|
+
{
|
|
1492
|
+
separator: true,
|
|
630
1493
|
},
|
|
631
1494
|
{
|
|
632
|
-
text: `
|
|
633
|
-
|
|
1495
|
+
text: `View Vehicle: ${vehicle.displayName}`,
|
|
1496
|
+
callback: () => this.contextPanel.focus(vehicle),
|
|
634
1497
|
},
|
|
635
1498
|
{
|
|
636
|
-
text: `
|
|
637
|
-
|
|
1499
|
+
text: `Edit Vehicle: ${vehicle.displayName}`,
|
|
1500
|
+
callback: () => this.contextPanel.focus(vehicle, 'editing'),
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
text: `Delete Vehicle: ${vehicle.displayName}`,
|
|
1504
|
+
callback: () => this.crud.delete(vehicle),
|
|
638
1505
|
},
|
|
639
1506
|
];
|
|
640
1507
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
1508
|
+
// append items from universe registry
|
|
1509
|
+
const registeredContextMenuItems = this.universe.getMenuItemsFromRegistry('contextmenu:vehicle');
|
|
1510
|
+
if (isArray(registeredContextMenuItems)) {
|
|
1511
|
+
contextmenuItems = [
|
|
1512
|
+
...contextmenuItems,
|
|
1513
|
+
...registeredContextMenuItems.map((menuItem) => {
|
|
1514
|
+
return {
|
|
1515
|
+
text: menuItem.title,
|
|
1516
|
+
callback: () => {
|
|
1517
|
+
const callbackContext = {
|
|
1518
|
+
vehicle,
|
|
1519
|
+
layer,
|
|
1520
|
+
contextmenuService: this.leafletContextmenuManager,
|
|
1521
|
+
menuItem,
|
|
1522
|
+
};
|
|
1523
|
+
return menuItem.onClick(callbackContext);
|
|
1524
|
+
},
|
|
1525
|
+
};
|
|
1526
|
+
}),
|
|
1527
|
+
];
|
|
646
1528
|
}
|
|
1529
|
+
|
|
1530
|
+
// create contextmenu registry
|
|
1531
|
+
const contextmenuRegistry = this.leafletContextmenuManager.createContextMenu(`vehicle:${vehicle.public_id}`, layer, contextmenuItems, { vehicle });
|
|
1532
|
+
|
|
1533
|
+
// trigger that contextmenu registry was created
|
|
1534
|
+
this.universe.createRegistryEvent('contextmenu:vehicle', 'created', contextmenuRegistry, this.leafletContextmenuManager);
|
|
1535
|
+
|
|
1536
|
+
return contextmenuRegistry;
|
|
647
1537
|
}
|
|
648
1538
|
|
|
649
|
-
|
|
650
|
-
|
|
1539
|
+
/**
|
|
1540
|
+
* Create a context menu for a zone layer on the map.
|
|
1541
|
+
*
|
|
1542
|
+
* @param {ZoneModel} zone - The zone associated with the layer.
|
|
1543
|
+
* @param {Layer} layer - The layer representing the zone.
|
|
1544
|
+
* @memberof LiveMapComponent
|
|
1545
|
+
*/
|
|
1546
|
+
@action createZoneContextMenu(zone, layer) {
|
|
1547
|
+
let contextmenuItems = [
|
|
651
1548
|
{
|
|
652
1549
|
separator: true,
|
|
653
1550
|
},
|
|
@@ -670,16 +1567,24 @@ export default class LiveMapComponent extends Component {
|
|
|
670
1567
|
},
|
|
671
1568
|
];
|
|
672
1569
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
1570
|
+
// create contextmenu registry
|
|
1571
|
+
const contextmenuRegistry = this.leafletContextmenuManager.createContextMenu(`zone:${zone.public_id}`, layer, contextmenuItems, { zone });
|
|
1572
|
+
|
|
1573
|
+
// trigger that contextmenu registry was created
|
|
1574
|
+
this.universe.createRegistryEvent('contextmenu:zone', 'created', contextmenuRegistry, this.leafletContextmenuManager);
|
|
1575
|
+
|
|
1576
|
+
return contextmenuRegistry;
|
|
679
1577
|
}
|
|
680
1578
|
|
|
681
|
-
|
|
682
|
-
|
|
1579
|
+
/**
|
|
1580
|
+
* Create a context menu for a service area layer on the map.
|
|
1581
|
+
*
|
|
1582
|
+
* @param {ServiceAreaModel} serviceArea - The service area associated with the layer.
|
|
1583
|
+
* @param {Layer} layer - The layer representing the service area.
|
|
1584
|
+
* @memberof LiveMapComponent
|
|
1585
|
+
*/
|
|
1586
|
+
@action createServiceAreaContextMenu(serviceArea, layer) {
|
|
1587
|
+
let contextmenuItems = [
|
|
683
1588
|
{
|
|
684
1589
|
separator: true,
|
|
685
1590
|
},
|
|
@@ -704,30 +1609,32 @@ export default class LiveMapComponent extends Component {
|
|
|
704
1609
|
callback: () =>
|
|
705
1610
|
this.serviceAreas.deleteServiceArea(serviceArea, {
|
|
706
1611
|
onFinish: () => {
|
|
707
|
-
this.
|
|
1612
|
+
this.rebuildMapContextMenu();
|
|
708
1613
|
this.removeEditableLayerByRecordId(serviceArea);
|
|
709
1614
|
},
|
|
710
1615
|
}),
|
|
711
1616
|
},
|
|
712
1617
|
];
|
|
713
1618
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
1619
|
+
// create contextmenu registry
|
|
1620
|
+
const contextmenuRegistry = this.leafletContextmenuManager.createContextMenu(`service-area:${serviceArea.public_id}`, layer, contextmenuItems, { serviceArea });
|
|
1621
|
+
|
|
1622
|
+
// trigger that contextmenu registry was created
|
|
1623
|
+
this.universe.createRegistryEvent('contextmenu:service-area', 'created', contextmenuRegistry, this.leafletContextmenuManager);
|
|
1624
|
+
|
|
1625
|
+
return contextmenuRegistry;
|
|
720
1626
|
}
|
|
721
1627
|
|
|
722
1628
|
/**
|
|
723
|
-
*
|
|
724
|
-
* Async/Socket Functions
|
|
725
|
-
* ----------------------------------------------------------------------------
|
|
1629
|
+
* Listens for events on the company channel and logs incoming data.
|
|
726
1630
|
*
|
|
727
|
-
*
|
|
1631
|
+
* This function sets up a WebSocket connection, subscribes to the company-specific channel,
|
|
1632
|
+
* and listens for events. When events are received, it logs them to the console.
|
|
728
1633
|
*
|
|
1634
|
+
* @async
|
|
1635
|
+
* @function
|
|
729
1636
|
*/
|
|
730
|
-
|
|
1637
|
+
async listen() {
|
|
731
1638
|
// setup socket
|
|
732
1639
|
const socket = this.socket.instance();
|
|
733
1640
|
|
|
@@ -751,26 +1658,49 @@ export default class LiveMapComponent extends Component {
|
|
|
751
1658
|
})();
|
|
752
1659
|
}
|
|
753
1660
|
|
|
754
|
-
|
|
755
|
-
|
|
1661
|
+
/**
|
|
1662
|
+
* Watches and manages moving objects (e.g., drivers or vehicles) on the LiveMapComponent.
|
|
1663
|
+
*
|
|
1664
|
+
* This function can be used to watch different types of moving objects by specifying
|
|
1665
|
+
* the 'type' parameter.
|
|
1666
|
+
*
|
|
1667
|
+
* @action
|
|
1668
|
+
* @function
|
|
1669
|
+
* @param {string} objectType - The type of moving object to watch (e.g., 'drivers', 'vehicles').
|
|
1670
|
+
* @param {Array} movingObjects - An array of moving objects to watch.
|
|
1671
|
+
*/
|
|
1672
|
+
watchMovingObjects(objectType, objects = []) {
|
|
1673
|
+
// Setup socket
|
|
756
1674
|
const socket = this.socket.instance();
|
|
757
1675
|
|
|
758
|
-
//
|
|
759
|
-
for (let i = 0; i <
|
|
760
|
-
const
|
|
761
|
-
this.
|
|
1676
|
+
// Listen for moving objects
|
|
1677
|
+
for (let i = 0; i < objects.length; i++) {
|
|
1678
|
+
const movingObject = objects.objectAt(i);
|
|
1679
|
+
this.listenForMovingObject(objectType, movingObject, socket);
|
|
762
1680
|
}
|
|
763
1681
|
}
|
|
764
1682
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1683
|
+
/**
|
|
1684
|
+
* Listens for events related to a specific type of moving object (e.g., driver or vehicle) and manages the associated marker.
|
|
1685
|
+
*
|
|
1686
|
+
* This function subscribes to the channel corresponding to the provided 'objectType' and the specific 'movingObject'
|
|
1687
|
+
* to listen for location-related events. It processes and updates the associated marker when events are received.
|
|
1688
|
+
*
|
|
1689
|
+
* @async
|
|
1690
|
+
* @function
|
|
1691
|
+
* @param {string} objectType - The type of moving object being watched (e.g., 'drivers', 'vehicles').
|
|
1692
|
+
* @param {Object} movingObject - The specific moving object to track.
|
|
1693
|
+
* @param {Socket} socket - The WebSocket instance used for communication.
|
|
1694
|
+
*/
|
|
1695
|
+
async listenForMovingObject(objectType, movingObject, socket) {
|
|
1696
|
+
// Listen on the specific channel
|
|
1697
|
+
const channelId = `${objectType}.${movingObject.id}`;
|
|
768
1698
|
const channel = socket.subscribe(channelId);
|
|
769
1699
|
|
|
770
|
-
//
|
|
1700
|
+
// Track the channel
|
|
771
1701
|
this.channels.pushObject(channel);
|
|
772
1702
|
|
|
773
|
-
//
|
|
1703
|
+
// Listen to the channel for events
|
|
774
1704
|
await channel.listener('subscribe').once();
|
|
775
1705
|
|
|
776
1706
|
// Initialize an empty buffer to store incoming events
|
|
@@ -787,11 +1717,19 @@ export default class LiveMapComponent extends Component {
|
|
|
787
1717
|
// Process sorted events
|
|
788
1718
|
for (const output of eventBuffer) {
|
|
789
1719
|
const { event, data } = output;
|
|
1720
|
+
|
|
1721
|
+
// log incoming event
|
|
790
1722
|
console.log(`${event} - #${data.additionalData.index} (${output.created_at}) [ ${data.location.coordinates.join(' ')} ]`);
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1723
|
+
|
|
1724
|
+
// get movingObject marker
|
|
1725
|
+
const objectMarker = movingObject._layer;
|
|
1726
|
+
|
|
1727
|
+
if (objectMarker) {
|
|
1728
|
+
// Update the object's heading degree
|
|
1729
|
+
objectMarker.setRotationAngle(data.heading);
|
|
1730
|
+
// Move the object's marker to new coordinates
|
|
1731
|
+
objectMarker.slideTo(data.location.coordinates, { duration: 2000 });
|
|
1732
|
+
}
|
|
795
1733
|
}
|
|
796
1734
|
|
|
797
1735
|
// Clear the buffer
|
|
@@ -801,12 +1739,12 @@ export default class LiveMapComponent extends Component {
|
|
|
801
1739
|
// Start a timer to process the buffer at intervals
|
|
802
1740
|
setInterval(processBuffer, bufferTime);
|
|
803
1741
|
|
|
804
|
-
//
|
|
1742
|
+
// Get incoming data and console out
|
|
805
1743
|
(async () => {
|
|
806
1744
|
for await (let output of channel) {
|
|
807
1745
|
const { event } = output;
|
|
808
1746
|
|
|
809
|
-
if (event ===
|
|
1747
|
+
if (event === `${objectType}.location_changed` || event === `${objectType}.simulated_location_changed`) {
|
|
810
1748
|
// Add the incoming event to the buffer
|
|
811
1749
|
eventBuffer.push(output);
|
|
812
1750
|
}
|
|
@@ -814,15 +1752,27 @@ export default class LiveMapComponent extends Component {
|
|
|
814
1752
|
})();
|
|
815
1753
|
}
|
|
816
1754
|
|
|
1755
|
+
/**
|
|
1756
|
+
* Close all socket channels associated subscribed to.
|
|
1757
|
+
* @memberof LiveMapComponent
|
|
1758
|
+
*/
|
|
817
1759
|
@action closeChannels() {
|
|
818
|
-
|
|
819
|
-
|
|
1760
|
+
if (isArray(this.channels)) {
|
|
1761
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1762
|
+
const channel = this.channels.objectAt(i);
|
|
820
1763
|
|
|
821
|
-
|
|
1764
|
+
channel.close();
|
|
1765
|
+
}
|
|
822
1766
|
}
|
|
823
1767
|
}
|
|
824
1768
|
|
|
825
|
-
|
|
1769
|
+
/**
|
|
1770
|
+
* Retrieve the initial coordinates for the map view.
|
|
1771
|
+
*
|
|
1772
|
+
* @returns {Promise} A promise that resolves to an object containing latitude and longitude.
|
|
1773
|
+
* @memberof LiveMapComponent
|
|
1774
|
+
*/
|
|
1775
|
+
getInitialCoordinates() {
|
|
826
1776
|
const initialCoordinates = {
|
|
827
1777
|
latitude: DEFAULT_LATITUDE,
|
|
828
1778
|
longitude: DEFAULT_LONGITUDE,
|
|
@@ -880,73 +1830,13 @@ export default class LiveMapComponent extends Component {
|
|
|
880
1830
|
});
|
|
881
1831
|
}
|
|
882
1832
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
this.isLoading = false;
|
|
891
|
-
|
|
892
|
-
if (typeof this.args.onRoutesLoaded === 'function') {
|
|
893
|
-
this.args.onRoutesLoaded(routes);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
resolve(routes);
|
|
897
|
-
})
|
|
898
|
-
.catch(() => {
|
|
899
|
-
resolve([]);
|
|
900
|
-
});
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
@action fetchActiveDrivers() {
|
|
905
|
-
this.isLoading = true;
|
|
906
|
-
|
|
907
|
-
return new Promise((resolve) => {
|
|
908
|
-
this.fetch
|
|
909
|
-
.get('fleet-ops/live/drivers', {}, { normalizeToEmberData: true, normalizeModelType: 'driver' })
|
|
910
|
-
.then((drivers) => {
|
|
911
|
-
this.isLoading = false;
|
|
912
|
-
|
|
913
|
-
if (typeof this.args.onDriversLoaded === 'function') {
|
|
914
|
-
this.args.onDriversLoaded(drivers);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
resolve(drivers);
|
|
918
|
-
})
|
|
919
|
-
.catch(() => {
|
|
920
|
-
resolve([]);
|
|
921
|
-
});
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
@action fetchActivePlaces() {
|
|
926
|
-
this.isLoading = true;
|
|
927
|
-
|
|
928
|
-
// get the center of map
|
|
929
|
-
const center = this.leafletMap.getCenter();
|
|
930
|
-
|
|
931
|
-
return new Promise((resolve) => {
|
|
932
|
-
this.fetch
|
|
933
|
-
.get('fleet-ops/live/places', { within: center }, { normalizeToEmberData: true, normalizeModelType: 'place' })
|
|
934
|
-
.then((places) => {
|
|
935
|
-
this.isLoading = false;
|
|
936
|
-
|
|
937
|
-
if (typeof this.args.onPlacesLoaded === 'function') {
|
|
938
|
-
this.args.onPlacesLoaded(places);
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
resolve(places);
|
|
942
|
-
})
|
|
943
|
-
.catch(() => {
|
|
944
|
-
resolve([]);
|
|
945
|
-
});
|
|
946
|
-
});
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
@action fetchServiceAreas() {
|
|
1833
|
+
/**
|
|
1834
|
+
* Fetch service areas and cache them if not already cached.
|
|
1835
|
+
*
|
|
1836
|
+
* @returns {Promise} A promise that resolves to an array of service area records.
|
|
1837
|
+
* @memberof LiveMapComponent
|
|
1838
|
+
*/
|
|
1839
|
+
fetchServiceAreas() {
|
|
950
1840
|
this.isLoading = true;
|
|
951
1841
|
|
|
952
1842
|
return new Promise((resolve) => {
|
|
@@ -968,14 +1858,26 @@ export default class LiveMapComponent extends Component {
|
|
|
968
1858
|
});
|
|
969
1859
|
}
|
|
970
1860
|
|
|
971
|
-
|
|
1861
|
+
/**
|
|
1862
|
+
* Get the local latitude for the map view.
|
|
1863
|
+
*
|
|
1864
|
+
* @returns {number} The local latitude.
|
|
1865
|
+
* @memberof LiveMapComponent
|
|
1866
|
+
*/
|
|
1867
|
+
getLocalLatitude() {
|
|
972
1868
|
const whois = this.currentUser.getOption('whois');
|
|
973
1869
|
const latitude = this.appCache.get('map_latitude');
|
|
974
1870
|
|
|
975
1871
|
return latitude || whois?.latitude || DEFAULT_LATITUDE;
|
|
976
1872
|
}
|
|
977
1873
|
|
|
978
|
-
|
|
1874
|
+
/**
|
|
1875
|
+
* Get the local longitude for the map view.
|
|
1876
|
+
*
|
|
1877
|
+
* @returns {number} The local longitude.
|
|
1878
|
+
* @memberof LiveMapComponent
|
|
1879
|
+
*/
|
|
1880
|
+
getLocalLongitude() {
|
|
979
1881
|
const whois = this.currentUser.getOption('whois');
|
|
980
1882
|
const longitude = this.appCache.get('map_longitude');
|
|
981
1883
|
|