Commit 715eefa6d0b1cf035a770166179e3081504c4adb

Authored by Igor Kulikov
Committed by GitHub
2 parents e378f86c 2e8b9b5c

Merge pull request #5616 from vvlladd28/improvement/map-widgets/marker-placement

[3.3.3] UI: Improvement add/edit location marker/polygon in maps widgets
Showing 29 changed files with 758 additions and 445 deletions
@@ -830,6 +830,7 @@ @@ -830,6 +830,7 @@
830 <exclude>src/.browserslistrc</exclude> 830 <exclude>src/.browserslistrc</exclude>
831 <exclude>**/yarn.lock</exclude> 831 <exclude>**/yarn.lock</exclude>
832 <exclude>**/*.raw</exclude> 832 <exclude>**/*.raw</exclude>
  833 + <exclude>**/*.patch</exclude>
833 <exclude>**/apache/cassandra/io/**</exclude> 834 <exclude>**/apache/cassandra/io/**</exclude>
834 <exclude>.run/**</exclude> 835 <exclude>.run/**</exclude>
835 </excludes> 836 </excludes>
@@ -79,6 +79,7 @@ @@ -79,6 +79,7 @@
79 "src/app/modules/home/components/widget/lib/maps/markers.scss", 79 "src/app/modules/home/components/widget/lib/maps/markers.scss",
80 "node_modules/leaflet.markercluster/dist/MarkerCluster.css", 80 "node_modules/leaflet.markercluster/dist/MarkerCluster.css",
81 "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css", 81 "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css",
  82 + "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css",
82 "node_modules/prismjs/themes/prism.css", 83 "node_modules/prismjs/themes/prism.css",
83 "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" 84 "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
84 ], 85 ],
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 "@date-io/date-fns": "^2.10.11", 28 "@date-io/date-fns": "^2.10.11",
29 "@flowjs/flow.js": "^2.14.1", 29 "@flowjs/flow.js": "^2.14.1",
30 "@flowjs/ngx-flow": "~0.4.6", 30 "@flowjs/ngx-flow": "~0.4.6",
  31 + "@geoman-io/leaflet-geoman-free": "^2.11.3",
31 "@juggle/resize-observer": "^3.3.1", 32 "@juggle/resize-observer": "^3.3.1",
32 "@mat-datetimepicker/core": "~6.0.2", 33 "@mat-datetimepicker/core": "~6.0.2",
33 "@material-ui/core": "^4.11.4", 34 "@material-ui/core": "^4.11.4",
@@ -57,11 +58,10 @@ @@ -57,11 +58,10 @@
57 "jstree-bootstrap-theme": "^1.0.1", 58 "jstree-bootstrap-theme": "^1.0.1",
58 "jszip": "^3.6.0", 59 "jszip": "^3.6.0",
59 "leaflet": "^1.7.1", 60 "leaflet": "^1.7.1",
60 - "leaflet-editable": "^1.2.0",  
61 "leaflet-polylinedecorator": "^1.6.0", 61 "leaflet-polylinedecorator": "^1.6.0",
62 - "leaflet-providers": "^1.12.0",  
63 - "leaflet.gridlayer.googlemutant": "0.10.2",  
64 - "leaflet.markercluster": "^1.5.0", 62 + "leaflet-providers": "^1.13.0",
  63 + "leaflet.gridlayer.googlemutant": "^0.13.4",
  64 + "leaflet.markercluster": "^1.5.3",
65 "material-design-icons": "^3.0.1", 65 "material-design-icons": "^3.0.1",
66 "messageformat": "^2.3.0", 66 "messageformat": "^2.3.0",
67 "moment": "^2.29.1", 67 "moment": "^2.29.1",
@@ -113,10 +113,11 @@ @@ -113,10 +113,11 @@
113 "@types/jquery": "^3.5.2", 113 "@types/jquery": "^3.5.2",
114 "@types/js-beautify": "^1.13.1", 114 "@types/js-beautify": "^1.13.1",
115 "@types/jstree": "^3.3.40", 115 "@types/jstree": "^3.3.40",
116 - "@types/leaflet": "1.5.17",  
117 - "@types/leaflet-editable": "^1.2.1",  
118 - "@types/leaflet-polylinedecorator": "^1.6.0",  
119 - "@types/leaflet.markercluster": "^1.4.4", 116 + "@types/leaflet": "^1.7.6",
  117 + "@types/leaflet-polylinedecorator": "^1.6.1",
  118 + "@types/leaflet-providers": "^1.2.1",
  119 + "@types/leaflet.gridlayer.googlemutant": "^0.4.6",
  120 + "@types/leaflet.markercluster": "^1.4.6",
120 "@types/lodash": "^4.14.170", 121 "@types/lodash": "^4.14.170",
121 "@types/moment-timezone": "^0.5.30", 122 "@types/moment-timezone": "^0.5.30",
122 "@types/mousetrap": "1.6.3", 123 "@types/mousetrap": "1.6.3",
  1 +<!--
  2 +
  3 + Copyright © 2016-2021 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<form #addEntityForm="ngForm" [formGroup]="selectEntityFormGroup" (ngSubmit)="save()">
  19 + <mat-toolbar fxLayout="row" color="primary">
  20 + <h2 translate>widgets.maps.select-entity</h2>
  21 + <span fxFlex></span>
  22 + <button mat-icon-button [matDialogClose]="null" type="button">
  23 + <mat-icon class="material-icons">close</mat-icon>
  24 + </button>
  25 + </mat-toolbar>
  26 + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
  27 + </mat-progress-bar>
  28 + <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
  29 + <div mat-dialog-content>
  30 + <mat-form-field class="mat-block" style="min-width: 280px">
  31 + <mat-label translate>entity.entity</mat-label>
  32 + <mat-select formControlName="entity">
  33 + <mat-option *ngFor="let entity of data.entities" [value]="entity">
  34 + {{ entity.entityName }}
  35 + </mat-option>
  36 + </mat-select>
  37 + </mat-form-field>
  38 + <div class="tb-hint" translate>widgets.maps.select-entity-hint</div>
  39 + </div>
  40 + <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
  41 + <button mat-button color="primary"
  42 + type="button"
  43 + [disabled]="(isLoading$ | async)"
  44 + [matDialogClose]="null"
  45 + cdkFocusInitial>
  46 + {{ 'action.cancel' | translate }}
  47 + </button>
  48 + <button mat-raised-button color="primary"
  49 + type="submit"
  50 + [disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">
  51 + {{ 'action.add' | translate }}
  52 + </button>
  53 + </div>
  54 +</form>
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +:host {
  17 + .tb-hint {
  18 + margin-top: -1.25em;
  19 + max-width: fit-content;
  20 + }
  21 +}
  1 +///
  2 +/// Copyright © 2016-2021 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Component, Inject } from '@angular/core';
  18 +import { DialogComponent } from '@shared/components/dialog.component';
  19 +import { Store } from '@ngrx/store';
  20 +import { AppState } from '@core/core.state';
  21 +import { Router } from '@angular/router';
  22 +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
  23 +import { FormBuilder, FormGroup, Validators } from '@angular/forms';
  24 +import { FormattedData } from '@home/components/widget/lib/maps/map-models';
  25 +
  26 +export interface SelectEntityDialogData {
  27 + entities: FormattedData[];
  28 +}
  29 +
  30 +@Component({
  31 + selector: 'tb-select-entity-dialog',
  32 + templateUrl: './select-entity-dialog.component.html',
  33 + styleUrls: ['./select-entity-dialog.component.scss']
  34 +})
  35 +export class SelectEntityDialogComponent extends DialogComponent<SelectEntityDialogComponent, FormattedData> {
  36 +
  37 + selectEntityFormGroup: FormGroup;
  38 +
  39 + constructor(protected store: Store<AppState>,
  40 + protected router: Router,
  41 + @Inject(MAT_DIALOG_DATA) public data: SelectEntityDialogData,
  42 + public dialogRef: MatDialogRef<SelectEntityDialogComponent, FormattedData>,
  43 + public fb: FormBuilder) {
  44 + super(store, router, dialogRef);
  45 +
  46 + this.selectEntityFormGroup = this.fb.group(
  47 + {
  48 + entity: ['', Validators.required]
  49 + }
  50 + );
  51 + }
  52 +
  53 + save(): void {
  54 + this.dialogRef.close(this.selectEntityFormGroup.value.entity);
  55 + }
  56 +}
@@ -14,23 +14,15 @@ @@ -14,23 +14,15 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import L, {  
18 - FeatureGroup,  
19 - Icon,  
20 - LatLngBounds,  
21 - LatLngTuple,  
22 - markerClusterGroup,  
23 - MarkerClusterGroup,  
24 - MarkerClusterGroupOptions, Projection  
25 -} from 'leaflet'; 17 +import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet';
26 import tinycolor from 'tinycolor2'; 18 import tinycolor from 'tinycolor2';
27 import 'leaflet-providers'; 19 import 'leaflet-providers';
28 -import 'leaflet.markercluster/dist/leaflet.markercluster'; 20 +import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster';
  21 +import '@geoman-io/leaflet-geoman-free';
29 22
30 import { 23 import {
31 defaultSettings, 24 defaultSettings,
32 FormattedData, 25 FormattedData,
33 - MapProviders,  
34 MapSettings, 26 MapSettings,
35 MarkerSettings, 27 MarkerSettings,
36 PolygonSettings, 28 PolygonSettings,
@@ -39,12 +31,10 @@ import { @@ -39,12 +31,10 @@ import {
39 UnitedMapSettings 31 UnitedMapSettings
40 } from './map-models'; 32 } from './map-models';
41 import { Marker } from './markers'; 33 import { Marker } from './markers';
42 -import { Observable, of } from 'rxjs'; 34 +import { forkJoin, Observable, of } from 'rxjs';
43 import { Polyline } from './polyline'; 35 import { Polyline } from './polyline';
44 import { Polygon } from './polygon'; 36 import { Polygon } from './polygon';
45 -import {  
46 - createTooltip,  
47 -} from '@home/components/widget/lib/maps/maps-utils'; 37 +import { createTooltip } from '@home/components/widget/lib/maps/maps-utils';
48 import { 38 import {
49 checkLngLat, 39 checkLngLat,
50 createLoadingDiv, 40 createLoadingDiv,
@@ -54,6 +44,15 @@ import { @@ -54,6 +44,15 @@ import {
54 } from '@home/components/widget/lib/maps/common-maps-utils'; 44 } from '@home/components/widget/lib/maps/common-maps-utils';
55 import { WidgetContext } from '@home/models/widget-component.models'; 45 import { WidgetContext } from '@home/models/widget-component.models';
56 import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; 46 import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils';
  47 +import { TranslateService } from '@ngx-translate/core';
  48 +import {
  49 + SelectEntityDialogComponent,
  50 + SelectEntityDialogData
  51 +} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component';
  52 +import { MatDialog } from '@angular/material/dialog';
  53 +import { AttributeService } from '@core/http/attribute.service';
  54 +import { EntityId } from '@shared/models/id/entity-id';
  55 +import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
57 56
58 export default abstract class LeafletMap { 57 export default abstract class LeafletMap {
59 58
@@ -78,20 +77,20 @@ export default abstract class LeafletMap { @@ -78,20 +77,20 @@ export default abstract class LeafletMap {
78 drawRoutes: boolean; 77 drawRoutes: boolean;
79 showPolygon: boolean; 78 showPolygon: boolean;
80 updatePending = false; 79 updatePending = false;
  80 + editPolygons = false;
  81 + selectedEntity: FormattedData;
81 addMarkers: L.Marker[] = []; 82 addMarkers: L.Marker[] = [];
82 addPolygons: L.Polygon[] = []; 83 addPolygons: L.Polygon[] = [];
83 // tslint:disable-next-line:no-string-literal 84 // tslint:disable-next-line:no-string-literal
84 southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); 85 southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180);
85 // tslint:disable-next-line:no-string-literal 86 // tslint:disable-next-line:no-string-literal
86 northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); 87 northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180);
87 - mousePositionOnMap: L.LatLng;  
88 - addMarker: L.Control;  
89 - addPolygon: L.Control;  
90 88
91 protected constructor(public ctx: WidgetContext, 89 protected constructor(public ctx: WidgetContext,
92 public $container: HTMLElement, 90 public $container: HTMLElement,
93 options: UnitedMapSettings) { 91 options: UnitedMapSettings) {
94 this.options = options; 92 this.options = options;
  93 + this.editPolygons = options.showPolygon && options.editablePolygon;
95 } 94 }
96 95
97 public initSettings(options: MapSettings) { 96 public initSettings(options: MapSettings) {
@@ -102,16 +101,28 @@ export default abstract class LeafletMap { @@ -102,16 +101,28 @@ export default abstract class LeafletMap {
102 removeOutsideVisibleBounds, 101 removeOutsideVisibleBounds,
103 animate, 102 animate,
104 chunkedLoading, 103 chunkedLoading,
  104 + spiderfyOnMaxZoom,
105 maxClusterRadius, 105 maxClusterRadius,
106 maxZoom }: MapSettings = options; 106 maxZoom }: MapSettings = options;
107 if (useClusterMarkers) { 107 if (useClusterMarkers) {
  108 + // disabled marker cluster icon
  109 + (L as any).MarkerCluster = (L as any).MarkerCluster.extend({
  110 + options: { pmIgnore: true, ...L.Icon.prototype.options }
  111 + });
108 const clusteringSettings: MarkerClusterGroupOptions = { 112 const clusteringSettings: MarkerClusterGroupOptions = {
109 - spiderfyOnMaxZoom: false, 113 + spiderfyOnMaxZoom,
110 zoomToBoundsOnClick: zoomOnClick, 114 zoomToBoundsOnClick: zoomOnClick,
111 showCoverageOnHover, 115 showCoverageOnHover,
112 removeOutsideVisibleBounds, 116 removeOutsideVisibleBounds,
113 animate, 117 animate,
114 - chunkedLoading 118 + chunkedLoading,
  119 + pmIgnore: true,
  120 + spiderLegPolylineOptions: {
  121 + pmIgnore: true
  122 + },
  123 + polygonOptions: {
  124 + pmIgnore: true
  125 + }
115 }; 126 };
116 if (maxClusterRadius && maxClusterRadius > 0) { 127 if (maxClusterRadius && maxClusterRadius > 0) {
117 clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius); 128 clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius);
@@ -119,183 +130,165 @@ export default abstract class LeafletMap { @@ -119,183 +130,165 @@ export default abstract class LeafletMap {
119 if (maxZoom && maxZoom >= 0 && maxZoom < 19) { 130 if (maxZoom && maxZoom >= 0 && maxZoom < 19) {
120 clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom); 131 clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom);
121 } 132 }
122 - this.markersCluster = markerClusterGroup(clusteringSettings); 133 + this.markersCluster = new MarkerClusterGroup(clusteringSettings);
123 } 134 }
124 } 135 }
125 136
126 - addMarkerControl() {  
127 - if (this.options.draggableMarker) {  
128 - this.map.on('mousemove', (e: L.LeafletMouseEvent) => {  
129 - this.mousePositionOnMap = e.latlng;  
130 - });  
131 - const dragListener = (e: L.DragEndEvent) => {  
132 - if (e.type === 'dragend' && this.mousePositionOnMap) {  
133 - const icon = L.icon({  
134 - iconRetinaUrl: 'marker-icon-2x.png',  
135 - iconUrl: 'marker-icon.png',  
136 - shadowUrl: 'marker-shadow.png',  
137 - iconSize: [25, 41],  
138 - iconAnchor: [12, 41],  
139 - popupAnchor: [1, -34],  
140 - tooltipAnchor: [16, -28],  
141 - shadowSize: [41, 41]  
142 - });  
143 - const customLatLng = this.convertToCustomFormat(this.mousePositionOnMap);  
144 - this.mousePositionOnMap.lat = customLatLng[this.options.latKeyName];  
145 - this.mousePositionOnMap.lng = customLatLng[this.options.lngKeyName];  
146 -  
147 - const newMarker = L.marker(this.mousePositionOnMap, { icon }).addTo(this.map);  
148 - this.addMarkers.push(newMarker);  
149 - const datasourcesList = document.createElement('div');  
150 - const header = document.createElement('p');  
151 - header.appendChild(document.createTextNode('Select entity:'));  
152 - header.setAttribute('style', 'font-size: 14px; margin: 8px 0');  
153 - datasourcesList.appendChild(header);  
154 - this.datasources.forEach(ds => {  
155 - const dsItem = document.createElement('p');  
156 - dsItem.appendChild(document.createTextNode(ds.entityName));  
157 - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer');  
158 - dsItem.onclick = () => {  
159 - const updatedEnttity = { ...ds, ...customLatLng };  
160 - this.saveMarkerLocation(updatedEnttity).subscribe(() => {  
161 - this.map.removeLayer(newMarker);  
162 - const markerIndex = this.addMarkers.indexOf(newMarker);  
163 - if (markerIndex > -1) {  
164 - this.addMarkers.splice(markerIndex, 1);  
165 - }  
166 - this.deleteMarker(ds.entityName);  
167 - this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options);  
168 - });  
169 - };  
170 - datasourcesList.appendChild(dsItem);  
171 - });  
172 - datasourcesList.appendChild(document.createElement('br'));  
173 - const deleteBtn = document.createElement('a');  
174 - deleteBtn.appendChild(document.createTextNode('Discard changes'));  
175 - deleteBtn.onclick = () => {  
176 - this.map.removeLayer(newMarker);  
177 - const markerIndex = this.addMarkers.indexOf(newMarker);  
178 - if (markerIndex > -1) {  
179 - this.addMarkers.splice(markerIndex, 1);  
180 - }  
181 - };  
182 - datasourcesList.appendChild(deleteBtn);  
183 - const popup = L.popup();  
184 - popup.setContent(datasourcesList);  
185 - newMarker.bindPopup(popup).openPopup();  
186 - }  
187 - this.addMarker.setPosition('topright');  
188 - };  
189 - const addMarker = L.Control.extend({  
190 - onAdd() {  
191 - const img = L.DomUtil.create('img') as any;  
192 - img.src = `assets/add_location.svg`;  
193 - img.style.width = '32px';  
194 - img.style.height = '32px';  
195 - img.title = 'Drag and drop to add marker';  
196 - img.onclick = this.dragMarker;  
197 - img.draggable = true;  
198 - const draggableImg = new L.Draggable(img);  
199 - draggableImg.enable();  
200 - draggableImg.on('dragend', dragListener);  
201 - return img;  
202 - },  
203 - onRemove() {  
204 - },  
205 - dragMarker: this.dragMarker  
206 - } as any);  
207 - const addMarkerControl = (opts) => {  
208 - return new addMarker(opts);  
209 - };  
210 - this.addMarker = addMarkerControl({ position: 'topright' }).addTo(this.map); 137 + private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable<FormattedData> {
  138 + let entities;
  139 + switch (shapes) {
  140 + case 'Polygon':
  141 + case 'Rectangle':
  142 + entities = this.datasources.filter(pData => !this.isValidPolygonPosition(pData));
  143 + break;
  144 + case 'Marker':
  145 + entities = this.datasources.filter(mData => !this.convertPosition(mData));
  146 + break;
  147 + default:
  148 + return of(null);
  149 + }
  150 + if (entities.length === 1) {
  151 + return of(entities[0]);
  152 + }
  153 + const dialog = this.ctx.$injector.get(MatDialog);
  154 + return dialog.open<SelectEntityDialogComponent, SelectEntityDialogData, FormattedData>(SelectEntityDialogComponent,
  155 + {
  156 + disableClose: true,
  157 + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
  158 + data: {
  159 + entities
  160 + }
  161 + }).afterClosed();
  162 + }
  163 +
  164 + private selectEntityWithoutLocation(type: string) {
  165 + this.selectEntityWithoutLocationDialog(type.substring(2)).subscribe((data) => {
  166 + if (data !== null) {
  167 + this.selectedEntity = data;
  168 + this.toggleDrawMode(type);
  169 + } else {
  170 + this.map.pm.Toolbar.toggleButton(type, false);
211 } 171 }
  172 + });
  173 + }
  174 +
  175 + private toggleDrawMode(type: string) {
  176 + this.map.pm.Draw[type].toggle();
212 } 177 }
213 178
214 - addPolygonControl() {  
215 - if (this.options.showPolygon && this.options.editablePolygon) {  
216 - this.map.on('mousemove', (e: L.LeafletMouseEvent) => {  
217 - this.mousePositionOnMap = e.latlng; 179 + addEditControl() {
  180 + // Customize edit marker
  181 + if (this.options.draggableMarker) {
  182 + const actions = [{
  183 + text: L.PM.Utils.getTranslation('actions.cancel'),
  184 + onClick: () => this.toggleDrawMode('tbMarker')
  185 + }];
  186 +
  187 + this.map.pm.Toolbar.copyDrawControl('Marker', {
  188 + name: 'tbMarker',
  189 + afterClick: () => this.selectEntityWithoutLocation('tbMarker'),
  190 + disabled: true,
  191 + actions
  192 + });
  193 + }
  194 +
  195 + // Customize edit polygon
  196 + if (this.editPolygons) {
  197 + const rectangleActions = [
  198 + {
  199 + text: L.PM.Utils.getTranslation('actions.cancel'),
  200 + onClick: () => this.toggleDrawMode('tbRectangle')
  201 + }
  202 + ];
  203 +
  204 + const polygonActions = [
  205 + 'finish' as const,
  206 + 'removeLastVertex' as const,
  207 + {
  208 + text: L.PM.Utils.getTranslation('actions.cancel'),
  209 + onClick: () => this.toggleDrawMode('tbPolygon')
  210 + }
  211 + ];
  212 +
  213 + this.map.pm.Toolbar.copyDrawControl('Rectangle', {
  214 + name: 'tbRectangle',
  215 + afterClick: () => this.selectEntityWithoutLocation('tbRectangle'),
  216 + disabled: true,
  217 + actions: rectangleActions
  218 + });
  219 +
  220 + this.map.pm.Toolbar.copyDrawControl('Polygon', {
  221 + name: 'tbPolygon',
  222 + afterClick: () => this.selectEntityWithoutLocation('tbPolygon'),
  223 + disabled: true,
  224 + actions: polygonActions
  225 + });
  226 + }
  227 +
  228 + const translateService = this.ctx.$injector.get(TranslateService);
  229 + this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en');
  230 + this.map.pm.addControls({
  231 + position: 'topleft',
  232 + drawMarker: false,
  233 + drawCircle: false,
  234 + drawCircleMarker: false,
  235 + drawRectangle: false,
  236 + drawPolyline: false,
  237 + drawPolygon: false,
  238 + editMode: this.editPolygons,
  239 + cutPolygon: this.editPolygons,
  240 + rotateMode: this.editPolygons
218 }); 241 });
219 242
220 - const dragListener = (e: L.DragEndEvent) => {  
221 - if (e.type === 'dragend') {  
222 - const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01;  
223 -  
224 - const convert = this.convertToCustomFormat(this.mousePositionOnMap, polygonOffset);  
225 - this.mousePositionOnMap.lat = convert[this.options.latKeyName];  
226 - this.mousePositionOnMap.lng = convert[this.options.lngKeyName];  
227 -  
228 - const latlng1 = this.mousePositionOnMap;  
229 - const latlng2 = L.latLng(this.mousePositionOnMap.lat, this.mousePositionOnMap.lng + polygonOffset);  
230 - const latlng3 = L.latLng(this.mousePositionOnMap.lat - polygonOffset, this.mousePositionOnMap.lng);  
231 - const polygonPoints = [latlng1, latlng2, latlng3];  
232 -  
233 - const newPolygon = L.polygon(polygonPoints).addTo(this.map);  
234 - this.addPolygons.push(newPolygon);  
235 - const datasourcesList = document.createElement('div');  
236 - const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(polygonPoints)};  
237 - const header = document.createElement('p');  
238 - header.appendChild(document.createTextNode('Select entity:'));  
239 - header.setAttribute('style', 'font-size: 14px; margin: 8px 0');  
240 - datasourcesList.appendChild(header);  
241 - this.datasources.forEach(ds => {  
242 - const dsItem = document.createElement('p');  
243 - dsItem.appendChild(document.createTextNode(ds.entityName));  
244 - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer');  
245 - dsItem.onclick = () => {  
246 - const updatedEnttity = { ...ds, ...customLatLng };  
247 - this.savePolygonLocation(updatedEnttity).subscribe(() => {  
248 - this.map.removeLayer(newPolygon);  
249 - const polygonIndex = this.addPolygons.indexOf(newPolygon);  
250 - if (polygonIndex > -1) {  
251 - this.addPolygons.splice(polygonIndex, 1);  
252 - }  
253 - this.deletePolygon(ds.entityName);  
254 - });  
255 - };  
256 - datasourcesList.appendChild(dsItem); 243 + this.map.on('pm:create', (e) => {
  244 + if (e.shape === 'tbMarker') {
  245 + // @ts-ignore
  246 + this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {
  247 + });
  248 + } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') {
  249 + // @ts-ignore
  250 + this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => {
257 }); 251 });
258 - datasourcesList.appendChild(document.createElement('br'));  
259 - const deleteBtn = document.createElement('a');  
260 - deleteBtn.appendChild(document.createTextNode('Discard changes'));  
261 - deleteBtn.onclick = () => {  
262 - this.map.removeLayer(newPolygon);  
263 - const polygonIndex = this.addPolygons.indexOf(newPolygon);  
264 - if (polygonIndex > -1) {  
265 - this.addPolygons.splice(polygonIndex, 1);  
266 - }  
267 - };  
268 - datasourcesList.appendChild(deleteBtn);  
269 - const popup = L.popup();  
270 - popup.setContent(datasourcesList);  
271 - newPolygon.bindPopup(popup).openPopup();  
272 } 252 }
273 - this.addPolygon.setPosition('topright');  
274 - };  
275 - const addPolygon = L.Control.extend({  
276 - onAdd() {  
277 - const img = L.DomUtil.create('img') as any;  
278 - img.src = `assets/add_polygon.svg`;  
279 - img.style.width = '32px';  
280 - img.style.height = '32px';  
281 - img.title = 'Drag and drop to add Polygon';  
282 - img.onclick = this.dragPolygonVertex;  
283 - img.draggable = true;  
284 - const draggableImg = new L.Draggable(img);  
285 - draggableImg.enable();  
286 - draggableImg.on('dragend', dragListener);  
287 - return img;  
288 - },  
289 - onRemove() {  
290 - },  
291 - dragPolygonVertex: this.dragPolygonVertex  
292 - } as any);  
293 - const addPolygonControl = (opts) => {  
294 - return new addPolygon(opts);  
295 - };  
296 - this.addPolygon = addPolygonControl({ position: 'topright' }).addTo(this.map); 253 + // @ts-ignore
  254 + e.layer._pmTempLayer = true;
  255 + e.layer.remove();
  256 + });
  257 +
  258 + this.map.on('pm:cut', (e) => {
  259 + // @ts-ignore
  260 + e.originalLayer.setLatLngs(e.layer.getLatLngs());
  261 + e.originalLayer.addTo(this.map);
  262 + // @ts-ignore
  263 + e.originalLayer._pmTempLayer = false;
  264 + const iterator = this.polygons.values();
  265 + let result = iterator.next();
  266 + while (!result.done && e.originalLayer !== result.value.leafletPoly) {
  267 + result = iterator.next();
  268 + }
  269 + // @ts-ignore
  270 + e.layer._pmTempLayer = true;
  271 + e.layer.remove();
  272 + });
  273 +
  274 + this.map.on('pm:remove', (e) => {
  275 + if (e.shape === 'Marker') {
  276 + const iterator = this.markers.values();
  277 + let result = iterator.next();
  278 + while (!result.done && e.layer !== result.value.leafletMarker) {
  279 + result = iterator.next();
  280 + }
  281 + this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {});
  282 + } else if (e.shape === 'Polygon') {
  283 + const iterator = this.polygons.values();
  284 + let result = iterator.next();
  285 + while (!result.done && e.layer !== result.value.leafletPoly) {
  286 + result = iterator.next();
  287 + }
  288 + this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {});
  289 + }
  290 + });
297 } 291 }
298 - }  
299 292
300 public setLoading(loading: boolean) { 293 public setLoading(loading: boolean) {
301 if (this.loading !== loading) { 294 if (this.loading !== loading) {
@@ -337,11 +330,10 @@ export default abstract class LeafletMap { @@ -337,11 +330,10 @@ export default abstract class LeafletMap {
337 if (this.options.disableScrollZooming) { 330 if (this.options.disableScrollZooming) {
338 this.map.scrollWheelZoom.disable(); 331 this.map.scrollWheelZoom.disable();
339 } 332 }
340 - if (this.options.draggableMarker) {  
341 - this.addMarkerControl();  
342 - }  
343 - if (this.options.editablePolygon) {  
344 - this.addPolygonControl(); 333 + if (this.options.draggableMarker || this.editPolygons) {
  334 + this.addEditControl();
  335 + } else {
  336 + this.map.pm.disableDraw();
345 } 337 }
346 if (this.options.useClusterMarkers) { 338 if (this.options.useClusterMarkers) {
347 this.map.addLayer(this.markersCluster); 339 this.map.addLayer(this.markersCluster);
@@ -352,12 +344,53 @@ export default abstract class LeafletMap { @@ -352,12 +344,53 @@ export default abstract class LeafletMap {
352 } 344 }
353 } 345 }
354 346
355 - public saveMarkerLocation(datasource: FormattedData, lat?: number, lng?: number): Observable<any> {  
356 - return of(null);  
357 - } 347 + private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable<any> {
  348 + const attributeService = this.ctx.$injector.get(AttributeService);
  349 + const attributes = [];
  350 + const timeseries = [];
  351 +
  352 + const entityId: EntityId = {
  353 + entityType: e.$datasource.entityType,
  354 + id: e.$datasource.entityId
  355 + };
358 356
359 - public savePolygonLocation(datasource: FormattedData, coordinates?: Array<[number, number]>): Observable<any> {  
360 - return of(null); 357 + for (const dataKeyName of Object.keys(values)) {
  358 + for (const key of e.$datasource.dataKeys) {
  359 + if (dataKeyName === key.name) {
  360 + const value = {
  361 + key: key.name,
  362 + value: values[dataKeyName]
  363 + };
  364 + if (key.type === DataKeyType.attribute) {
  365 + attributes.push(value);
  366 + } else if (key.type === DataKeyType.timeseries) {
  367 + timeseries.push(value);
  368 + }
  369 + break;
  370 + }
  371 + }
  372 + }
  373 +
  374 + const observables: Observable<any>[] = [];
  375 + if (timeseries.length) {
  376 + observables.push(attributeService.saveEntityTimeseries(
  377 + entityId,
  378 + LatestTelemetry.LATEST_TELEMETRY,
  379 + timeseries
  380 + ));
  381 + }
  382 + if (attributes.length) {
  383 + observables.push(attributeService.saveEntityAttributes(
  384 + entityId,
  385 + AttributeScope.SERVER_SCOPE,
  386 + attributes
  387 + ));
  388 + }
  389 + if (observables.length) {
  390 + return forkJoin(observables);
  391 + } else {
  392 + return of(null);
  393 + }
361 } 394 }
362 395
363 createLatLng(lat: number, lng: number): L.LatLng { 396 createLatLng(lat: number, lng: number): L.LatLng {
@@ -441,7 +474,7 @@ export default abstract class LeafletMap { @@ -441,7 +474,7 @@ export default abstract class LeafletMap {
441 } 474 }
442 475
443 convertToCustomFormat(position: L.LatLng, offset = 0): object { 476 convertToCustomFormat(position: L.LatLng, offset = 0): object {
444 - position = checkLngLat(position, this.southWest, this.northEast, offset); 477 + position = position ? checkLngLat(position, this.southWest, this.northEast, offset) : {lat: null, lng: null} as L.LatLng;
445 478
446 return { 479 return {
447 [this.options.latKeyName]: position.lat, 480 [this.options.latKeyName]: position.lat,
@@ -455,17 +488,18 @@ export default abstract class LeafletMap { @@ -455,17 +488,18 @@ export default abstract class LeafletMap {
455 if (point.length) { 488 if (point.length) {
456 return this.convertToPolygonFormat(point); 489 return this.convertToPolygonFormat(point);
457 } else { 490 } else {
458 - return [point.lat, point.lng]; 491 + const convertPoint = checkLngLat(point, this.southWest, this.northEast);
  492 + return [convertPoint.lat, convertPoint.lng];
459 } 493 }
460 }); 494 });
461 - } else {  
462 - return [];  
463 } 495 }
  496 + return [];
464 } 497 }
465 498
466 - convertPolygonToCustomFormat(expression: any[][]): object { 499 + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
  500 + const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
467 return { 501 return {
468 - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) 502 + [this.options.polygonKeyName]: coordinate
469 }; 503 };
470 } 504 }
471 505
@@ -484,7 +518,15 @@ export default abstract class LeafletMap { @@ -484,7 +518,15 @@ export default abstract class LeafletMap {
484 } 518 }
485 this.updateMarkers(formattedData, false); 519 this.updateMarkers(formattedData, false);
486 this.updateBoundsInternal(); 520 this.updateBoundsInternal();
487 - if (this.options.draggableMarker || this.options.editablePolygon) { 521 + if (this.options.draggableMarker) {
  522 + const foundEntityWithoutLocation = formattedData.some(mData => !this.convertPosition(mData));
  523 + this.map.pm.Toolbar.setButtonDisabled('tbMarker', !foundEntityWithoutLocation);
  524 + this.datasources = formattedData;
  525 + }
  526 + if (this.editPolygons) {
  527 + const foundEntityWithoutPolygon = formattedData.some(pData => !this.isValidPolygonPosition(pData));
  528 + this.map.pm.Toolbar.setButtonDisabled('tbPolygon', !foundEntityWithoutPolygon);
  529 + this.map.pm.Toolbar.setButtonDisabled('tbRectangle', !foundEntityWithoutPolygon);
488 this.datasources = formattedData; 530 this.datasources = formattedData;
489 } 531 }
490 } else { 532 } else {
@@ -577,10 +619,10 @@ export default abstract class LeafletMap { @@ -577,10 +619,10 @@ export default abstract class LeafletMap {
577 } 619 }
578 620
579 dragMarker = (e, data = {} as FormattedData) => { 621 dragMarker = (e, data = {} as FormattedData) => {
580 - if (e.type !== 'dragend') { 622 + if (e === undefined) {
581 return; 623 return;
582 } 624 }
583 - this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }).subscribe(); 625 + this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe();
584 } 626 }
585 627
586 private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, 628 private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings,
@@ -728,11 +770,15 @@ export default abstract class LeafletMap { @@ -728,11 +770,15 @@ export default abstract class LeafletMap {
728 770
729 // Polygon 771 // Polygon
730 772
  773 + isValidPolygonPosition(data: FormattedData): boolean {
  774 + return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]);
  775 + }
  776 +
731 updatePolygons(polyData: FormattedData[], updateBounds = true) { 777 updatePolygons(polyData: FormattedData[], updateBounds = true) {
732 const keys: string[] = []; 778 const keys: string[] = [];
733 this.polygonsData = deepClone(polyData); 779 this.polygonsData = deepClone(polyData);
734 polyData.forEach((data: FormattedData) => { 780 polyData.forEach((data: FormattedData) => {
735 - if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) { 781 + if (this.isValidPolygonPosition(data)) {
736 if (isString((data[this.options.polygonKeyName]))) { 782 if (isString((data[this.options.polygonKeyName]))) {
737 data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]); 783 data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]);
738 } 784 }
@@ -758,15 +804,14 @@ export default abstract class LeafletMap { @@ -758,15 +804,14 @@ export default abstract class LeafletMap {
758 } 804 }
759 805
760 dragPolygonVertex = (e?, data = {} as FormattedData) => { 806 dragPolygonVertex = (e?, data = {} as FormattedData) => {
761 - if (e === undefined || (e.type !== 'editable:vertex:dragend' && e.type !== 'editable:vertex:deleted')) { 807 + if (e === undefined) {
762 return; 808 return;
763 } 809 }
764 - if (this.options.provider !== MapProviders.image) {  
765 - for (const key of Object.keys(e.layer._latlngs[0])) {  
766 - e.layer._latlngs[0][key] = checkLngLat(e.layer._latlngs[0][key], this.southWest, this.northEast);  
767 - } 810 + let coordinates = e.layer.getLatLngs();
  811 + if (coordinates.length === 1) {
  812 + coordinates = coordinates[0];
768 } 813 }
769 - this.savePolygonLocation({ ...data, ...this.convertPolygonToCustomFormat(e.layer._latlngs) }).subscribe(); 814 + this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {});
770 } 815 }
771 816
772 createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) { 817 createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {
@@ -57,6 +57,7 @@ export type MapSettings = { @@ -57,6 +57,7 @@ export type MapSettings = {
57 showCoverageOnHover: boolean, 57 showCoverageOnHover: boolean,
58 animate: boolean, 58 animate: boolean,
59 maxClusterRadius: number, 59 maxClusterRadius: number,
  60 + spiderfyOnMaxZoom: boolean,
60 chunkedLoading: boolean, 61 chunkedLoading: boolean,
61 removeOutsideVisibleBounds: boolean, 62 removeOutsideVisibleBounds: boolean,
62 useCustomProvider: boolean, 63 useCustomProvider: boolean,
@@ -14,41 +14,23 @@ @@ -14,41 +14,23 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import {  
18 - defaultSettings,  
19 - FormattedData,  
20 - hereProviders,  
21 - MapProviders,  
22 - UnitedMapSettings  
23 -} from './map-models'; 17 +import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models';
24 import LeafletMap from './leaflet-map'; 18 import LeafletMap from './leaflet-map';
25 import { 19 import {
26 commonMapSettingsSchema, 20 commonMapSettingsSchema,
27 mapPolygonSchema, 21 mapPolygonSchema,
28 - mapProviderSchema,  
29 markerClusteringSettingsSchema, 22 markerClusteringSettingsSchema,
30 markerClusteringSettingsSchemaLeaflet, 23 markerClusteringSettingsSchemaLeaflet,
31 routeMapSettingsSchema 24 routeMapSettingsSchema
32 } from './schemes'; 25 } from './schemes';
33 import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; 26 import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
34 -import {  
35 - addCondition,  
36 - addGroupInfo,  
37 - addToSchema,  
38 - initSchema,  
39 - mergeSchemes  
40 -} from '@core/schema-utils'; 27 +import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
41 import { WidgetContext } from '@app/modules/home/models/widget-component.models'; 28 import { WidgetContext } from '@app/modules/home/models/widget-component.models';
42 import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils'; 29 import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils';
43 import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; 30 import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models';
44 -import { EntityId } from '@shared/models/id/entity-id';  
45 -import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';  
46 -import { AttributeService } from '@core/http/attribute.service';  
47 import { TranslateService } from '@ngx-translate/core'; 31 import { TranslateService } from '@ngx-translate/core';
48 import { UtilsService } from '@core/services/utils.service'; 32 import { UtilsService } from '@core/services/utils.service';
49 import { EntityDataPageLink } from '@shared/models/query/query.models'; 33 import { EntityDataPageLink } from '@shared/models/query/query.models';
50 -import { isDefined } from '@core/utils';  
51 -import { forkJoin, Observable, of } from 'rxjs';  
52 import { providerClass } from '@home/components/widget/lib/maps/providers'; 34 import { providerClass } from '@home/components/widget/lib/maps/providers';
53 35
54 // @dynamic 36 // @dynamic
@@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface { @@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface {
81 } 63 }
82 parseWithTranslation.setTranslate(this.translate); 64 parseWithTranslation.setTranslate(this.translate);
83 this.map = new MapClass(this.ctx, $element, this.settings); 65 this.map = new MapClass(this.ctx, $element, this.settings);
84 - this.map.saveMarkerLocation = this.setMarkerLocation;  
85 - this.map.savePolygonLocation = this.savePolygonLocation;  
86 this.pageLink = { 66 this.pageLink = {
87 page: 0, 67 page: 0,
88 pageSize: this.settings.mapPageSize, 68 pageSize: this.settings.mapPageSize,
@@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface { @@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface {
178 }, entityName, null, entityLabel); 158 }, entityName, null, entityLabel);
179 } 159 }
180 160
181 - setMarkerLocation = (e: FormattedData, lat?: number, lng?: number) => {  
182 - const attributeService = this.ctx.$injector.get(AttributeService);  
183 -  
184 - const entityId: EntityId = {  
185 - entityType: e.$datasource.entityType,  
186 - id: e.$datasource.entityId  
187 - };  
188 - const attributes = [];  
189 - const timeseries = [];  
190 -  
191 - const latProperties = [this.settings.latKeyName, this.settings.xPosKeyName];  
192 - const lngProperties = [this.settings.lngKeyName, this.settings.yPosKeyName];  
193 - e.$datasource.dataKeys.forEach(key => {  
194 - let value;  
195 - if (latProperties.includes(key.name)) {  
196 - value = {  
197 - key: key.name,  
198 - value: isDefined(lat) ? lat : e[key.name]  
199 - };  
200 - } else if (lngProperties.includes(key.name)) {  
201 - value = {  
202 - key: key.name,  
203 - value: isDefined(lng) ? lng : e[key.name]  
204 - };  
205 - }  
206 - if (value) {  
207 - if (key.type === DataKeyType.attribute) {  
208 - attributes.push(value);  
209 - }  
210 - if (key.type === DataKeyType.timeseries) {  
211 - timeseries.push(value);  
212 - }  
213 - }  
214 - });  
215 - const observables: Observable<any>[] = [];  
216 - if (timeseries.length) {  
217 - observables.push(attributeService.saveEntityTimeseries(  
218 - entityId,  
219 - LatestTelemetry.LATEST_TELEMETRY,  
220 - timeseries  
221 - ));  
222 - }  
223 - if (attributes.length) {  
224 - observables.push(attributeService.saveEntityAttributes(  
225 - entityId,  
226 - AttributeScope.SERVER_SCOPE,  
227 - attributes  
228 - ));  
229 - }  
230 - if (observables.length) {  
231 - return forkJoin(observables);  
232 - } else {  
233 - return of(null);  
234 - }  
235 - }  
236 -  
237 - savePolygonLocation = (e: FormattedData, coordinates?: Array<any>) => {  
238 - const attributeService = this.ctx.$injector.get(AttributeService);  
239 -  
240 - const entityId: EntityId = {  
241 - entityType: e.$datasource.entityType,  
242 - id: e.$datasource.entityId  
243 - };  
244 - const attributes = [];  
245 - const timeseries = [];  
246 -  
247 - const coordinatesProperties = this.settings.polygonKeyName;  
248 - e.$datasource.dataKeys.forEach(key => {  
249 - let value;  
250 - if (coordinatesProperties === key.name) {  
251 - value = {  
252 - key: key.name,  
253 - value: isDefined(coordinates) ? coordinates : e[key.name]  
254 - };  
255 - }  
256 - if (value) {  
257 - if (key.type === DataKeyType.attribute) {  
258 - attributes.push(value);  
259 - }  
260 - if (key.type === DataKeyType.timeseries) {  
261 - timeseries.push(value);  
262 - }  
263 - }  
264 - });  
265 - const observables: Observable<any>[] = [];  
266 - if (timeseries.length) {  
267 - observables.push(attributeService.saveEntityTimeseries(  
268 - entityId,  
269 - LatestTelemetry.LATEST_TELEMETRY,  
270 - timeseries  
271 - ));  
272 - }  
273 - if (attributes.length) {  
274 - observables.push(attributeService.saveEntityAttributes(  
275 - entityId,  
276 - AttributeScope.SERVER_SCOPE,  
277 - attributes  
278 - ));  
279 - }  
280 - if (observables.length) {  
281 - return forkJoin(observables);  
282 - } else {  
283 - return of(null);  
284 - }  
285 - }  
286 -  
287 initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { 161 initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings {
288 const functionParams = ['data', 'dsData', 'dsIndex']; 162 const functionParams = ['data', 'dsData', 'dsIndex'];
289 this.provider = settings.provider || this.mapProvider; 163 this.provider = settings.provider || this.mapProvider;
@@ -29,6 +29,10 @@ @@ -29,6 +29,10 @@
29 box-shadow: none; 29 box-shadow: none;
30 } 30 }
31 31
32 -.leaflet-container{ 32 +.leaflet-container {
33 background-color: white; 33 background-color: white;
34 } 34 }
  35 +
  36 +.leaflet-buttons-control-button.pm-disabled {
  37 + pointer-events: none;
  38 +}
@@ -42,9 +42,7 @@ export class Marker { @@ -42,9 +42,7 @@ export class Marker {
42 constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings, 42 constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings,
43 data?: FormattedData, dataSources?, onDragendListener?) { 43 data?: FormattedData, dataSources?, onDragendListener?) {
44 this.setDataSources(data, dataSources); 44 this.setDataSources(data, dataSources);
45 - this.leafletMarker = L.marker(location, {  
46 - draggable: settings.draggableMarker  
47 - }); 45 + this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker});
48 46
49 this.markerOffset = [ 47 this.markerOffset = [
50 isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5, 48 isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5,
@@ -72,8 +70,8 @@ export class Marker { @@ -72,8 +70,8 @@ export class Marker {
72 }); 70 });
73 } 71 }
74 72
75 - if (onDragendListener) {  
76 - this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data)); 73 + if (settings.draggableMarker && onDragendListener) {
  74 + this.leafletMarker.on('pm:dragend', (e) => onDragendListener(e, this.data));
77 } 75 }
78 } 76 }
79 77
@@ -199,19 +197,24 @@ export class Marker { @@ -199,19 +197,24 @@ export class Marker {
199 197
200 createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } { 198 createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } {
201 return { 199 return {
202 - size: [21, 34],  
203 - icon: L.icon({  
204 - iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color.toHex(),  
205 - iconSize: [21, 34],  
206 - iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]],  
207 - popupAnchor: [0, -34],  
208 - shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow',  
209 - shadowSize: [40, 37],  
210 - shadowAnchor: [12, 35] 200 + size: [21, 34],
  201 + icon: L.icon({
  202 + iconUrl: this.createColorIconURI(color),
  203 + iconSize: [21, 34],
  204 + iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]],
  205 + popupAnchor: [0, -34],
  206 + shadowUrl: 'assets/shadow.png',
  207 + shadowSize: [40, 37],
  208 + shadowAnchor: [12, 35]
211 }) 209 })
212 }; 210 };
213 } 211 }
214 212
  213 + createColorIconURI(color: tinycolor.Instance): string {
  214 + const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-191.35 -351.18 1083.58 1730.46"><path fill-rule="evenodd" clip-rule="evenodd" fill="#${color.toHex()}" stroke="#000" stroke-width="37" stroke-miterlimit="10" d="M351.833 1360.78c-38.766-190.3-107.116-348.665-189.903-495.44C100.523 756.469 29.386 655.978-36.434 550.404c-21.972-35.244-40.934-72.477-62.047-109.054-42.216-73.137-76.444-157.935-74.269-267.932 2.125-107.473 33.208-193.685 78.03-264.173C-21-206.69 102.481-301.745 268.164-326.724c135.466-20.425 262.475 14.082 352.543 66.747 73.6 43.038 130.596 100.528 173.92 168.28 45.22 70.716 76.36 154.26 78.971 263.233 1.337 55.83-7.805 107.532-20.684 150.417-13.034 43.41-33.996 79.695-52.646 118.455-36.406 75.659-82.049 144.981-127.855 214.345-136.437 206.606-264.496 417.31-320.58 706.028z"/><circle fill-rule="evenodd" clip-rule="evenodd" cx="352.891" cy="225.779" r="183.332"/></svg>`;
  215 + return 'data:image/svg+xml;base64,' + btoa(svg);
  216 + }
  217 +
215 removeMarker() { 218 removeMarker() {
216 /* this.map$.subscribe(map => 219 /* this.map$.subscribe(map =>
217 this.leafletMarker.addTo(map))*/ 220 this.leafletMarker.addTo(map))*/
@@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
17 import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; 17 import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
18 import { createTooltip } from './maps-utils'; 18 import { createTooltip } from './maps-utils';
19 import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; 19 import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils';
20 -import 'leaflet-editable/src/Leaflet.Editable';  
21 import { FormattedData, PolygonSettings } from './map-models'; 20 import { FormattedData, PolygonSettings } from './map-models';
22 21
23 export class Polygon { 22 export class Polygon {
@@ -37,14 +36,12 @@ export class Polygon { @@ -37,14 +36,12 @@ export class Polygon {
37 color: settings.polygonStrokeColor, 36 color: settings.polygonStrokeColor,
38 weight: settings.polygonStrokeWeight, 37 weight: settings.polygonStrokeWeight,
39 fillOpacity: settings.polygonOpacity, 38 fillOpacity: settings.polygonOpacity,
40 - opacity: settings.polygonStrokeOpacity 39 + opacity: settings.polygonStrokeOpacity,
  40 + pmIgnore: !settings.editablePolygon
41 }).addTo(this.map); 41 }).addTo(this.map);
42 - if (settings.editablePolygon) {  
43 - this.leafletPoly.enableEdit(this.map);  
44 - if (onDragendListener) {  
45 - this.leafletPoly.on('editable:vertex:dragend', e => onDragendListener(e, this.data));  
46 - this.leafletPoly.on('editable:vertex:deleted', e => onDragendListener(e, this.data));  
47 - } 42 +
  43 + if (settings.editablePolygon && onDragendListener) {
  44 + this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data));
