...
|
...
|
@@ -32,8 +32,9 @@ import { BehaviorSubject, Observable } from 'rxjs'; |
32
|
32
|
import { filter } from 'rxjs/operators';
|
33
|
33
|
import { Polyline } from './polyline';
|
34
|
34
|
import { Polygon } from './polygon';
|
35
|
|
-import { createTooltip, safeExecute } from '@home/components/widget/lib/maps/maps-utils';
|
|
35
|
+import { createTooltip, parseArray, parseData, safeExecute } from '@home/components/widget/lib/maps/maps-utils';
|
36
|
36
|
import { WidgetContext } from '@home/models/widget-component.models';
|
|
37
|
+import { DatasourceData } from '@shared/models/widget.models';
|
37
|
38
|
|
38
|
39
|
export default abstract class LeafletMap {
|
39
|
40
|
|
...
|
...
|
@@ -247,32 +248,75 @@ export default abstract class LeafletMap { |
247
|
248
|
}
|
248
|
249
|
}
|
249
|
250
|
|
250
|
|
- // Markers
|
251
|
|
- updateMarkers(markersData: FormattedData[], callback?) {
|
252
|
|
- markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => {
|
|
251
|
+ updateData(data: DatasourceData[], drawRoutes: boolean, showPolygon: boolean) {
|
|
252
|
+ this.ready$.subscribe(() => {
|
|
253
|
+ if (drawRoutes) {
|
|
254
|
+ this.updatePolylines(parseArray(data), false);
|
|
255
|
+ }
|
|
256
|
+ if (showPolygon) {
|
|
257
|
+ this.updatePolygons(parseData(data), false);
|
|
258
|
+ }
|
|
259
|
+ this.updateMarkers(parseData(data), false);
|
|
260
|
+ this.updateBoundsInternal(drawRoutes, showPolygon);
|
|
261
|
+ });
|
|
262
|
+ }
|
|
263
|
+
|
|
264
|
+ private updateBoundsInternal(drawRoutes: boolean, showPolygon: boolean) {
|
|
265
|
+ this.bounds = new L.LatLngBounds(null, null);
|
|
266
|
+ if (drawRoutes) {
|
|
267
|
+ this.polylines.forEach((polyline) => {
|
|
268
|
+ this.bounds.extend(polyline.leafletPoly.getBounds());
|
|
269
|
+ });
|
|
270
|
+ }
|
|
271
|
+ if (showPolygon) {
|
|
272
|
+ this.polygons.forEach((polygon) => {
|
|
273
|
+ this.bounds.extend(polygon.leafletPoly.getBounds());
|
|
274
|
+ });
|
|
275
|
+ }
|
|
276
|
+ this.markers.forEach((marker) => {
|
|
277
|
+ this.bounds.extend(marker.leafletMarker.getLatLng());
|
|
278
|
+ });
|
|
279
|
+ this.fitBounds(this.bounds);
|
|
280
|
+ }
|
|
281
|
+
|
|
282
|
+ // Markers
|
|
283
|
+ updateMarkers(markersData: FormattedData[], updateBounds = true, callback?) {
|
|
284
|
+ const rawMarkers = markersData.filter(mdata => !!this.convertPosition(mdata));
|
|
285
|
+ this.ready$.subscribe(() => {
|
|
286
|
+ const keys: string[] = [];
|
|
287
|
+ rawMarkers.forEach(data => {
|
253
|
288
|
if (data.rotationAngle || data.rotationAngle === 0) {
|
254
|
|
- const currentImage = this.options.useMarkerImageFunction ?
|
255
|
|
- safeExecute(this.options.markerImageFunction,
|
256
|
|
- [data, this.options.markerImages, markersData, data.dsIndex]) : this.options.currentImage;
|
257
|
|
- const style = currentImage ? 'background-image: url(' + currentImage.url + ');' : '';
|
258
|
|
- this.options.icon = L.divIcon({
|
259
|
|
- html: `<div class="arrow"
|
|
289
|
+ const currentImage = this.options.useMarkerImageFunction ?
|
|
290
|
+ safeExecute(this.options.markerImageFunction,
|
|
291
|
+ [data, this.options.markerImages, markersData, data.dsIndex]) : this.options.currentImage;
|
|
292
|
+ const style = currentImage ? 'background-image: url(' + currentImage.url + ');' : '';
|
|
293
|
+ this.options.icon = L.divIcon({
|
|
294
|
+ html: `<div class="arrow"
|
260
|
295
|
style="transform: translate(-10px, -10px)
|
261
|
296
|
rotate(${data.rotationAngle}deg);
|
262
|
297
|
${style}"><div>`
|
263
|
|
- });
|
264
|
|
- }
|
265
|
|
- else {
|
266
|
|
- this.options.icon = null;
|
|
298
|
+ });
|
|
299
|
+ } else {
|
|
300
|
+ this.options.icon = null;
|
267
|
301
|
}
|
268
|
302
|
if (this.markers.get(data.entityName)) {
|
269
|
|
- this.updateMarker(data.entityName, data, markersData, this.options)
|
|
303
|
+ this.updateMarker(data.entityName, data, markersData, this.options)
|
|
304
|
+ } else {
|
|
305
|
+ this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings, updateBounds, callback);
|
270
|
306
|
}
|
271
|
|
- else {
|
272
|
|
- this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings, callback);
|
|
307
|
+ keys.push(data.entityName);
|
|
308
|
+ });
|
|
309
|
+ const toDelete: string[] = [];
|
|
310
|
+ this.markers.forEach((v, mKey) => {
|
|
311
|
+ if (!keys.includes(mKey)) {
|
|
312
|
+ toDelete.push(mKey);
|
273
|
313
|
}
|
|
314
|
+ });
|
|
315
|
+ toDelete.forEach((key) => {
|
|
316
|
+ this.deleteMarker(key);
|
|
317
|
+ });
|
|
318
|
+ this.markersData = markersData;
|
274
|
319
|
});
|
275
|
|
- this.markersData = markersData;
|
276
|
320
|
}
|
277
|
321
|
|
278
|
322
|
dragMarker = (e, data = {}) => {
|
...
|
...
|
@@ -280,21 +324,20 @@ export default abstract class LeafletMap { |
280
|
324
|
this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) });
|
281
|
325
|
}
|
282
|
326
|
|
283
|
|
- private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, callback?) {
|
284
|
|
- this.ready$.subscribe(() => {
|
285
|
|
- const newMarker = new Marker(this.convertPosition(data), settings, data, dataSources, this.dragMarker);
|
286
|
|
- if (callback)
|
287
|
|
- newMarker.leafletMarker.on('click', () => { callback(data, true) });
|
288
|
|
- if (this.bounds)
|
289
|
|
- this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()));
|
290
|
|
- this.markers.set(key, newMarker);
|
291
|
|
- if (this.options.useClusterMarkers) {
|
292
|
|
- this.markersCluster.addLayer(newMarker.leafletMarker);
|
293
|
|
- }
|
294
|
|
- else {
|
295
|
|
- this.map.addLayer(newMarker.leafletMarker);
|
296
|
|
- }
|
297
|
|
- });
|
|
327
|
+ private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings,
|
|
328
|
+ updateBounds = true, callback?) {
|
|
329
|
+ const newMarker = new Marker(this.convertPosition(data), settings, data, dataSources, this.dragMarker);
|
|
330
|
+ if (callback)
|
|
331
|
+ newMarker.leafletMarker.on('click', () => { callback(data, true) });
|
|
332
|
+ if (this.bounds && updateBounds)
|
|
333
|
+ this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()));
|
|
334
|
+ this.markers.set(key, newMarker);
|
|
335
|
+ if (this.options.useClusterMarkers) {
|
|
336
|
+ this.markersCluster.addLayer(newMarker.leafletMarker);
|
|
337
|
+ }
|
|
338
|
+ else {
|
|
339
|
+ this.map.addLayer(newMarker.leafletMarker);
|
|
340
|
+ }
|
298
|
341
|
}
|
299
|
342
|
|
300
|
343
|
private updateMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings) {
|
...
|
...
|
@@ -306,8 +349,9 @@ export default abstract class LeafletMap { |
306
|
349
|
if (settings.showTooltip) {
|
307
|
350
|
marker.updateMarkerTooltip(data);
|
308
|
351
|
}
|
309
|
|
- if (settings.useClusterMarkers)
|
310
|
|
- this.markersCluster.refreshClusters()
|
|
352
|
+ if (settings.useClusterMarkers) {
|
|
353
|
+ this.markersCluster.refreshClusters()
|
|
354
|
+ }
|
311
|
355
|
marker.setDataSources(data, dataSources);
|
312
|
356
|
marker.updateMarkerIcon(settings);
|
313
|
357
|
}
|
...
|
...
|
@@ -315,7 +359,11 @@ export default abstract class LeafletMap { |
315
|
359
|
deleteMarker(key: string) {
|
316
|
360
|
let marker = this.markers.get(key)?.leafletMarker;
|
317
|
361
|
if (marker) {
|
318
|
|
- this.map.removeLayer(marker);
|
|
362
|
+ if (this.options.useClusterMarkers) {
|
|
363
|
+ this.markersCluster.removeLayer(marker);
|
|
364
|
+ } else {
|
|
365
|
+ this.map.removeLayer(marker);
|
|
366
|
+ }
|
319
|
367
|
this.markers.delete(key);
|
320
|
368
|
marker = null;
|
321
|
369
|
}
|
...
|
...
|
@@ -346,41 +394,49 @@ export default abstract class LeafletMap { |
346
|
394
|
|
347
|
395
|
// Polyline
|
348
|
396
|
|
349
|
|
- updatePolylines(polyData: FormattedData[][], data?: FormattedData) {
|
|
397
|
+ updatePolylines(polyData: FormattedData[][], updateBounds = true, data?: FormattedData) {
|
|
398
|
+ const keys: string[] = [];
|
350
|
399
|
polyData.forEach((dataSource: FormattedData[]) => {
|
351
|
400
|
data = data || dataSource[0];
|
352
|
401
|
if (dataSource.length && data.entityName === dataSource[0].entityName) {
|
353
|
402
|
if (this.polylines.get(data.entityName)) {
|
354
|
|
- this.updatePolyline(data, dataSource, this.options);
|
|
403
|
+ this.updatePolyline(data, dataSource, this.options, updateBounds);
|
|
404
|
+ } else {
|
|
405
|
+ this.createPolyline(data, dataSource, this.options, updateBounds);
|
355
|
406
|
}
|
356
|
|
- else {
|
357
|
|
- this.createPolyline(data, dataSource, this.options);
|
358
|
|
- }
|
359
|
|
- }
|
360
|
|
- else {
|
361
|
|
- if (data)
|
362
|
|
- this.removePolyline(dataSource[0]?.entityName)
|
|
407
|
+ keys.push(data.entityName);
|
363
|
408
|
}
|
364
|
|
- })
|
|
409
|
+ });
|
|
410
|
+ const toDelete: string[] = [];
|
|
411
|
+ this.polylines.forEach((v, mKey) => {
|
|
412
|
+ if (!keys.includes(mKey)) {
|
|
413
|
+ toDelete.push(mKey);
|
|
414
|
+ }
|
|
415
|
+ });
|
|
416
|
+ toDelete.forEach((key) => {
|
|
417
|
+ this.removePolyline(key);
|
|
418
|
+ });
|
365
|
419
|
}
|
366
|
420
|
|
367
|
|
- createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) {
|
|
421
|
+ createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings, updateBounds = true) {
|
368
|
422
|
this.ready$.subscribe(() => {
|
369
|
423
|
const poly = new Polyline(this.map,
|
370
|
424
|
dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
|
371
|
|
- const bounds = poly.leafletPoly.getBounds();
|
372
|
|
- this.fitBounds(bounds);
|
|
425
|
+ if (updateBounds) {
|
|
426
|
+ const bounds = poly.leafletPoly.getBounds();
|
|
427
|
+ this.fitBounds(bounds);
|
|
428
|
+ }
|
373
|
429
|
this.polylines.set(data.entityName, poly);
|
374
|
430
|
});
|
375
|
431
|
}
|
376
|
432
|
|
377
|
|
- updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) {
|
|
433
|
+ updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings, updateBounds = true) {
|
378
|
434
|
this.ready$.subscribe(() => {
|
379
|
435
|
const poly = this.polylines.get(data.entityName);
|
380
|
436
|
const oldBounds = poly.leafletPoly.getBounds();
|
381
|
437
|
poly.updatePolyline(dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
|
382
|
438
|
const newBounds = poly.leafletPoly.getBounds();
|
383
|
|
- if (oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
|
|
439
|
+ if (updateBounds && oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
|
384
|
440
|
this.fitBounds(newBounds);
|
385
|
441
|
}
|
386
|
442
|
});
|
...
|
...
|
@@ -399,40 +455,60 @@ export default abstract class LeafletMap { |
399
|
455
|
|
400
|
456
|
// Polygon
|
401
|
457
|
|
402
|
|
- updatePolygons(polyData: FormattedData[]) {
|
|
458
|
+ updatePolygons(polyData: FormattedData[], updateBounds = true) {
|
|
459
|
+ const keys: string[] = [];
|
403
|
460
|
polyData.forEach((data: FormattedData) => {
|
404
|
461
|
if (data && data.hasOwnProperty(this.options.polygonKeyName)) {
|
405
|
462
|
if (typeof (data[this.options.polygonKeyName]) === 'string') {
|
406
|
463
|
data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]) as LatLngTuple[];
|
407
|
464
|
}
|
408
|
|
- if (this.polygons.get(data.$datasource.entityName)) {
|
409
|
|
- this.updatePolygon(data, polyData, this.options);
|
410
|
|
- }
|
411
|
|
- else {
|
412
|
|
- this.createPolygon(data, polyData, this.options);
|
|
465
|
+ if (this.polygons.get(data.entityName)) {
|
|
466
|
+ this.updatePolygon(data, polyData, this.options, updateBounds);
|
|
467
|
+ } else {
|
|
468
|
+ this.createPolygon(data, polyData, this.options, updateBounds);
|
413
|
469
|
}
|
|
470
|
+ keys.push(data.entityName);
|
414
|
471
|
}
|
415
|
472
|
});
|
|
473
|
+ const toDelete: string[] = [];
|
|
474
|
+ this.polygons.forEach((v, mKey) => {
|
|
475
|
+ if (!keys.includes(mKey)) {
|
|
476
|
+ toDelete.push(mKey);
|
|
477
|
+ }
|
|
478
|
+ });
|
|
479
|
+ toDelete.forEach((key) => {
|
|
480
|
+ this.removePolygon(key);
|
|
481
|
+ });
|
416
|
482
|
}
|
417
|
483
|
|
418
|
|
- createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
|
|
484
|
+ createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {
|
419
|
485
|
this.ready$.subscribe(() => {
|
420
|
486
|
const polygon = new Polygon(this.map, polyData, dataSources, settings);
|
421
|
|
- const bounds = polygon.leafletPoly.getBounds();
|
422
|
|
- this.fitBounds(bounds);
|
423
|
|
- this.polygons.set(polyData.$datasource.entityName, polygon);
|
|
487
|
+ if (updateBounds) {
|
|
488
|
+ const bounds = polygon.leafletPoly.getBounds();
|
|
489
|
+ this.fitBounds(bounds);
|
|
490
|
+ }
|
|
491
|
+ this.polygons.set(polyData.entityName, polygon);
|
424
|
492
|
});
|
425
|
493
|
}
|
426
|
494
|
|
427
|
|
- updatePolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
|
|
495
|
+ updatePolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {
|
428
|
496
|
this.ready$.subscribe(() => {
|
429
|
497
|
const poly = this.polygons.get(polyData.entityName);
|
430
|
498
|
const oldBounds = poly.leafletPoly.getBounds();
|
431
|
499
|
poly.updatePolygon(polyData, dataSources, settings);
|
432
|
500
|
const newBounds = poly.leafletPoly.getBounds();
|
433
|
|
- if (oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
|
|
501
|
+ if (updateBounds && oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
|
434
|
502
|
this.fitBounds(newBounds);
|
435
|
503
|
}
|
436
|
504
|
});
|
437
|
505
|
}
|
|
506
|
+
|
|
507
|
+ removePolygon(name: string) {
|
|
508
|
+ const poly = this.polygons.get(name);
|
|
509
|
+ if (poly) {
|
|
510
|
+ this.map.removeLayer(poly.leafletPoly);
|
|
511
|
+ this.polygons.delete(name);
|
|
512
|
+ }
|
|
513
|
+ }
|
438
|
514
|
} |
...
|
...
|
|