diff --git a/pom.xml b/pom.xml
index 7503bcc4c0..cf348e2f4a 100755
--- a/pom.xml
+++ b/pom.xml
@@ -830,6 +830,7 @@
src/.browserslistrc
**/yarn.lock
**/*.raw
+ **/*.patch
**/apache/cassandra/io/**
.run/**
diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json
index a97e65b04c..0d6203c88e 100644
--- a/ui-ngx/angular.json
+++ b/ui-ngx/angular.json
@@ -79,6 +79,7 @@
"src/app/modules/home/components/widget/lib/maps/markers.scss",
"node_modules/leaflet.markercluster/dist/MarkerCluster.css",
"node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css",
+ "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css",
"node_modules/prismjs/themes/prism.css",
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
],
diff --git a/ui-ngx/package.json b/ui-ngx/package.json
index 519d31b66c..f9ca6d478c 100644
--- a/ui-ngx/package.json
+++ b/ui-ngx/package.json
@@ -28,6 +28,7 @@
"@date-io/date-fns": "^2.10.11",
"@flowjs/flow.js": "^2.14.1",
"@flowjs/ngx-flow": "~0.4.6",
+ "@geoman-io/leaflet-geoman-free": "^2.11.3",
"@juggle/resize-observer": "^3.3.1",
"@mat-datetimepicker/core": "~6.0.2",
"@material-ui/core": "^4.11.4",
@@ -57,11 +58,10 @@
"jstree-bootstrap-theme": "^1.0.1",
"jszip": "^3.6.0",
"leaflet": "^1.7.1",
- "leaflet-editable": "^1.2.0",
"leaflet-polylinedecorator": "^1.6.0",
- "leaflet-providers": "^1.12.0",
- "leaflet.gridlayer.googlemutant": "0.10.2",
- "leaflet.markercluster": "^1.5.0",
+ "leaflet-providers": "^1.13.0",
+ "leaflet.gridlayer.googlemutant": "^0.13.4",
+ "leaflet.markercluster": "^1.5.3",
"material-design-icons": "^3.0.1",
"messageformat": "^2.3.0",
"moment": "^2.29.1",
@@ -113,10 +113,11 @@
"@types/jquery": "^3.5.2",
"@types/js-beautify": "^1.13.1",
"@types/jstree": "^3.3.40",
- "@types/leaflet": "1.5.17",
- "@types/leaflet-editable": "^1.2.1",
- "@types/leaflet-polylinedecorator": "^1.6.0",
- "@types/leaflet.markercluster": "^1.4.4",
+ "@types/leaflet": "^1.7.6",
+ "@types/leaflet-polylinedecorator": "^1.6.1",
+ "@types/leaflet-providers": "^1.2.1",
+ "@types/leaflet.gridlayer.googlemutant": "^0.4.6",
+ "@types/leaflet.markercluster": "^1.4.6",
"@types/lodash": "^4.14.170",
"@types/moment-timezone": "^0.5.30",
"@types/mousetrap": "1.6.3",
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html
new file mode 100644
index 0000000000..93fa72c84b
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html
@@ -0,0 +1,54 @@
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss
new file mode 100644
index 0000000000..b9600d8731
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss
@@ -0,0 +1,21 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+:host {
+ .tb-hint {
+ margin-top: -1.25em;
+ max-width: fit-content;
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts
new file mode 100644
index 0000000000..58526a4e66
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts
@@ -0,0 +1,56 @@
+///
+/// Copyright © 2016-2021 The Thingsboard Authors
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+///
+
+import { Component, Inject } from '@angular/core';
+import { DialogComponent } from '@shared/components/dialog.component';
+import { Store } from '@ngrx/store';
+import { AppState } from '@core/core.state';
+import { Router } from '@angular/router';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { FormattedData } from '@home/components/widget/lib/maps/map-models';
+
+export interface SelectEntityDialogData {
+ entities: FormattedData[];
+}
+
+@Component({
+ selector: 'tb-select-entity-dialog',
+ templateUrl: './select-entity-dialog.component.html',
+ styleUrls: ['./select-entity-dialog.component.scss']
+})
+export class SelectEntityDialogComponent extends DialogComponent {
+
+ selectEntityFormGroup: FormGroup;
+
+ constructor(protected store: Store,
+ protected router: Router,
+ @Inject(MAT_DIALOG_DATA) public data: SelectEntityDialogData,
+ public dialogRef: MatDialogRef,
+ public fb: FormBuilder) {
+ super(store, router, dialogRef);
+
+ this.selectEntityFormGroup = this.fb.group(
+ {
+ entity: ['', Validators.required]
+ }
+ );
+ }
+
+ save(): void {
+ this.dialogRef.close(this.selectEntityFormGroup.value.entity);
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
index 5120fc8c9e..03249a5307 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
@@ -14,23 +14,15 @@
/// limitations under the License.
///
-import L, {
- FeatureGroup,
- Icon,
- LatLngBounds,
- LatLngTuple,
- markerClusterGroup,
- MarkerClusterGroup,
- MarkerClusterGroupOptions, Projection
-} from 'leaflet';
+import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet';
import tinycolor from 'tinycolor2';
import 'leaflet-providers';
-import 'leaflet.markercluster/dist/leaflet.markercluster';
+import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster';
+import '@geoman-io/leaflet-geoman-free';
import {
defaultSettings,
FormattedData,
- MapProviders,
MapSettings,
MarkerSettings,
PolygonSettings,
@@ -39,12 +31,10 @@ import {
UnitedMapSettings
} from './map-models';
import { Marker } from './markers';
-import { Observable, of } from 'rxjs';
+import { forkJoin, Observable, of } from 'rxjs';
import { Polyline } from './polyline';
import { Polygon } from './polygon';
-import {
- createTooltip,
-} from '@home/components/widget/lib/maps/maps-utils';
+import { createTooltip } from '@home/components/widget/lib/maps/maps-utils';
import {
checkLngLat,
createLoadingDiv,
@@ -54,6 +44,15 @@ import {
} from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models';
import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils';
+import { TranslateService } from '@ngx-translate/core';
+import {
+ SelectEntityDialogComponent,
+ SelectEntityDialogData
+} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component';
+import { MatDialog } from '@angular/material/dialog';
+import { AttributeService } from '@core/http/attribute.service';
+import { EntityId } from '@shared/models/id/entity-id';
+import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
export default abstract class LeafletMap {
@@ -78,20 +77,20 @@ export default abstract class LeafletMap {
drawRoutes: boolean;
showPolygon: boolean;
updatePending = false;
+ editPolygons = false;
+ selectedEntity: FormattedData;
addMarkers: L.Marker[] = [];
addPolygons: L.Polygon[] = [];
// tslint:disable-next-line:no-string-literal
southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180);
// tslint:disable-next-line:no-string-literal
northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180);
- mousePositionOnMap: L.LatLng;
- addMarker: L.Control;
- addPolygon: L.Control;
protected constructor(public ctx: WidgetContext,
public $container: HTMLElement,
options: UnitedMapSettings) {
this.options = options;
+ this.editPolygons = options.showPolygon && options.editablePolygon;
}
public initSettings(options: MapSettings) {
@@ -102,16 +101,28 @@ export default abstract class LeafletMap {
removeOutsideVisibleBounds,
animate,
chunkedLoading,
+ spiderfyOnMaxZoom,
maxClusterRadius,
maxZoom }: MapSettings = options;
if (useClusterMarkers) {
+ // disabled marker cluster icon
+ (L as any).MarkerCluster = (L as any).MarkerCluster.extend({
+ options: { pmIgnore: true, ...L.Icon.prototype.options }
+ });
const clusteringSettings: MarkerClusterGroupOptions = {
- spiderfyOnMaxZoom: false,
+ spiderfyOnMaxZoom,
zoomToBoundsOnClick: zoomOnClick,
showCoverageOnHover,
removeOutsideVisibleBounds,
animate,
- chunkedLoading
+ chunkedLoading,
+ pmIgnore: true,
+ spiderLegPolylineOptions: {
+ pmIgnore: true
+ },
+ polygonOptions: {
+ pmIgnore: true
+ }
};
if (maxClusterRadius && maxClusterRadius > 0) {
clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius);
@@ -119,183 +130,165 @@ export default abstract class LeafletMap {
if (maxZoom && maxZoom >= 0 && maxZoom < 19) {
clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom);
}
- this.markersCluster = markerClusterGroup(clusteringSettings);
+ this.markersCluster = new MarkerClusterGroup(clusteringSettings);
}
}
- addMarkerControl() {
- if (this.options.draggableMarker) {
- this.map.on('mousemove', (e: L.LeafletMouseEvent) => {
- this.mousePositionOnMap = e.latlng;
- });
- const dragListener = (e: L.DragEndEvent) => {
- if (e.type === 'dragend' && this.mousePositionOnMap) {
- const icon = L.icon({
- iconRetinaUrl: 'marker-icon-2x.png',
- iconUrl: 'marker-icon.png',
- shadowUrl: 'marker-shadow.png',
- iconSize: [25, 41],
- iconAnchor: [12, 41],
- popupAnchor: [1, -34],
- tooltipAnchor: [16, -28],
- shadowSize: [41, 41]
- });
- const customLatLng = this.convertToCustomFormat(this.mousePositionOnMap);
- this.mousePositionOnMap.lat = customLatLng[this.options.latKeyName];
- this.mousePositionOnMap.lng = customLatLng[this.options.lngKeyName];
-
- const newMarker = L.marker(this.mousePositionOnMap, { icon }).addTo(this.map);
- this.addMarkers.push(newMarker);
- const datasourcesList = document.createElement('div');
- const header = document.createElement('p');
- header.appendChild(document.createTextNode('Select entity:'));
- header.setAttribute('style', 'font-size: 14px; margin: 8px 0');
- datasourcesList.appendChild(header);
- this.datasources.forEach(ds => {
- const dsItem = document.createElement('p');
- dsItem.appendChild(document.createTextNode(ds.entityName));
- dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer');
- dsItem.onclick = () => {
- const updatedEnttity = { ...ds, ...customLatLng };
- this.saveMarkerLocation(updatedEnttity).subscribe(() => {
- this.map.removeLayer(newMarker);
- const markerIndex = this.addMarkers.indexOf(newMarker);
- if (markerIndex > -1) {
- this.addMarkers.splice(markerIndex, 1);
- }
- this.deleteMarker(ds.entityName);
- this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options);
- });
- };
- datasourcesList.appendChild(dsItem);
- });
- datasourcesList.appendChild(document.createElement('br'));
- const deleteBtn = document.createElement('a');
- deleteBtn.appendChild(document.createTextNode('Discard changes'));
- deleteBtn.onclick = () => {
- this.map.removeLayer(newMarker);
- const markerIndex = this.addMarkers.indexOf(newMarker);
- if (markerIndex > -1) {
- this.addMarkers.splice(markerIndex, 1);
- }
- };
- datasourcesList.appendChild(deleteBtn);
- const popup = L.popup();
- popup.setContent(datasourcesList);
- newMarker.bindPopup(popup).openPopup();
- }
- this.addMarker.setPosition('topright');
- };
- const addMarker = L.Control.extend({
- onAdd() {
- const img = L.DomUtil.create('img') as any;
- img.src = `assets/add_location.svg`;
- img.style.width = '32px';
- img.style.height = '32px';
- img.title = 'Drag and drop to add marker';
- img.onclick = this.dragMarker;
- img.draggable = true;
- const draggableImg = new L.Draggable(img);
- draggableImg.enable();
- draggableImg.on('dragend', dragListener);
- return img;
- },
- onRemove() {
- },
- dragMarker: this.dragMarker
- } as any);
- const addMarkerControl = (opts) => {
- return new addMarker(opts);
- };
- this.addMarker = addMarkerControl({ position: 'topright' }).addTo(this.map);
+ private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable {
+ let entities;
+ switch (shapes) {
+ case 'Polygon':
+ case 'Rectangle':
+ entities = this.datasources.filter(pData => !this.isValidPolygonPosition(pData));
+ break;
+ case 'Marker':
+ entities = this.datasources.filter(mData => !this.convertPosition(mData));
+ break;
+ default:
+ return of(null);
+ }
+ if (entities.length === 1) {
+ return of(entities[0]);
+ }
+ const dialog = this.ctx.$injector.get(MatDialog);
+ return dialog.open(SelectEntityDialogComponent,
+ {
+ disableClose: true,
+ panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
+ data: {
+ entities
+ }
+ }).afterClosed();
+ }
+
+ private selectEntityWithoutLocation(type: string) {
+ this.selectEntityWithoutLocationDialog(type.substring(2)).subscribe((data) => {
+ if (data !== null) {
+ this.selectedEntity = data;
+ this.toggleDrawMode(type);
+ } else {
+ this.map.pm.Toolbar.toggleButton(type, false);
}
+ });
+ }
+
+ private toggleDrawMode(type: string) {
+ this.map.pm.Draw[type].toggle();
}
- addPolygonControl() {
- if (this.options.showPolygon && this.options.editablePolygon) {
- this.map.on('mousemove', (e: L.LeafletMouseEvent) => {
- this.mousePositionOnMap = e.latlng;
+ addEditControl() {
+ // Customize edit marker
+ if (this.options.draggableMarker) {
+ const actions = [{
+ text: L.PM.Utils.getTranslation('actions.cancel'),
+ onClick: () => this.toggleDrawMode('tbMarker')
+ }];
+
+ this.map.pm.Toolbar.copyDrawControl('Marker', {
+ name: 'tbMarker',
+ afterClick: () => this.selectEntityWithoutLocation('tbMarker'),
+ disabled: true,
+ actions
+ });
+ }
+
+ // Customize edit polygon
+ if (this.editPolygons) {
+ const rectangleActions = [
+ {
+ text: L.PM.Utils.getTranslation('actions.cancel'),
+ onClick: () => this.toggleDrawMode('tbRectangle')
+ }
+ ];
+
+ const polygonActions = [
+ 'finish' as const,
+ 'removeLastVertex' as const,
+ {
+ text: L.PM.Utils.getTranslation('actions.cancel'),
+ onClick: () => this.toggleDrawMode('tbPolygon')
+ }
+ ];
+
+ this.map.pm.Toolbar.copyDrawControl('Rectangle', {
+ name: 'tbRectangle',
+ afterClick: () => this.selectEntityWithoutLocation('tbRectangle'),
+ disabled: true,
+ actions: rectangleActions
+ });
+
+ this.map.pm.Toolbar.copyDrawControl('Polygon', {
+ name: 'tbPolygon',
+ afterClick: () => this.selectEntityWithoutLocation('tbPolygon'),
+ disabled: true,
+ actions: polygonActions
+ });
+ }
+
+ const translateService = this.ctx.$injector.get(TranslateService);
+ this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en');
+ this.map.pm.addControls({
+ position: 'topleft',
+ drawMarker: false,
+ drawCircle: false,
+ drawCircleMarker: false,
+ drawRectangle: false,
+ drawPolyline: false,
+ drawPolygon: false,
+ editMode: this.editPolygons,
+ cutPolygon: this.editPolygons,
+ rotateMode: this.editPolygons
});
- const dragListener = (e: L.DragEndEvent) => {
- if (e.type === 'dragend') {
- const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01;
-
- const convert = this.convertToCustomFormat(this.mousePositionOnMap, polygonOffset);
- this.mousePositionOnMap.lat = convert[this.options.latKeyName];
- this.mousePositionOnMap.lng = convert[this.options.lngKeyName];
-
- const latlng1 = this.mousePositionOnMap;
- const latlng2 = L.latLng(this.mousePositionOnMap.lat, this.mousePositionOnMap.lng + polygonOffset);
- const latlng3 = L.latLng(this.mousePositionOnMap.lat - polygonOffset, this.mousePositionOnMap.lng);
- const polygonPoints = [latlng1, latlng2, latlng3];
-
- const newPolygon = L.polygon(polygonPoints).addTo(this.map);
- this.addPolygons.push(newPolygon);
- const datasourcesList = document.createElement('div');
- const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(polygonPoints)};
- const header = document.createElement('p');
- header.appendChild(document.createTextNode('Select entity:'));
- header.setAttribute('style', 'font-size: 14px; margin: 8px 0');
- datasourcesList.appendChild(header);
- this.datasources.forEach(ds => {
- const dsItem = document.createElement('p');
- dsItem.appendChild(document.createTextNode(ds.entityName));
- dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer');
- dsItem.onclick = () => {
- const updatedEnttity = { ...ds, ...customLatLng };
- this.savePolygonLocation(updatedEnttity).subscribe(() => {
- this.map.removeLayer(newPolygon);
- const polygonIndex = this.addPolygons.indexOf(newPolygon);
- if (polygonIndex > -1) {
- this.addPolygons.splice(polygonIndex, 1);
- }
- this.deletePolygon(ds.entityName);
- });
- };
- datasourcesList.appendChild(dsItem);
+ this.map.on('pm:create', (e) => {
+ if (e.shape === 'tbMarker') {
+ // @ts-ignore
+ this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {
+ });
+ } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') {
+ // @ts-ignore
+ this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => {
});
- datasourcesList.appendChild(document.createElement('br'));
- const deleteBtn = document.createElement('a');
- deleteBtn.appendChild(document.createTextNode('Discard changes'));
- deleteBtn.onclick = () => {
- this.map.removeLayer(newPolygon);
- const polygonIndex = this.addPolygons.indexOf(newPolygon);
- if (polygonIndex > -1) {
- this.addPolygons.splice(polygonIndex, 1);
- }
- };
- datasourcesList.appendChild(deleteBtn);
- const popup = L.popup();
- popup.setContent(datasourcesList);
- newPolygon.bindPopup(popup).openPopup();
}
- this.addPolygon.setPosition('topright');
- };
- const addPolygon = L.Control.extend({
- onAdd() {
- const img = L.DomUtil.create('img') as any;
- img.src = `assets/add_polygon.svg`;
- img.style.width = '32px';
- img.style.height = '32px';
- img.title = 'Drag and drop to add Polygon';
- img.onclick = this.dragPolygonVertex;
- img.draggable = true;
- const draggableImg = new L.Draggable(img);
- draggableImg.enable();
- draggableImg.on('dragend', dragListener);
- return img;
- },
- onRemove() {
- },
- dragPolygonVertex: this.dragPolygonVertex
- } as any);
- const addPolygonControl = (opts) => {
- return new addPolygon(opts);
- };
- this.addPolygon = addPolygonControl({ position: 'topright' }).addTo(this.map);
+ // @ts-ignore
+ e.layer._pmTempLayer = true;
+ e.layer.remove();
+ });
+
+ this.map.on('pm:cut', (e) => {
+ // @ts-ignore
+ e.originalLayer.setLatLngs(e.layer.getLatLngs());
+ e.originalLayer.addTo(this.map);
+ // @ts-ignore
+ e.originalLayer._pmTempLayer = false;
+ const iterator = this.polygons.values();
+ let result = iterator.next();
+ while (!result.done && e.originalLayer !== result.value.leafletPoly) {
+ result = iterator.next();
+ }
+ // @ts-ignore
+ e.layer._pmTempLayer = true;
+ e.layer.remove();
+ });
+
+ this.map.on('pm:remove', (e) => {
+ if (e.shape === 'Marker') {
+ const iterator = this.markers.values();
+ let result = iterator.next();
+ while (!result.done && e.layer !== result.value.leafletMarker) {
+ result = iterator.next();
+ }
+ this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {});
+ } else if (e.shape === 'Polygon') {
+ const iterator = this.polygons.values();
+ let result = iterator.next();
+ while (!result.done && e.layer !== result.value.leafletPoly) {
+ result = iterator.next();
+ }
+ this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {});
+ }
+ });
}
- }
public setLoading(loading: boolean) {
if (this.loading !== loading) {
@@ -337,11 +330,10 @@ export default abstract class LeafletMap {
if (this.options.disableScrollZooming) {
this.map.scrollWheelZoom.disable();
}
- if (this.options.draggableMarker) {
- this.addMarkerControl();
- }
- if (this.options.editablePolygon) {
- this.addPolygonControl();
+ if (this.options.draggableMarker || this.editPolygons) {
+ this.addEditControl();
+ } else {
+ this.map.pm.disableDraw();
}
if (this.options.useClusterMarkers) {
this.map.addLayer(this.markersCluster);
@@ -352,12 +344,53 @@ export default abstract class LeafletMap {
}
}
- public saveMarkerLocation(datasource: FormattedData, lat?: number, lng?: number): Observable {
- return of(null);
- }
+ private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable {
+ const attributeService = this.ctx.$injector.get(AttributeService);
+ const attributes = [];
+ const timeseries = [];
+
+ const entityId: EntityId = {
+ entityType: e.$datasource.entityType,
+ id: e.$datasource.entityId
+ };
- public savePolygonLocation(datasource: FormattedData, coordinates?: Array<[number, number]>): Observable {
- return of(null);
+ for (const dataKeyName of Object.keys(values)) {
+ for (const key of e.$datasource.dataKeys) {
+ if (dataKeyName === key.name) {
+ const value = {
+ key: key.name,
+ value: values[dataKeyName]
+ };
+ if (key.type === DataKeyType.attribute) {
+ attributes.push(value);
+ } else if (key.type === DataKeyType.timeseries) {
+ timeseries.push(value);
+ }
+ break;
+ }
+ }
+ }
+
+ const observables: Observable[] = [];
+ if (timeseries.length) {
+ observables.push(attributeService.saveEntityTimeseries(
+ entityId,
+ LatestTelemetry.LATEST_TELEMETRY,
+ timeseries
+ ));
+ }
+ if (attributes.length) {
+ observables.push(attributeService.saveEntityAttributes(
+ entityId,
+ AttributeScope.SERVER_SCOPE,
+ attributes
+ ));
+ }
+ if (observables.length) {
+ return forkJoin(observables);
+ } else {
+ return of(null);
+ }
}
createLatLng(lat: number, lng: number): L.LatLng {
@@ -441,7 +474,7 @@ export default abstract class LeafletMap {
}
convertToCustomFormat(position: L.LatLng, offset = 0): object {
- position = checkLngLat(position, this.southWest, this.northEast, offset);
+ position = position ? checkLngLat(position, this.southWest, this.northEast, offset) : {lat: null, lng: null} as L.LatLng;
return {
[this.options.latKeyName]: position.lat,
@@ -455,17 +488,18 @@ export default abstract class LeafletMap {
if (point.length) {
return this.convertToPolygonFormat(point);
} else {
- return [point.lat, point.lng];
+ const convertPoint = checkLngLat(point, this.southWest, this.northEast);
+ return [convertPoint.lat, convertPoint.lng];
}
});
- } else {
- return [];
}
+ return [];
}
- convertPolygonToCustomFormat(expression: any[][]): object {
+ convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
+ const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
return {
- [this.options.polygonKeyName] : this.convertToPolygonFormat(expression)
+ [this.options.polygonKeyName]: coordinate
};
}
@@ -484,7 +518,15 @@ export default abstract class LeafletMap {
}
this.updateMarkers(formattedData, false);
this.updateBoundsInternal();
- if (this.options.draggableMarker || this.options.editablePolygon) {
+ if (this.options.draggableMarker) {
+ const foundEntityWithoutLocation = formattedData.some(mData => !this.convertPosition(mData));
+ this.map.pm.Toolbar.setButtonDisabled('tbMarker', !foundEntityWithoutLocation);
+ this.datasources = formattedData;
+ }
+ if (this.editPolygons) {
+ const foundEntityWithoutPolygon = formattedData.some(pData => !this.isValidPolygonPosition(pData));
+ this.map.pm.Toolbar.setButtonDisabled('tbPolygon', !foundEntityWithoutPolygon);
+ this.map.pm.Toolbar.setButtonDisabled('tbRectangle', !foundEntityWithoutPolygon);
this.datasources = formattedData;
}
} else {
@@ -577,10 +619,10 @@ export default abstract class LeafletMap {
}
dragMarker = (e, data = {} as FormattedData) => {
- if (e.type !== 'dragend') {
+ if (e === undefined) {
return;
}
- this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }).subscribe();
+ this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe();
}
private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings,
@@ -728,11 +770,15 @@ export default abstract class LeafletMap {
// Polygon
+ isValidPolygonPosition(data: FormattedData): boolean {
+ return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]);
+ }
+
updatePolygons(polyData: FormattedData[], updateBounds = true) {
const keys: string[] = [];
this.polygonsData = deepClone(polyData);
polyData.forEach((data: FormattedData) => {
- if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) {
+ if (this.isValidPolygonPosition(data)) {
if (isString((data[this.options.polygonKeyName]))) {
data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]);
}
@@ -758,15 +804,14 @@ export default abstract class LeafletMap {
}
dragPolygonVertex = (e?, data = {} as FormattedData) => {
- if (e === undefined || (e.type !== 'editable:vertex:dragend' && e.type !== 'editable:vertex:deleted')) {
+ if (e === undefined) {
return;
}
- if (this.options.provider !== MapProviders.image) {
- for (const key of Object.keys(e.layer._latlngs[0])) {
- e.layer._latlngs[0][key] = checkLngLat(e.layer._latlngs[0][key], this.southWest, this.northEast);
- }
+ let coordinates = e.layer.getLatLngs();
+ if (coordinates.length === 1) {
+ coordinates = coordinates[0];
}
- this.savePolygonLocation({ ...data, ...this.convertPolygonToCustomFormat(e.layer._latlngs) }).subscribe();
+ this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {});
}
createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
index d9183c1cb6..5b99b792e9 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
@@ -57,6 +57,7 @@ export type MapSettings = {
showCoverageOnHover: boolean,
animate: boolean,
maxClusterRadius: number,
+ spiderfyOnMaxZoom: boolean,
chunkedLoading: boolean,
removeOutsideVisibleBounds: boolean,
useCustomProvider: boolean,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts
index 3ad10a0980..eca27d6532 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts
@@ -14,41 +14,23 @@
/// limitations under the License.
///
-import {
- defaultSettings,
- FormattedData,
- hereProviders,
- MapProviders,
- UnitedMapSettings
-} from './map-models';
+import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models';
import LeafletMap from './leaflet-map';
import {
commonMapSettingsSchema,
mapPolygonSchema,
- mapProviderSchema,
markerClusteringSettingsSchema,
markerClusteringSettingsSchemaLeaflet,
routeMapSettingsSchema
} from './schemes';
import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
-import {
- addCondition,
- addGroupInfo,
- addToSchema,
- initSchema,
- mergeSchemes
-} from '@core/schema-utils';
+import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
import { WidgetContext } from '@app/modules/home/models/widget-component.models';
import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils';
import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models';
-import { EntityId } from '@shared/models/id/entity-id';
-import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
-import { AttributeService } from '@core/http/attribute.service';
import { TranslateService } from '@ngx-translate/core';
import { UtilsService } from '@core/services/utils.service';
import { EntityDataPageLink } from '@shared/models/query/query.models';
-import { isDefined } from '@core/utils';
-import { forkJoin, Observable, of } from 'rxjs';
import { providerClass } from '@home/components/widget/lib/maps/providers';
// @dynamic
@@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface {
}
parseWithTranslation.setTranslate(this.translate);
this.map = new MapClass(this.ctx, $element, this.settings);
- this.map.saveMarkerLocation = this.setMarkerLocation;
- this.map.savePolygonLocation = this.savePolygonLocation;
this.pageLink = {
page: 0,
pageSize: this.settings.mapPageSize,
@@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface {
}, entityName, null, entityLabel);
}
- setMarkerLocation = (e: FormattedData, lat?: number, lng?: number) => {
- const attributeService = this.ctx.$injector.get(AttributeService);
-
- const entityId: EntityId = {
- entityType: e.$datasource.entityType,
- id: e.$datasource.entityId
- };
- const attributes = [];
- const timeseries = [];
-
- const latProperties = [this.settings.latKeyName, this.settings.xPosKeyName];
- const lngProperties = [this.settings.lngKeyName, this.settings.yPosKeyName];
- e.$datasource.dataKeys.forEach(key => {
- let value;
- if (latProperties.includes(key.name)) {
- value = {
- key: key.name,
- value: isDefined(lat) ? lat : e[key.name]
- };
- } else if (lngProperties.includes(key.name)) {
- value = {
- key: key.name,
- value: isDefined(lng) ? lng : e[key.name]
- };
- }
- if (value) {
- if (key.type === DataKeyType.attribute) {
- attributes.push(value);
- }
- if (key.type === DataKeyType.timeseries) {
- timeseries.push(value);
- }
- }
- });
- const observables: Observable[] = [];
- if (timeseries.length) {
- observables.push(attributeService.saveEntityTimeseries(
- entityId,
- LatestTelemetry.LATEST_TELEMETRY,
- timeseries
- ));
- }
- if (attributes.length) {
- observables.push(attributeService.saveEntityAttributes(
- entityId,
- AttributeScope.SERVER_SCOPE,
- attributes
- ));
- }
- if (observables.length) {
- return forkJoin(observables);
- } else {
- return of(null);
- }
- }
-
- savePolygonLocation = (e: FormattedData, coordinates?: Array) => {
- const attributeService = this.ctx.$injector.get(AttributeService);
-
- const entityId: EntityId = {
- entityType: e.$datasource.entityType,
- id: e.$datasource.entityId
- };
- const attributes = [];
- const timeseries = [];
-
- const coordinatesProperties = this.settings.polygonKeyName;
- e.$datasource.dataKeys.forEach(key => {
- let value;
- if (coordinatesProperties === key.name) {
- value = {
- key: key.name,
- value: isDefined(coordinates) ? coordinates : e[key.name]
- };
- }
- if (value) {
- if (key.type === DataKeyType.attribute) {
- attributes.push(value);
- }
- if (key.type === DataKeyType.timeseries) {
- timeseries.push(value);
- }
- }
- });
- const observables: Observable[] = [];
- if (timeseries.length) {
- observables.push(attributeService.saveEntityTimeseries(
- entityId,
- LatestTelemetry.LATEST_TELEMETRY,
- timeseries
- ));
- }
- if (attributes.length) {
- observables.push(attributeService.saveEntityAttributes(
- entityId,
- AttributeScope.SERVER_SCOPE,
- attributes
- ));
- }
- if (observables.length) {
- return forkJoin(observables);
- } else {
- return of(null);
- }
- }
-
initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings {
const functionParams = ['data', 'dsData', 'dsIndex'];
this.provider = settings.provider || this.mapProvider;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss
index 7abf1423c7..147386685c 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss
@@ -29,6 +29,10 @@
box-shadow: none;
}
-.leaflet-container{
+.leaflet-container {
background-color: white;
}
+
+.leaflet-buttons-control-button.pm-disabled {
+ pointer-events: none;
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts
index cd3f19980f..5550706402 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts
@@ -42,9 +42,7 @@ export class Marker {
constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings,
data?: FormattedData, dataSources?, onDragendListener?) {
this.setDataSources(data, dataSources);
- this.leafletMarker = L.marker(location, {
- draggable: settings.draggableMarker
- });
+ this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker});
this.markerOffset = [
isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5,
@@ -72,8 +70,8 @@ export class Marker {
});
}
- if (onDragendListener) {
- this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data));
+ if (settings.draggableMarker && onDragendListener) {
+ this.leafletMarker.on('pm:dragend', (e) => onDragendListener(e, this.data));
}
}
@@ -199,19 +197,24 @@ export class Marker {
createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } {
return {
- size: [21, 34],
- icon: L.icon({
- iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color.toHex(),
- iconSize: [21, 34],
- iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]],
- popupAnchor: [0, -34],
- shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow',
- shadowSize: [40, 37],
- shadowAnchor: [12, 35]
+ size: [21, 34],
+ icon: L.icon({
+ iconUrl: this.createColorIconURI(color),
+ iconSize: [21, 34],
+ iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]],
+ popupAnchor: [0, -34],
+ shadowUrl: 'assets/shadow.png',
+ shadowSize: [40, 37],
+ shadowAnchor: [12, 35]
})
};
}
+ createColorIconURI(color: tinycolor.Instance): string {
+ const svg = ``;
+ return 'data:image/svg+xml;base64,' + btoa(svg);
+ }
+
removeMarker() {
/* this.map$.subscribe(map =>
this.leafletMarker.addTo(map))*/
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts
index c7cca2a40b..d87d764d0a 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts
@@ -17,7 +17,6 @@
import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
import { createTooltip } from './maps-utils';
import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils';
-import 'leaflet-editable/src/Leaflet.Editable';
import { FormattedData, PolygonSettings } from './map-models';
export class Polygon {
@@ -37,14 +36,12 @@ export class Polygon {
color: settings.polygonStrokeColor,
weight: settings.polygonStrokeWeight,
fillOpacity: settings.polygonOpacity,
- opacity: settings.polygonStrokeOpacity
+ opacity: settings.polygonStrokeOpacity,
+ pmIgnore: !settings.editablePolygon
}).addTo(this.map);
- if (settings.editablePolygon) {
- this.leafletPoly.enableEdit(this.map);
- if (onDragendListener) {
- this.leafletPoly.on('editable:vertex:dragend', e => onDragendListener(e, this.data));
- this.leafletPoly.on('editable:vertex:deleted', e => onDragendListener(e, this.data));
- }
+
+ if (settings.editablePolygon && onDragendListener) {
+ this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data));
}
@@ -73,13 +70,7 @@ export class Polygon {
updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
this.data = data;
this.dataSources = dataSources;
- if (settings.editablePolygon) {
- this.leafletPoly.disableEdit();
- }
this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]);
- if (settings.editablePolygon) {
- this.leafletPoly.enableEdit(this.map);
- }
if (settings.showPolygonTooltip) {
this.updateTooltip(this.data);
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
index be319ded3a..895dc15763 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
@@ -14,7 +14,8 @@
/// limitations under the License.
///
-import L, { PolylineDecoratorOptions } from 'leaflet';
+// @ts-ignore
+import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet';
import 'leaflet-polylinedecorator';
import { FormattedData, PolylineSettings } from './map-models';
@@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common
export class Polyline {
leafletPoly: L.Polyline;
- polylineDecorator: L.PolylineDecorator;
+ polylineDecorator: PolylineDecorator;
dataSources: FormattedData[];
data: FormattedData;
@@ -36,7 +37,7 @@ export class Polyline {
).addTo(this.map);
if (settings.usePolylineDecorator) {
- this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map);
+ this.polylineDecorator = new PolylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map);
}
}
@@ -47,7 +48,7 @@ export class Polyline {
offset: settings.decoratorOffset,
endOffset: settings.endDecoratorOffset,
repeat: settings.decoratorRepeat,
- symbol: L.Symbol[settings.decoratorSymbol]({
+ symbol: Symbol[settings.decoratorSymbol]({
pixelSize: settings.decoratorSymbolSize,
polygon: false,
pathOptions: {
@@ -78,7 +79,8 @@ export class Polyline {
opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction,
[this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity),
weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction,
- [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight)
+ [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight),
+ pmIgnore: true
};
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts
index f3369dd46c..00d9353218 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts
@@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap {
this.loadGoogle(() => {
const map = L.map($container, {
attributionControl: false,
- editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
(L.gridLayer as any).googleMutant({
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts
index e15c897c3b..caac9a78b4 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts
@@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
super(ctx, $container, options);
const map = L.map($container, {
- editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials);
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts
index 272476ea9e..be427f55cf 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts
@@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators';
import {
aspectCache,
calculateNewPointCoordinate,
- checkLngLat,
parseFunction
} from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models';
@@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap {
zoom: 1,
crs: L.CRS.Simple,
attributionControl: false,
- editable: !!this.options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile
});
this.updateBounds(updateImage);
@@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap {
return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
}
- convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): object {
+ convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} {
+ if (!position) {
+ return {
+ [this.options.xPosKeyName]: null,
+ [this.options.yPosKeyName]: null
+ };
+ }
const point = this.latLngToPoint(position);
const customX = calculateNewPointCoordinate(point.x, width);
const customY = calculateNewPointCoordinate(point.y, height);
@@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap {
point.y = height;
}
- const customLatLng = checkLngLat(this.pointToLatLng(point.x, point.y), this.southWest, this.northEast, offset);
-
return {
[this.options.xPosKeyName]: customX,
- [this.options.yPosKeyName]: customY,
- [this.options.latKeyName]: customLatLng.lat,
- [this.options.lngKeyName]: customLatLng.lng
+ [this.options.yPosKeyName]: customY
};
}
@@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap {
}
}
- convertPolygonToCustomFormat(expression: any[][]): object {
+ convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
+ const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
return {
- [this.options.polygonKeyName] : this.convertToPolygonFormat(expression)
+ [this.options.polygonKeyName]: coordinate
};
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts
index 61312aab23..01eb04ea40 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts
@@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
super(ctx, $container, options);
const map = L.map($container, {
- editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
let tileLayer;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts
index bd34e24331..5e71d92e5d 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts
@@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap {
super(ctx, $container, options);
const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
const map = L.map($container, {
- editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
const txLayer = L.tileLayer(txUrl, {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts
index 4c7e6e61fa..ff52ece929 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts
@@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet =
type: 'number',
default: 80
},
+ spiderfyOnMaxZoom: {
+ title: 'Spiderfy at the max zoom level (to see all cluster markers)',
+ type: 'boolean',
+ default: false
+ },
chunkedLoading: {
title: 'Use chunks for adding markers so that the page does not freeze',
type: 'boolean',
@@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet =
'showCoverageOnHover',
'animate',
'maxClusterRadius',
+ 'spiderfyOnMaxZoom',
'chunkedLoading',
'removeOutsideVisibleBounds'
]
diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts
index b8b1d193e4..dfa630b3ad 100644
--- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts
@@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
addGroupInfo(schema, 'Path Settings');
addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
addGroupInfo(schema, 'Path Points Settings');
- addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon']));
+ const mapPolygonSchemaWithoutEdit = mapPolygonSchema;
+ delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon;
+ mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1);
+ addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon']));
addGroupInfo(schema, 'Polygon Settings');
return schema;
}
@@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
rotationAngle: 0
};
this.settings = { ...settings, ...this.ctx.settings };
+ this.settings.editablePolygon = false;
this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
index ed9ef23f82..ba692ed122 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
@@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges-
import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component';
import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component';
import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component';
+import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component';
@NgModule({
declarations:
@@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi
NavigationCardsWidgetComponent,
NavigationCardWidgetComponent,
QrCodeWidgetComponent,
- MarkdownWidgetComponent
+ MarkdownWidgetComponent,
+ SelectEntityDialogComponent
],
imports: [
CommonModule,
diff --git a/ui-ngx/src/assets/add_location.svg b/ui-ngx/src/assets/add_location.svg
deleted file mode 100644
index e3150115b7..0000000000
--- a/ui-ngx/src/assets/add_location.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/ui-ngx/src/assets/add_polygon.svg b/ui-ngx/src/assets/add_polygon.svg
deleted file mode 100644
index 098f02c128..0000000000
--- a/ui-ngx/src/assets/add_polygon.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index bd14f73e27..3ee86c15d6 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -3238,7 +3238,40 @@
"update-timeseries": "Update timeseries",
"value": "Value"
},
- "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type"
+ "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type",
+ "maps": {
+ "select-entity": "Select entity",
+ "select-entity-hint": "Hint: after selection click at the map to set position",
+ "tooltips": {
+ "placeMarker": "Click to place marker",
+ "firstVertex": "Click to place first point",
+ "continueLine": "Click to continue drawing",
+ "finishLine": "Click any existing marker to finish",
+ "finishPoly": "Click first marker to finish and save",
+ "finishRect": "Click to finish and save",
+ "startCircle": "Click to place circle center",
+ "finishCircle": "Click to finish circle",
+ "placeCircleMarker": "Click to place circle marker"
+ },
+ "actions": {
+ "finish": "Finish",
+ "cancel": "Cancel",
+ "removeLastVertex": "Remove last point"
+ },
+ "buttonTitles": {
+ "drawMarkerButton": "Create marker",
+ "drawPolyButton": "Create polygon",
+ "drawLineButton": "Create Polyline",
+ "drawCircleButton": "Create Circle",
+ "drawRectButton": "Create rectangle",
+ "editButton": "Edit mode",
+ "dragButton": "Drag-drop mode",
+ "cutButton": "Cut polygon area",
+ "deleteButton": "Remove",
+ "drawCircleMarkerButton": "Create circle marker",
+ "rotateButton": "Rotate polygon"
+ }
+ }
},
"icon": {
"icon": "Icon",
diff --git a/ui-ngx/src/assets/shadow.png b/ui-ngx/src/assets/shadow.png
new file mode 100644
index 0000000000..fc2f271799
Binary files /dev/null and b/ui-ngx/src/assets/shadow.png differ
diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json
index 5f897102b7..e73cce9a21 100644
--- a/ui-ngx/src/tsconfig.app.json
+++ b/ui-ngx/src/tsconfig.app.json
@@ -3,7 +3,7 @@
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify",
- "react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet.markercluster", "leaflet-editable"]
+ "react", "react-dom", "jstree", "raphael", "canvas-gauges"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true
diff --git a/ui-ngx/src/typings/add-marker.d.ts b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts
similarity index 72%
rename from ui-ngx/src/typings/add-marker.d.ts
rename to ui-ngx/src/typings/leaflet-geoman-extend.d.ts
index daef6bada9..7b3378aee3 100644
--- a/ui-ngx/src/typings/add-marker.d.ts
+++ b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts
@@ -17,15 +17,13 @@
import * as L from 'leaflet';
declare module 'leaflet' {
-
- namespace Control {
- class AddMarker extends L.Control { }
- class AddPolygon extends L.Control { }
- }
-
- namespace control {
- function addMarker(options): Control.AddMarker;
- function addPolygon(options): Control.AddPolygon;
+ namespace PM {
+ interface PMMapToolbar {
+ toggleButton(
+ name: string,
+ status: boolean,
+ disableOthers?: boolean
+ ): void;
}
-
+ }
}
diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json
index 38cdc74820..131a93b826 100644
--- a/ui-ngx/tsconfig.json
+++ b/ui-ngx/tsconfig.json
@@ -20,7 +20,8 @@
"src/typings/jquery.flot.typings.d.ts",
"src/typings/jquery.jstree.typings.d.ts",
"src/typings/split.js.typings.d.ts",
- "src/typings/add-marker.d.ts"
+ "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.d.ts",
+ "src/typings/leaflet-geoman-extend.d.ts"
],
"paths": {
"@app/*": ["src/app/*"],
diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock
index acb3a9eaa2..046e100cd1 100644
--- a/ui-ngx/yarn.lock
+++ b/ui-ngx/yarn.lock
@@ -1422,6 +1422,18 @@
"@types/flowjs" "2.13.3"
tslib "^1.9.0"
+"@geoman-io/leaflet-geoman-free@^2.11.3":
+ version "2.11.3"
+ resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36"
+ integrity sha512-LsiurEgKEHBcTnAVl8h7EfS5V/doCuxePzPE9SnfrhtJBN7IzP6UwkEo35Agwko+BnIuw/o2bE4F7irvKwQzjw==
+ dependencies:
+ "@turf/boolean-contains" "6.3.0"
+ "@turf/kinks" "6.3.0"
+ "@turf/line-intersect" "6.3.0"
+ "@turf/line-split" "6.3.0"
+ lodash "4.17.21"
+ polygon-clipping "0.15.3"
+
"@istanbuljs/schema@^0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
@@ -1688,6 +1700,167 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
+"@turf/bbox@*", "@turf/bbox@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5"
+ integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/meta" "^6.5.0"
+
+"@turf/bearing@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/bearing/-/bearing-6.5.0.tgz#462a053c6c644434bdb636b39f8f43fb0cd857b0"
+ integrity sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+
+"@turf/boolean-contains@6.3.0":
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.3.0.tgz#fe4fc359e408c8c3c89e7fb159c9d31fde48779a"
+ integrity sha512-1MW7B5G5tIu1lnAv3pXyFzl75wfBYnbA2GhwHDb4okIXMhloy/r5uIqAZHo0fOXykKVJS/gIfA/MioKIftoTug==
+ dependencies:
+ "@turf/bbox" "^6.3.0"
+ "@turf/boolean-point-in-polygon" "^6.3.0"
+ "@turf/boolean-point-on-line" "^6.3.0"
+ "@turf/helpers" "^6.3.0"
+ "@turf/invariant" "^6.3.0"
+
+"@turf/boolean-point-in-polygon@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz#6d2e9c89de4cd2e4365004c1e51490b7795a63cf"
+ integrity sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+
+"@turf/boolean-point-on-line@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz#a8efa7bad88760676f395afb9980746bc5b376e9"
+ integrity sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+
+"@turf/destination@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/destination/-/destination-6.5.0.tgz#30a84702f9677d076130e0440d3223ae503fdae1"
+ integrity sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+
+"@turf/distance@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.5.0.tgz#21f04d5f86e864d54e2abde16f35c15b4f36149a"
+ integrity sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+
+"@turf/helpers@6.x", "@turf/helpers@^6.3.0", "@turf/helpers@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e"
+ integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==
+
+"@turf/invariant@^6.3.0", "@turf/invariant@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.5.0.tgz#970afc988023e39c7ccab2341bd06979ddc7463f"
+ integrity sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+
+"@turf/kinks@6.3.0":
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/@turf/kinks/-/kinks-6.3.0.tgz#a16b4ccc5a5aae139d43e36271e0a0494fdb4bf7"
+ integrity sha512-BLWvbl2/fa4SeJzVMbleT6Vo1cmzwmzRfxL2xxMei2jmf6JSvqDoMJFwIHGXrLZXvhOCb1b2C+MhBfhtc7kYkQ==
+ dependencies:
+ "@turf/helpers" "^6.3.0"
+
+"@turf/line-intersect@6.3.0":
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.3.0.tgz#726a50edc66bb7b5e798b052b103fb0da4d1c4f4"
+ integrity sha512-3naxR7XpkPd2vst3Mw6DFry4C9m3o0/f2n/xu5UAyxb88Ie4m2k+1eqkhzMMx/0L+E6iThWpLx7DASM6q6o9ow==
+ dependencies:
+ "@turf/helpers" "^6.3.0"
+ "@turf/invariant" "^6.3.0"
+ "@turf/line-segment" "^6.3.0"
+ "@turf/meta" "^6.3.0"
+ geojson-rbush "3.x"
+
+"@turf/line-intersect@^6.3.0", "@turf/line-intersect@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz#dea48348b30c093715d2195d2dd7524aee4cf020"
+ integrity sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+ "@turf/line-segment" "^6.5.0"
+ "@turf/meta" "^6.5.0"
+ geojson-rbush "3.x"
+
+"@turf/line-segment@^6.3.0", "@turf/line-segment@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/line-segment/-/line-segment-6.5.0.tgz#ee73f3ffcb7c956203b64ed966d96af380a4dd65"
+ integrity sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+ "@turf/meta" "^6.5.0"
+
+"@turf/line-split@6.3.0":
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/@turf/line-split/-/line-split-6.3.0.tgz#ee218f66cd65ce84eafc4956c24083663f6082ea"
+ integrity sha512-Q0nUJ0vczy11piyEz0FaKScFwSQtb1HJ2RPEMCw1coUJhTCB02KBWQLImhYqwsD3uLg+H/fxaJ1Gva6EPWoDNQ==
+ dependencies:
+ "@turf/bbox" "^6.3.0"
+ "@turf/helpers" "^6.3.0"
+ "@turf/invariant" "^6.3.0"
+ "@turf/line-intersect" "^6.3.0"
+ "@turf/line-segment" "^6.3.0"
+ "@turf/meta" "^6.3.0"
+ "@turf/nearest-point-on-line" "^6.3.0"
+ "@turf/square" "^6.3.0"
+ "@turf/truncate" "^6.3.0"
+ geojson-rbush "3.x"
+
+"@turf/meta@6.x", "@turf/meta@^6.3.0", "@turf/meta@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca"
+ integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+
+"@turf/nearest-point-on-line@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz#8e1cd2cdc0b5acaf4c8d8b3b33bb008d3cb99e7b"
+ integrity sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==
+ dependencies:
+ "@turf/bearing" "^6.5.0"
+ "@turf/destination" "^6.5.0"
+ "@turf/distance" "^6.5.0"
+ "@turf/helpers" "^6.5.0"
+ "@turf/invariant" "^6.5.0"
+ "@turf/line-intersect" "^6.5.0"
+ "@turf/meta" "^6.5.0"
+
+"@turf/square@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/square/-/square-6.5.0.tgz#ab43eef99d39c36157ab5b80416bbeba1f6b2122"
+ integrity sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==
+ dependencies:
+ "@turf/distance" "^6.5.0"
+ "@turf/helpers" "^6.5.0"
+
+"@turf/truncate@^6.3.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@turf/truncate/-/truncate-6.5.0.tgz#c3a16cad959f1be1c5156157d5555c64b19185d8"
+ integrity sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==
+ dependencies:
+ "@turf/helpers" "^6.5.0"
+ "@turf/meta" "^6.5.0"
+
"@types/canvas-gauges@^2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210"
@@ -1725,6 +1898,11 @@
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==
+"@types/geojson@7946.0.8":
+ version "7946.0.8"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
+ integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
+
"@types/glob@^7.1.1":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
@@ -1791,34 +1969,48 @@
dependencies:
"@types/jquery" "*"
-"@types/leaflet-editable@^1.2.1":
+"@types/leaflet-polylinedecorator@^1.6.1":
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.1.tgz#b6522f9dae52146bf73da249e4bedfbab200c6e4"
+ integrity sha512-9etweJ2U4SWqcV/AR3i0NdWJByeMn6+zMUNlO6jVbpL8UI6qrMKybu8v9/s6UR4oXvsV4lZT6vzAsNAAMq5Ssg==
+ dependencies:
+ "@types/leaflet" "*"
+
+"@types/leaflet-providers@^1.2.1":
version "1.2.1"
- resolved "https://registry.yarnpkg.com/@types/leaflet-editable/-/leaflet-editable-1.2.1.tgz#12f1bd1d9af7beafbac256216062e97fe2ee4d55"
- integrity sha512-7Oms1HgulWiclkI0s1XLmr1yRylNoJX8sVUfAv9+28JzwWbKbLcQ6//vhFEOmoMlBQyL5veogKpUUb5qeF+Qyg==
+ resolved "https://registry.yarnpkg.com/@types/leaflet-providers/-/leaflet-providers-1.2.1.tgz#620669b828959740a2d8572e0c0288a2382d3564"
+ integrity sha512-uNyuXiNV2q3fmgNjQji2P6RjQISmL40bbOL91/3OAwiE3XhkLKPmSAtAcfe11MAIz45iEjdFZJWppq9QyfnPIw==
dependencies:
"@types/leaflet" "*"
-"@types/leaflet-polylinedecorator@^1.6.0":
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#1572131ffedb3154c6e18e682d2fb700e203af19"
- integrity sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw==
+"@types/leaflet.gridlayer.googlemutant@^0.4.6":
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/@types/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.4.6.tgz#86d3ba9d432dec29b4796e37d815c233680e7fcb"
+ integrity sha512-L0J7NadcZp5bcKQrv4DVlsEbQ90xLsOKScckAMnxoghh/wogk0GVkauYOYHBKeKDkx9qkMRzTf8oO+fKeYD7oQ==
dependencies:
"@types/leaflet" "*"
-"@types/leaflet.markercluster@^1.4.4":
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.4.tgz#4b4772c86182923e920061a0c25cb3e53543ad35"
- integrity sha512-BQAilNWlBpYl4+PrsJXLOh4vyv7KfWi5kh3Fclg5y4gEeNeXKqhS6y1zzBB4+wcTuVUnMWfm2G0MfqA4yA5A5A==
+"@types/leaflet.markercluster@^1.4.6":
+ version "1.4.6"
+ resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.6.tgz#1159460b374ba5e329cb678d0e427f99dca75be5"
+ integrity sha512-MD+bUDzxHznY0zOlSBUAMNQUGB2+xpJPKrR2MNEoBAAKa3QTKJJySBtCqWyGLvYNNO+Cdyc2c64aF2IFwe4fcQ==
dependencies:
"@types/leaflet" "*"
-"@types/leaflet@*", "@types/leaflet@1.5.17":
+"@types/leaflet@*":
version "1.5.17"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b"
integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g==
dependencies:
"@types/geojson" "*"
+"@types/leaflet@^1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.6.tgz#6580f4babb648972c5af3abc3d66866753fa9311"
+ integrity sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA==
+ dependencies:
+ "@types/geojson" "*"
+
"@types/lodash@^4.14.170":
version "4.14.170"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
@@ -4858,6 +5050,17 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+geojson-rbush@3.x:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/geojson-rbush/-/geojson-rbush-3.2.0.tgz#8b543cf0d56f99b78faf1da52bb66acad6dfc290"
+ integrity sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==
+ dependencies:
+ "@turf/bbox" "*"
+ "@turf/helpers" "6.x"
+ "@turf/meta" "6.x"
+ "@types/geojson" "7946.0.8"
+ rbush "^3.0.1"
+
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
@@ -6224,11 +6427,6 @@ klona@^2.0.4:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
-leaflet-editable@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/leaflet-editable/-/leaflet-editable-1.2.0.tgz#a3a01001764ba58ea923381ee6a1c814708a0b84"
- integrity sha512-wG11JwpL8zqIbypTop6xCRGagMuWw68ihYu4uqrqc5Ep0wnEJeyob7NB2Rt5t74Oih4rwJ3OfwaGbzdowOGfYQ==
-
leaflet-polylinedecorator@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#9ef79fd1b5302d67b72efe959a8ecd2553f27266"
@@ -6236,25 +6434,25 @@ leaflet-polylinedecorator@^1.6.0:
dependencies:
leaflet-rotatedmarker "^0.2.0"
-leaflet-providers@^1.12.0:
- version "1.12.0"
- resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.12.0.tgz#bf407f580d9564480e2346bc1e6412ef696624cf"
- integrity sha512-pU/mR4B+NbayBGCg5/88dmRq7t1EGiNPhsVGV3yqHuDn594vIwus4CiPVW0RtiKJNKg8Vf1pILAbFl0i+yk+lQ==
+leaflet-providers@^1.13.0:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.13.0.tgz#10c843a23d5823a65096d40ad53f27029e13434b"
+ integrity sha512-f/sN5wdgBbVA2jcCYzScIfYNxKdn2wBJP9bu+5cRX9Xj6g8Bt1G9Sr8WgJAt/ckIFIc3LVVxCBNFpSCfTuUElg==
leaflet-rotatedmarker@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277"
integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc=
-leaflet.gridlayer.googlemutant@0.10.2:
- version "0.10.2"
- resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.10.2.tgz#3c5351db4230beac1b1ea1f774d9288cfb0b6283"
- integrity sha512-r3le0W8izKmF2aeCCYp6P+dLQvPadV/vpJkres0ltDHiWac6qt3fQPNWjQl+8WCsCmcGTb1y5bmHOx0Yj6HA7g==
+leaflet.gridlayer.googlemutant@0.13.4:
+ version "0.13.4"
+ resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.13.4.tgz#0add37d240c70c999e1f1d341208e6fea2372c40"
+ integrity sha512-oC6xUSFJ9HP4WIupXakgiYckdBHuHQeSaxTXsVlcvcpfsuYoJ/HFIrz1bmK4Qr/qKO4fY1MDM6AoewU7Bph8ZQ==
-leaflet.markercluster@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.0.tgz#54db42485da32fc3d92c7ae22d0d7982879e0b67"
- integrity sha512-Fvf/cq4o806mJL50n+fZW9+QALDDLPvt7vuAjlD2vfnxx3srMDs2vWINJze4nKYJYRY45OC6tM/669C3pLwMCA==
+leaflet.markercluster@^1.5.3:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz#9cdb52a4eab92671832e1ef9899669e80efc4056"
+ integrity sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==
leaflet@^1.7.1:
version "1.7.1"
@@ -6365,7 +6563,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21:
+lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -7651,6 +7849,13 @@ pnp-webpack-plugin@1.6.4:
dependencies:
ts-pnp "^1.1.6"
+polygon-clipping@0.15.3:
+ version "0.15.3"
+ resolved "https://registry.yarnpkg.com/polygon-clipping/-/polygon-clipping-0.15.3.tgz#0215840438470ba2e9e6593625e4ea5c1087b4b7"
+ integrity sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==
+ dependencies:
+ splaytree "^3.1.0"
+
popper.js@1.16.1-lts:
version "1.16.1-lts"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
@@ -8191,6 +8396,11 @@ querystringify@^2.1.1:
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
+quickselect@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
+ integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
+
raf@^3.4.0, raf@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
@@ -8243,6 +8453,13 @@ raw-loader@4.0.2:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
+rbush@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf"
+ integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
+ dependencies:
+ quickselect "^2.0.0"
+
rc-align@^4.0.0:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668"
@@ -9298,6 +9515,11 @@ speed-measure-webpack-plugin@1.4.2:
dependencies:
chalk "^4.1.0"
+splaytree@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/splaytree/-/splaytree-3.1.0.tgz#17d4a0108a6da3627579690b7b847241e18ddec8"
+ integrity sha512-gvUGR7xnOy0fLKTCxDeUZYgU/I1Tdf8M/lM1Qrf8L2TIOR5ipZjGk02uYcdv0o2x7WjVRgpm3iS2clLyuVAt0Q==
+
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"