48 } 45 }
49 46
50 47
@@ -73,13 +70,7 @@ export class Polygon { @@ -73,13 +70,7 @@ export class Polygon {
73 updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { 70 updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
74 this.data = data; 71 this.data = data;
75 this.dataSources = dataSources; 72 this.dataSources = dataSources;
76 - if (settings.editablePolygon) {  
77 - this.leafletPoly.disableEdit();  
78 - }  
79 this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); 73 this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]);
80 - if (settings.editablePolygon) {  
81 - this.leafletPoly.enableEdit(this.map);  
82 - }  
83 if (settings.showPolygonTooltip) { 74 if (settings.showPolygonTooltip) {
84 this.updateTooltip(this.data); 75 this.updateTooltip(this.data);
85 } 76 }
@@ -14,7 +14,8 @@ @@ -14,7 +14,8 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import L, { PolylineDecoratorOptions } from 'leaflet'; 17 +// @ts-ignore
  18 +import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet';
18 import 'leaflet-polylinedecorator'; 19 import 'leaflet-polylinedecorator';
19 20
20 import { FormattedData, PolylineSettings } from './map-models'; 21 import { FormattedData, PolylineSettings } from './map-models';
@@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common @@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common
23 export class Polyline { 24 export class Polyline {
24 25
25 leafletPoly: L.Polyline; 26 leafletPoly: L.Polyline;
26 - polylineDecorator: L.PolylineDecorator; 27 + polylineDecorator: PolylineDecorator;
27 dataSources: FormattedData[]; 28 dataSources: FormattedData[];
28 data: FormattedData; 29 data: FormattedData;
29 30
@@ -36,7 +37,7 @@ export class Polyline { @@ -36,7 +37,7 @@ export class Polyline {
36 ).addTo(this.map); 37 ).addTo(this.map);
37 38
38 if (settings.usePolylineDecorator) { 39 if (settings.usePolylineDecorator) {
39 - this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); 40 + this.polylineDecorator = new PolylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map);
40 } 41 }
41 } 42 }
42 43
@@ -47,7 +48,7 @@ export class Polyline { @@ -47,7 +48,7 @@ export class Polyline {
47 offset: settings.decoratorOffset, 48 offset: settings.decoratorOffset,
48 endOffset: settings.endDecoratorOffset, 49 endOffset: settings.endDecoratorOffset,
49 repeat: settings.decoratorRepeat, 50 repeat: settings.decoratorRepeat,
50 - symbol: L.Symbol[settings.decoratorSymbol]({ 51 + symbol: Symbol[settings.decoratorSymbol]({
51 pixelSize: settings.decoratorSymbolSize, 52 pixelSize: settings.decoratorSymbolSize,
52 polygon: false, 53 polygon: false,
53 pathOptions: { 54 pathOptions: {
@@ -78,7 +79,8 @@ export class Polyline { @@ -78,7 +79,8 @@ export class Polyline {
78 opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction, 79 opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction,
79 [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity), 80 [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity),
80 weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction, 81 weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction,
81 - [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight) 82 + [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight),
  83 + pmIgnore: true
82 }; 84 };
83 } 85 }
84 86
@@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap { @@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap {
38 this.loadGoogle(() => { 38 this.loadGoogle(() => {
39 const map = L.map($container, { 39 const map = L.map($container, {
40 attributionControl: false, 40 attributionControl: false,
41 - editable: !!options.editablePolygon,  
42 tap: L.Browser.safari && L.Browser.mobile 41 tap: L.Browser.safari && L.Browser.mobile
43 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); 42 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
44 (L.gridLayer as any).googleMutant({ 43 (L.gridLayer as any).googleMutant({
@@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap { @@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap {
23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { 23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
24 super(ctx, $container, options); 24 super(ctx, $container, options);
25 const map = L.map($container, { 25 const map = L.map($container, {
26 - editable: !!options.editablePolygon,  
27 tap: L.Browser.safari && L.Browser.mobile 26 tap: L.Browser.safari && L.Browser.mobile
28 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); 27 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
29 const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); 28 const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials);
@@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators'; @@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators';
22 import { 22 import {
23 aspectCache, 23 aspectCache,
24 calculateNewPointCoordinate, 24 calculateNewPointCoordinate,
25 - checkLngLat,  
26 parseFunction 25 parseFunction
27 } from '@home/components/widget/lib/maps/common-maps-utils'; 26 } from '@home/components/widget/lib/maps/common-maps-utils';
28 import { WidgetContext } from '@home/models/widget-component.models'; 27 import { WidgetContext } from '@home/models/widget-component.models';
@@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap { @@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap {
221 zoom: 1, 220 zoom: 1,
222 crs: L.CRS.Simple, 221 crs: L.CRS.Simple,
223 attributionControl: false, 222 attributionControl: false,
224 - editable: !!this.options.editablePolygon,  
225 tap: L.Browser.safari && L.Browser.mobile 223 tap: L.Browser.safari && L.Browser.mobile
226 }); 224 });
227 this.updateBounds(updateImage); 225 this.updateBounds(updateImage);
@@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap { @@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap {
263 return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); 261 return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
264 } 262 }
265 263
266 - convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): object { 264 + convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} {
  265 + if (!position) {
  266 + return {
  267 + [this.options.xPosKeyName]: null,
  268 + [this.options.yPosKeyName]: null
  269 + };
  270 + }
267 const point = this.latLngToPoint(position); 271 const point = this.latLngToPoint(position);
268 const customX = calculateNewPointCoordinate(point.x, width); 272 const customX = calculateNewPointCoordinate(point.x, width);
269 const customY = calculateNewPointCoordinate(point.y, height); 273 const customY = calculateNewPointCoordinate(point.y, height);
@@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap { @@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap {
279 point.y = height; 283 point.y = height;
280 } 284 }
281 285
282 - const customLatLng = checkLngLat(this.pointToLatLng(point.x, point.y), this.southWest, this.northEast, offset);  
283 -  
284 return { 286 return {
285 [this.options.xPosKeyName]: customX, 287 [this.options.xPosKeyName]: customX,
286 - [this.options.yPosKeyName]: customY,  
287 - [this.options.latKeyName]: customLatLng.lat,  
288 - [this.options.lngKeyName]: customLatLng.lng 288 + [this.options.yPosKeyName]: customY
289 }; 289 };
290 } 290 }
291 291
@@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap { @@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap {
304 } 304 }
305 } 305 }
306 306
307 - convertPolygonToCustomFormat(expression: any[][]): object { 307 + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
  308 + const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
308 return { 309 return {
309 - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) 310 + [this.options.polygonKeyName]: coordinate
310 }; 311 };
311 } 312 }
312 } 313 }
@@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap { @@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap {
23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { 23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
24 super(ctx, $container, options); 24 super(ctx, $container, options);
25 const map = L.map($container, { 25 const map = L.map($container, {
26 - editable: !!options.editablePolygon,  
27 tap: L.Browser.safari && L.Browser.mobile 26 tap: L.Browser.safari && L.Browser.mobile
28 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); 27 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
29 let tileLayer; 28 let tileLayer;
@@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap { @@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap {
25 super(ctx, $container, options); 25 super(ctx, $container, options);
26 const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; 26 const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
27 const map = L.map($container, { 27 const map = L.map($container, {
28 - editable: !!options.editablePolygon,  
29 tap: L.Browser.safari && L.Browser.mobile 28 tap: L.Browser.safari && L.Browser.mobile
30 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); 29 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
31 const txLayer = L.tileLayer(txUrl, { 30 const txLayer = L.tileLayer(txUrl, {
@@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet = @@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet =
728 type: 'number', 728 type: 'number',
729 default: 80 729 default: 80
730 }, 730 },
  731 + spiderfyOnMaxZoom: {
  732 + title: 'Spiderfy at the max zoom level (to see all cluster markers)',
  733 + type: 'boolean',
  734 + default: false
  735 + },
731 chunkedLoading: { 736 chunkedLoading: {
732 title: 'Use chunks for adding markers so that the page does not freeze', 737 title: 'Use chunks for adding markers so that the page does not freeze',
733 type: 'boolean', 738 type: 'boolean',
@@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet = @@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet =
747 'showCoverageOnHover', 752 'showCoverageOnHover',
748 'animate', 753 'animate',
749 'maxClusterRadius', 754 'maxClusterRadius',
  755 + 'spiderfyOnMaxZoom',
750 'chunkedLoading', 756 'chunkedLoading',
751 'removeOutsideVisibleBounds' 757 'removeOutsideVisibleBounds'
752 ] 758 ]
@@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy @@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
100 addGroupInfo(schema, 'Path Settings'); 100 addGroupInfo(schema, 'Path Settings');
101 addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints'])); 101 addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
102 addGroupInfo(schema, 'Path Points Settings'); 102 addGroupInfo(schema, 'Path Points Settings');
103 - addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon'])); 103 + const mapPolygonSchemaWithoutEdit = mapPolygonSchema;
  104 + delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon;
  105 + mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1);
  106 + addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon']));
104 addGroupInfo(schema, 'Polygon Settings'); 107 addGroupInfo(schema, 'Polygon Settings');
105 return schema; 108 return schema;
106 } 109 }
@@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy @@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
115 rotationAngle: 0 118 rotationAngle: 0
116 }; 119 };
117 this.settings = { ...settings, ...this.ctx.settings }; 120 this.settings = { ...settings, ...this.ctx.settings };
  121 + this.settings.editablePolygon = false;
118 this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; 122 this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
119 this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); 123 this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
120 this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); 124 this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
@@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges- @@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges-
41 import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; 41 import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component';
42 import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; 42 import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component';
43 import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; 43 import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component';
  44 +import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component';
44 45
45 @NgModule({ 46 @NgModule({
46 declarations: 47 declarations:
@@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi @@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi
62 NavigationCardsWidgetComponent, 63 NavigationCardsWidgetComponent,
63 NavigationCardWidgetComponent, 64 NavigationCardWidgetComponent,
64 QrCodeWidgetComponent, 65 QrCodeWidgetComponent,
65 - MarkdownWidgetComponent 66 + MarkdownWidgetComponent,
  67 + SelectEntityDialogComponent
66 ], 68 ],
67 imports: [ 69 imports: [
68 CommonModule, 70 CommonModule,
1 -<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 4c-7.72 0-14 6.28-14 14 0 10.5 14 26 14 26s14-15.5 14-26c0-7.72-6.28-14-14-14zm8 16h-6v6h-4v-6h-6v-4h6v-6h4v6h6v4z"/></svg>  
1 -<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">  
2 - <polygon points="2,46 46,46 24,2" style="fill:transparent;stroke:black;stroke-width:2"/>  
3 -</svg>  
@@ -3238,7 +3238,40 @@ @@ -3238,7 +3238,40 @@
3238 "update-timeseries": "Update timeseries", 3238 "update-timeseries": "Update timeseries",
3239 "value": "Value" 3239 "value": "Value"
3240 }, 3240 },
3241 - "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type" 3241 + "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type",
  3242 + "maps": {
  3243 + "select-entity": "Select entity",
  3244 + "select-entity-hint": "Hint: after selection click at the map to set position",
  3245 + "tooltips": {
  3246 + "placeMarker": "Click to place marker",
  3247 + "firstVertex": "Click to place first point",
  3248 + "continueLine": "Click to continue drawing",
  3249 + "finishLine": "Click any existing marker to finish",
  3250 + "finishPoly": "Click first marker to finish and save",
  3251 + "finishRect": "Click to finish and save",
  3252 + "startCircle": "Click to place circle center",
  3253 + "finishCircle": "Click to finish circle",
  3254 + "placeCircleMarker": "Click to place circle marker"
  3255 + },
  3256 + "actions": {
  3257 + "finish": "Finish",
  3258 + "cancel": "Cancel",
  3259 + "removeLastVertex": "Remove last point"
  3260 + },
  3261 + "buttonTitles": {
  3262 + "drawMarkerButton": "Create marker",
  3263 + "drawPolyButton": "Create polygon",
  3264 + "drawLineButton": "Create Polyline",
  3265 + "drawCircleButton": "Create Circle",
  3266 + "drawRectButton": "Create rectangle",
  3267 + "editButton": "Edit mode",
  3268 + "dragButton": "Drag-drop mode",
  3269 + "cutButton": "Cut polygon area",
  3270 + "deleteButton": "Remove",
  3271 + "drawCircleMarkerButton": "Create circle marker",
  3272 + "rotateButton": "Rotate polygon"
  3273 + }
  3274 + }
3242 }, 3275 },
3243 "icon": { 3276 "icon": {
3244 "icon": "Icon", 3277 "icon": "Icon",
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 "compilerOptions": { 3 "compilerOptions": {
4 "outDir": "../out-tsc/app", 4 "outDir": "../out-tsc/app",
5 "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", 5 "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify",
6 - "react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet.markercluster", "leaflet-editable"] 6 + "react", "react-dom", "jstree", "raphael", "canvas-gauges"]
7 }, 7 },
8 "angularCompilerOptions": { 8 "angularCompilerOptions": {
9 "fullTemplateTypeCheck": true 9 "fullTemplateTypeCheck": true
ui-ngx/src/typings/leaflet-geoman-extend.d.ts renamed from ui-ngx/src/typings/add-marker.d.ts
@@ -17,15 +17,13 @@ @@ -17,15 +17,13 @@
17 import * as L from 'leaflet'; 17 import * as L from 'leaflet';
18 18
19 declare module 'leaflet' { 19 declare module 'leaflet' {
20 -  
21 - namespace Control {  
22 - class AddMarker extends L.Control { }  
23 - class AddPolygon extends L.Control { }  
24 - }  
25 -  
26 - namespace control {  
27 - function addMarker(options): Control.AddMarker;  
28 - function addPolygon(options): Control.AddPolygon; 20 + namespace PM {
  21 + interface PMMapToolbar {
  22 + toggleButton(
  23 + name: string,
  24 + status: boolean,
  25 + disableOthers?: boolean
  26 + ): void;
29 } 27 }
30 - 28 + }
31 } 29 }
@@ -20,7 +20,8 @@ @@ -20,7 +20,8 @@
20 "src/typings/jquery.flot.typings.d.ts", 20 "src/typings/jquery.flot.typings.d.ts",
21 "src/typings/jquery.jstree.typings.d.ts", 21 "src/typings/jquery.jstree.typings.d.ts",
22 "src/typings/split.js.typings.d.ts", 22 "src/typings/split.js.typings.d.ts",
23 - "src/typings/add-marker.d.ts" 23 + "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.d.ts",
  24 + "src/typings/leaflet-geoman-extend.d.ts"
24 ], 25 ],
25 "paths": { 26 "paths": {
26 "@app/*": ["src/app/*"], 27 "@app/*": ["src/app/*"],
@@ -1422,6 +1422,18 @@ @@ -1422,6 +1422,18 @@
1422 "@types/flowjs" "2.13.3" 1422 "@types/flowjs" "2.13.3"
1423 tslib "^1.9.0" 1423 tslib "^1.9.0"
1424 1424
  1425 +"@geoman-io/leaflet-geoman-free@^2.11.3":
  1426 + version "2.11.3"
  1427 + resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36"
  1428 + integrity sha512-LsiurEgKEHBcTnAVl8h7EfS5V/doCuxePzPE9SnfrhtJBN7IzP6UwkEo35Agwko+BnIuw/o2bE4F7irvKwQzjw==
  1429 + dependencies:
  1430 + "@turf/boolean-contains" "6.3.0"
  1431 + "@turf/kinks" "6.3.0"
  1432 + "@turf/line-intersect" "6.3.0"
  1433 + "@turf/line-split" "6.3.0"
  1434 + lodash "4.17.21"
  1435 + polygon-clipping "0.15.3"
  1436 +
1425 "@istanbuljs/schema@^0.1.2": 1437 "@istanbuljs/schema@^0.1.2":
1426 version "0.1.2" 1438 version "0.1.2"
1427 resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" 1439 resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
@@ -1688,6 +1700,167 @@ @@ -1688,6 +1700,167 @@
1688 resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" 1700 resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
1689 integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== 1701 integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
1690 1702
  1703 +"@turf/bbox@*", "@turf/bbox@^6.3.0":
  1704 + version "6.5.0"
  1705 + resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5"
  1706 + integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==
  1707 + dependencies:
  1708 + "@turf/helpers" "^6.5.0"
  1709 + "@turf/meta" "^6.5.0"
  1710 +
  1711 +"@turf/bearing@^6.5.0":
  1712 + version "6.5.0"
  1713 + resolved "https://registry.yarnpkg.com/@turf/bearing/-/bearing-6.5.0.tgz#462a053c6c644434bdb636b39f8f43fb0cd857b0"
  1714 + integrity sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==
  1715 + dependencies:
  1716 + "@turf/helpers" "^6.5.0"
  1717 + "@turf/invariant" "^6.5.0"
  1718 +
  1719 +"@turf/boolean-contains@6.3.0":
  1720 + version "6.3.0"
  1721 + resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.3.0.tgz#fe4fc359e408c8c3c89e7fb159c9d31fde48779a"
  1722 + integrity sha512-1MW7B5G5tIu1lnAv3pXyFzl75wfBYnbA2GhwHDb4okIXMhloy/r5uIqAZHo0fOXykKVJS/gIfA/MioKIftoTug==
  1723 + dependencies:
  1724 + "@turf/bbox" "^6.3.0"
  1725 + "@turf/boolean-point-in-polygon" "^6.3.0"
  1726 + "@turf/boolean-point-on-line" "^6.3.0"
  1727 + "@turf/helpers" "^6.3.0"
  1728 + "@turf/invariant" "^6.3.0"
  1729 +
  1730 +"@turf/boolean-point-in-polygon@^6.3.0":
  1731 + version "6.5.0"
  1732 + resolved "https://registry.yarnpkg.com/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz#6d2e9c89de4cd2e4365004c1e51490b7795a63cf"
  1733 + integrity sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==
  1734 + dependencies:
  1735 + "@turf/helpers" "^6.5.0"
  1736 + "@turf/invariant" "^6.5.0"
  1737 +
  1738 +"@turf/boolean-point-on-line@^6.3.0":
  1739 + version "6.5.0"
  1740 + resolved "https://registry.yarnpkg.com/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz#a8efa7bad88760676f395afb9980746bc5b376e9"
  1741 + integrity sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==
  1742 + dependencies:
  1743 + "@turf/helpers" "^6.5.0"
  1744 + "@turf/invariant" "^6.5.0"
  1745 +
  1746 +"@turf/destination@^6.5.0":
  1747 + version "6.5.0"
  1748 + resolved "https://registry.yarnpkg.com/@turf/destination/-/destination-6.5.0.tgz#30a84702f9677d076130e0440d3223ae503fdae1"
  1749 + integrity sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==
  1750 + dependencies:
  1751 + "@turf/helpers" "^6.5.0"
  1752 + "@turf/invariant" "^6.5.0"
  1753 +
  1754 +"@turf/distance@^6.5.0":
  1755 + version "6.5.0"
  1756 + resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.5.0.tgz#21f04d5f86e864d54e2abde16f35c15b4f36149a"
  1757 + integrity sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==
  1758 + dependencies:
  1759 + "@turf/helpers" "^6.5.0"
  1760 + "@turf/invariant" "^6.5.0"
  1761 +
  1762 +"@turf/helpers@6.x", "@turf/helpers@^6.3.0", "@turf/helpers@^6.5.0":
  1763 + version "6.5.0"
  1764 + resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e"
  1765 + integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==
  1766 +
  1767 +"@turf/invariant@^6.3.0", "@turf/invariant@^6.5.0":
  1768 + version "6.5.0"
  1769 + resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.5.0.tgz#970afc988023e39c7ccab2341bd06979ddc7463f"
  1770 + integrity sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==
  1771 + dependencies:
  1772 + "@turf/helpers" "^6.5.0"
  1773 +
  1774 +"@turf/kinks@6.3.0":
  1775 + version "6.3.0"
  1776 + resolved "https://registry.yarnpkg.com/@turf/kinks/-/kinks-6.3.0.tgz#a16b4ccc5a5aae139d43e36271e0a0494fdb4bf7"
  1777 + integrity sha512-BLWvbl2/fa4SeJzVMbleT6Vo1cmzwmzRfxL2xxMei2jmf6JSvqDoMJFwIHGXrLZXvhOCb1b2C+MhBfhtc7kYkQ==
  1778 + dependencies:
  1779 + "@turf/helpers" "^6.3.0"
  1780 +
  1781 +"@turf/line-intersect@6.3.0":
  1782 + version "6.3.0"
  1783 + resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.3.0.tgz#726a50edc66bb7b5e798b052b103fb0da4d1c4f4"
  1784 + integrity sha512-3naxR7XpkPd2vst3Mw6DFry4C9m3o0/f2n/xu5UAyxb88Ie4m2k+1eqkhzMMx/0L+E6iThWpLx7DASM6q6o9ow==
  1785 + dependencies:
  1786 + "@turf/helpers" "^6.3.0"
  1787 + "@turf/invariant" "^6.3.0"
  1788 + "@turf/line-segment" "^6.3.0"
  1789 + "@turf/meta" "^6.3.0"
  1790 + geojson-rbush "3.x"
  1791 +
  1792 +"@turf/line-intersect@^6.3.0", "@turf/line-intersect@^6.5.0":
  1793 + version "6.5.0"
  1794 + resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz#dea48348b30c093715d2195d2dd7524aee4cf020"
  1795 + integrity sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==
  1796 + dependencies:
  1797 + "@turf/helpers" "^6.5.0"
  1798 + "@turf/invariant" "^6.5.0"
  1799 + "@turf/line-segment" "^6.5.0"
  1800 + "@turf/meta" "^6.5.0"
  1801 + geojson-rbush "3.x"
  1802 +
  1803 +"@turf/line-segment@^6.3.0", "@turf/line-segment@^6.5.0":
  1804 + version "6.5.0"
  1805 + resolved "https://registry.yarnpkg.com/@turf/line-segment/-/line-segment-6.5.0.tgz#ee73f3ffcb7c956203b64ed966d96af380a4dd65"
  1806 + integrity sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==
  1807 + dependencies:
  1808 + "@turf/helpers" "^6.5.0"
  1809 + "@turf/invariant" "^6.5.0"
  1810 + "@turf/meta" "^6.5.0"
  1811 +
  1812 +"@turf/line-split@6.3.0":
  1813 + version "6.3.0"
  1814 + resolved "https://registry.yarnpkg.com/@turf/line-split/-/line-split-6.3.0.tgz#ee218f66cd65ce84eafc4956c24083663f6082ea"
  1815 + integrity sha512-Q0nUJ0vczy11piyEz0FaKScFwSQtb1HJ2RPEMCw1coUJhTCB02KBWQLImhYqwsD3uLg+H/fxaJ1Gva6EPWoDNQ==
  1816 + dependencies:
  1817 + "@turf/bbox" "^6.3.0"
  1818 + "@turf/helpers" "^6.3.0"
  1819 + "@turf/invariant" "^6.3.0"
  1820 + "@turf/line-intersect" "^6.3.0"
  1821 + "@turf/line-segment" "^6.3.0"
  1822 + "@turf/meta" "^6.3.0"
  1823 + "@turf/nearest-point-on-line" "^6.3.0"
  1824 + "@turf/square" "^6.3.0"
  1825 + "@turf/truncate" "^6.3.0"
  1826 + geojson-rbush "3.x"
  1827 +
  1828 +"@turf/meta@6.x", "@turf/meta@^6.3.0", "@turf/meta@^6.5.0":
  1829 + version "6.5.0"
  1830 + resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca"
  1831 + integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==
  1832 + dependencies:
  1833 + "@turf/helpers" "^6.5.0"
  1834 +
  1835 +"@turf/nearest-point-on-line@^6.3.0":
  1836 + version "6.5.0"
  1837 + resolved "https://registry.yarnpkg.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz#8e1cd2cdc0b5acaf4c8d8b3b33bb008d3cb99e7b"
  1838 + integrity sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==
  1839 + dependencies:
  1840 + "@turf/bearing" "^6.5.0"
  1841 + "@turf/destination" "^6.5.0"
  1842 + "@turf/distance" "^6.5.0"
  1843 + "@turf/helpers" "^6.5.0"
  1844 + "@turf/invariant" "^6.5.0"
  1845 + "@turf/line-intersect" "^6.5.0"
  1846 + "@turf/meta" "^6.5.0"
  1847 +
  1848 +"@turf/square@^6.3.0":
  1849 + version "6.5.0"
  1850 + resolved "https://registry.yarnpkg.com/@turf/square/-/square-6.5.0.tgz#ab43eef99d39c36157ab5b80416bbeba1f6b2122"
  1851 + integrity sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==
  1852 + dependencies:
  1853 + "@turf/distance" "^6.5.0"
  1854 + "@turf/helpers" "^6.5.0"
  1855 +
  1856 +"@turf/truncate@^6.3.0":
  1857 + version "6.5.0"
  1858 + resolved "https://registry.yarnpkg.com/@turf/truncate/-/truncate-6.5.0.tgz#c3a16cad959f1be1c5156157d5555c64b19185d8"
  1859 + integrity sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==
  1860 + dependencies:
  1861 + "@turf/helpers" "^6.5.0"
  1862 + "@turf/meta" "^6.5.0"
  1863 +
1691 "@types/canvas-gauges@^2.1.2": 1864 "@types/canvas-gauges@^2.1.2":
1692 version "2.1.2" 1865 version "2.1.2"
1693 resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210" 1866 resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210"
@@ -1725,6 +1898,11 @@ @@ -1725,6 +1898,11 @@
1725 resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" 1898 resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
1726 integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== 1899 integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==
1727 1900
  1901 +"@types/geojson@7946.0.8":
  1902 + version "7946.0.8"
  1903 + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
  1904 + integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
  1905 +
1728 "@types/glob@^7.1.1": 1906 "@types/glob@^7.1.1":
1729 version "7.1.3" 1907 version "7.1.3"
1730 resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" 1908 resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
@@ -1791,34 +1969,48 @@ @@ -1791,34 +1969,48 @@
1791 dependencies: 1969 dependencies:
1792 "@types/jquery" "*" 1970 "@types/jquery" "*"
1793 1971
1794 -"@types/leaflet-editable@^1.2.1": 1972 +"@types/leaflet-polylinedecorator@^1.6.1":
  1973 + version "1.6.1"
  1974 + resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.1.tgz#b6522f9dae52146bf73da249e4bedfbab200c6e4"
  1975 + integrity sha512-9etweJ2U4SWqcV/AR3i0NdWJByeMn6+zMUNlO6jVbpL8UI6qrMKybu8v9/s6UR4oXvsV4lZT6vzAsNAAMq5Ssg==
  1976 + dependencies:
  1977 + "@types/leaflet" "*"
  1978 +
  1979 +"@types/leaflet-providers@^1.2.1":
1795 version "1.2.1" 1980 version "1.2.1"
1796 - resolved "https://registry.yarnpkg.com/@types/leaflet-editable/-/leaflet-editable-1.2.1.tgz#12f1bd1d9af7beafbac256216062e97fe2ee4d55"  
1797 - integrity sha512-7Oms1HgulWiclkI0s1XLmr1yRylNoJX8sVUfAv9+28JzwWbKbLcQ6//vhFEOmoMlBQyL5veogKpUUb5qeF+Qyg== 1981 + resolved "https://registry.yarnpkg.com/@types/leaflet-providers/-/leaflet-providers-1.2.1.tgz#620669b828959740a2d8572e0c0288a2382d3564"
  1982 + integrity sha512-uNyuXiNV2q3fmgNjQji2P6RjQISmL40bbOL91/3OAwiE3XhkLKPmSAtAcfe11MAIz45iEjdFZJWppq9QyfnPIw==
1798 dependencies: 1983 dependencies:
1799 "@types/leaflet" "*" 1984 "@types/leaflet" "*"
1800 1985
1801 -"@types/leaflet-polylinedecorator@^1.6.0":  
1802 - version "1.6.0"  
1803 - resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#1572131ffedb3154c6e18e682d2fb700e203af19"  
1804 - integrity sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw== 1986 +"@types/leaflet.gridlayer.googlemutant@^0.4.6":
  1987 + version "0.4.6"
  1988 + resolved "https://registry.yarnpkg.com/@types/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.4.6.tgz#86d3ba9d432dec29b4796e37d815c233680e7fcb"
  1989 + integrity sha512-L0J7NadcZp5bcKQrv4DVlsEbQ90xLsOKScckAMnxoghh/wogk0GVkauYOYHBKeKDkx9qkMRzTf8oO+fKeYD7oQ==
1805 dependencies: 1990 dependencies:
1806 "@types/leaflet" "*" 1991 "@types/leaflet" "*"
1807 1992
1808 -"@types/leaflet.markercluster@^1.4.4":  
1809 - version "1.4.4"  
1810 - resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.4.tgz#4b4772c86182923e920061a0c25cb3e53543ad35"  
1811 - integrity sha512-BQAilNWlBpYl4+PrsJXLOh4vyv7KfWi5kh3Fclg5y4gEeNeXKqhS6y1zzBB4+wcTuVUnMWfm2G0MfqA4yA5A5A== 1993 +"@types/leaflet.markercluster@^1.4.6":
  1994 + version "1.4.6"
  1995 + resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.6.tgz#1159460b374ba5e329cb678d0e427f99dca75be5"
  1996 + integrity sha512-MD+bUDzxHznY0zOlSBUAMNQUGB2+xpJPKrR2MNEoBAAKa3QTKJJySBtCqWyGLvYNNO+Cdyc2c64aF2IFwe4fcQ==
1812 dependencies: 1997 dependencies:
1813 "@types/leaflet" "*" 1998 "@types/leaflet" "*"
1814 1999
1815 -"@types/leaflet@*", "@types/leaflet@1.5.17": 2000 +"@types/leaflet@*":
1816 version "1.5.17" 2001 version "1.5.17"
1817 resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b" 2002 resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b"
1818 integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g== 2003 integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g==
1819 dependencies: 2004 dependencies:
1820 "@types/geojson" "*" 2005 "@types/geojson" "*"
1821 2006
  2007 +"@types/leaflet@^1.7.6":
  2008 + version "1.7.6"
  2009 + resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.6.tgz#6580f4babb648972c5af3abc3d66866753fa9311"
  2010 + integrity sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA==
  2011 + dependencies:
  2012 + "@types/geojson" "*"
  2013 +
1822 "@types/lodash@^4.14.170": 2014 "@types/lodash@^4.14.170":
1823 version "4.14.170" 2015 version "4.14.170"
1824 resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" 2016 resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
@@ -4858,6 +5050,17 @@ gensync@^1.0.0-beta.2: @@ -4858,6 +5050,17 @@ gensync@^1.0.0-beta.2:
4858 resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" 5050 resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
4859 integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== 5051 integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
4860 5052
  5053 +geojson-rbush@3.x:
  5054 + version "3.2.0"
  5055 + resolved "https://registry.yarnpkg.com/geojson-rbush/-/geojson-rbush-3.2.0.tgz#8b543cf0d56f99b78faf1da52bb66acad6dfc290"
  5056 + integrity sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==
  5057 + dependencies:
  5058 + "@turf/bbox" "*"
  5059 + "@turf/helpers" "6.x"
  5060 + "@turf/meta" "6.x"
  5061 + "@types/geojson" "7946.0.8"
  5062 + rbush "^3.0.1"
  5063 +
4861 get-caller-file@^2.0.1, get-caller-file@^2.0.5: 5064 get-caller-file@^2.0.1, get-caller-file@^2.0.5:
4862 version "2.0.5" 5065 version "2.0.5"
4863 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 5066 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
@@ -6224,11 +6427,6 @@ klona@^2.0.4: @@ -6224,11 +6427,6 @@ klona@^2.0.4:
6224 resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" 6427 resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
6225 integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== 6428 integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
6226 6429
6227 -leaflet-editable@^1.2.0:  
6228 - version "1.2.0"  
6229 - resolved "https://registry.yarnpkg.com/leaflet-editable/-/leaflet-editable-1.2.0.tgz#a3a01001764ba58ea923381ee6a1c814708a0b84"  
6230 - integrity sha512-wG11JwpL8zqIbypTop6xCRGagMuWw68ihYu4uqrqc5Ep0wnEJeyob7NB2Rt5t74Oih4rwJ3OfwaGbzdowOGfYQ==  
6231 -  
6232 leaflet-polylinedecorator@^1.6.0: 6430 leaflet-polylinedecorator@^1.6.0:
6233 version "1.6.0" 6431 version "1.6.0"
6234 resolved "https://registry.yarnpkg.com/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#9ef79fd1b5302d67b72efe959a8ecd2553f27266" 6432 resolved "https://registry.yarnpkg.com/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#9ef79fd1b5302d67b72efe959a8ecd2553f27266"
@@ -6236,25 +6434,25 @@ leaflet-polylinedecorator@^1.6.0: @@ -6236,25 +6434,25 @@ leaflet-polylinedecorator@^1.6.0:
6236 dependencies: 6434 dependencies:
6237 leaflet-rotatedmarker "^0.2.0" 6435 leaflet-rotatedmarker "^0.2.0"
6238 6436
6239 -leaflet-providers@^1.12.0:  
6240 - version "1.12.0"  
6241 - resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.12.0.tgz#bf407f580d9564480e2346bc1e6412ef696624cf"  
6242 - integrity sha512-pU/mR4B+NbayBGCg5/88dmRq7t1EGiNPhsVGV3yqHuDn594vIwus4CiPVW0RtiKJNKg8Vf1pILAbFl0i+yk+lQ== 6437 +leaflet-providers@^1.13.0:
  6438 + version "1.13.0"
  6439 + resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.13.0.tgz#10c843a23d5823a65096d40ad53f27029e13434b"
  6440 + integrity sha512-f/sN5wdgBbVA2jcCYzScIfYNxKdn2wBJP9bu+5cRX9Xj6g8Bt1G9Sr8WgJAt/ckIFIc3LVVxCBNFpSCfTuUElg==
6243 6441
6244 leaflet-rotatedmarker@^0.2.0: 6442 leaflet-rotatedmarker@^0.2.0:
6245 version "0.2.0" 6443 version "0.2.0"
6246 resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277" 6444 resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277"
6247 integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc= 6445 integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc=
6248 6446
6249 -leaflet.gridlayer.googlemutant@0.10.2:  
6250 - version "0.10.2"  
6251 - resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.10.2.tgz#3c5351db4230beac1b1ea1f774d9288cfb0b6283"  
6252 - integrity sha512-r3le0W8izKmF2aeCCYp6P+dLQvPadV/vpJkres0ltDHiWac6qt3fQPNWjQl+8WCsCmcGTb1y5bmHOx0Yj6HA7g== 6447 +leaflet.gridlayer.googlemutant@0.13.4:
  6448 + version "0.13.4"
  6449 + resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.13.4.tgz#0add37d240c70c999e1f1d341208e6fea2372c40"
  6450 + integrity sha512-oC6xUSFJ9HP4WIupXakgiYckdBHuHQeSaxTXsVlcvcpfsuYoJ/HFIrz1bmK4Qr/qKO4fY1MDM6AoewU7Bph8ZQ==
6253 6451
6254 -leaflet.markercluster@^1.5.0:  
6255 - version "1.5.0"  
6256 - resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.0.tgz#54db42485da32fc3d92c7ae22d0d7982879e0b67"  
6257 - integrity sha512-Fvf/cq4o806mJL50n+fZW9+QALDDLPvt7vuAjlD2vfnxx3srMDs2vWINJze4nKYJYRY45OC6tM/669C3pLwMCA== 6452 +leaflet.markercluster@^1.5.3:
  6453 + version "1.5.3"
  6454 + resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz#9cdb52a4eab92671832e1ef9899669e80efc4056"
  6455 + integrity sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==
6258 6456
6259 leaflet@^1.7.1: 6457 leaflet@^1.7.1:
6260 version "1.7.1" 6458 version "1.7.1"
@@ -6365,7 +6563,7 @@ lodash.uniq@^4.5.0: @@ -6365,7 +6563,7 @@ lodash.uniq@^4.5.0:
6365 resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" 6563 resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
6366 integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= 6564 integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
6367 6565
6368 -lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21: 6566 +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:
6369 version "4.17.21" 6567 version "4.17.21"
6370 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 6568 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
6371 integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 6569 integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -7651,6 +7849,13 @@ pnp-webpack-plugin@1.6.4: @@ -7651,6 +7849,13 @@ pnp-webpack-plugin@1.6.4:
7651 dependencies: 7849 dependencies:
7652 ts-pnp "^1.1.6" 7850 ts-pnp "^1.1.6"
7653 7851
  7852 +polygon-clipping@0.15.3:
  7853 + version "0.15.3"
  7854 + resolved "https://registry.yarnpkg.com/polygon-clipping/-/polygon-clipping-0.15.3.tgz#0215840438470ba2e9e6593625e4ea5c1087b4b7"
  7855 + integrity sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==
  7856 + dependencies:
  7857 + splaytree "^3.1.0"
  7858 +
7654 popper.js@1.16.1-lts: 7859 popper.js@1.16.1-lts:
7655 version "1.16.1-lts" 7860 version "1.16.1-lts"
7656 resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" 7861 resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
@@ -8191,6 +8396,11 @@ querystringify@^2.1.1: @@ -8191,6 +8396,11 @@ querystringify@^2.1.1:
8191 resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" 8396 resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
8192 integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== 8397 integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
8193 8398
  8399 +quickselect@^2.0.0:
  8400 + version "2.0.0"
  8401 + resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
  8402 + integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
  8403 +
8194 raf@^3.4.0, raf@^3.4.1: 8404 raf@^3.4.0, raf@^3.4.1:
8195 version "3.4.1" 8405 version "3.4.1"
8196 resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" 8406 resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
@@ -8243,6 +8453,13 @@ raw-loader@4.0.2: @@ -8243,6 +8453,13 @@ raw-loader@4.0.2:
8243 loader-utils "^2.0.0" 8453 loader-utils "^2.0.0"
8244 schema-utils "^3.0.0" 8454 schema-utils "^3.0.0"
8245 8455
  8456 +rbush@^3.0.1:
  8457 + version "3.0.1"
  8458 + resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf"
  8459 + integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
  8460 + dependencies:
  8461 + quickselect "^2.0.0"
  8462 +
8246 rc-align@^4.0.0: 8463 rc-align@^4.0.0:
8247 version "4.0.8" 8464 version "4.0.8"
8248 resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668" 8465 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: @@ -9298,6 +9515,11 @@ speed-measure-webpack-plugin@1.4.2:
9298 dependencies: 9515 dependencies:
9299 chalk "^4.1.0" 9516 chalk "^4.1.0"
9300 9517
  9518 +splaytree@^3.1.0:
  9519 + version "3.1.0"
  9520 + resolved "https://registry.yarnpkg.com/splaytree/-/splaytree-3.1.0.tgz#17d4a0108a6da3627579690b7b847241e18ddec8"
  9521 + integrity sha512-gvUGR7xnOy0fLKTCxDeUZYgU/I1Tdf8M/lM1Qrf8L2TIOR5ipZjGk02uYcdv0o2x7WjVRgpm3iS2clLyuVAt0Q==
  9522 +
9301 split-string@^3.0.1, split-string@^3.0.2: 9523 split-string@^3.0.1, split-string@^3.0.2:
9302 version "3.1.0" 9524 version "3.1.0"
9303 resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" 9525 resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"