Commit 2e8b9b5cd7b66a6420b87480ea11ed0a1bbdcdc5

Authored by Vladyslav_Prykhodko
1 parent c0514ca3

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 830 <exclude>src/.browserslistrc</exclude>
831 831 <exclude>**/yarn.lock</exclude>
832 832 <exclude>**/*.raw</exclude>
  833 + <exclude>**/*.patch</exclude>
833 834 <exclude>**/apache/cassandra/io/**</exclude>
834 835 <exclude>.run/**</exclude>
835 836 </excludes>
... ...
... ... @@ -79,6 +79,7 @@
79 79 "src/app/modules/home/components/widget/lib/maps/markers.scss",
80 80 "node_modules/leaflet.markercluster/dist/MarkerCluster.css",
81 81 "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css",
  82 + "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css",
82 83 "node_modules/prismjs/themes/prism.css",
83 84 "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
84 85 ],
... ...
... ... @@ -28,6 +28,7 @@
28 28 "@date-io/date-fns": "^2.10.11",
29 29 "@flowjs/flow.js": "^2.14.1",
30 30 "@flowjs/ngx-flow": "~0.4.6",
  31 + "@geoman-io/leaflet-geoman-free": "^2.11.3",
31 32 "@juggle/resize-observer": "^3.3.1",
32 33 "@mat-datetimepicker/core": "~6.0.2",
33 34 "@material-ui/core": "^4.11.4",
... ... @@ -57,11 +58,10 @@
57 58 "jstree-bootstrap-theme": "^1.0.1",
58 59 "jszip": "^3.6.0",
59 60 "leaflet": "^1.7.1",
60   - "leaflet-editable": "^1.2.0",
61 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 65 "material-design-icons": "^3.0.1",
66 66 "messageformat": "^2.3.0",
67 67 "moment": "^2.29.1",
... ... @@ -113,10 +113,11 @@
113 113 "@types/jquery": "^3.5.2",
114 114 "@types/js-beautify": "^1.13.1",
115 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 121 "@types/lodash": "^4.14.170",
121 122 "@types/moment-timezone": "^0.5.30",
122 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 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 18 import tinycolor from 'tinycolor2';
27 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 23 import {
31 24 defaultSettings,
32 25 FormattedData,
33   - MapProviders,
34 26 MapSettings,
35 27 MarkerSettings,
36 28 PolygonSettings,
... ... @@ -39,12 +31,10 @@ import {
39 31 UnitedMapSettings
40 32 } from './map-models';
41 33 import { Marker } from './markers';
42   -import { Observable, of } from 'rxjs';
  34 +import { forkJoin, Observable, of } from 'rxjs';
43 35 import { Polyline } from './polyline';
44 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 38 import {
49 39 checkLngLat,
50 40 createLoadingDiv,
... ... @@ -54,6 +44,15 @@ import {
54 44 } from '@home/components/widget/lib/maps/common-maps-utils';
55 45 import { WidgetContext } from '@home/models/widget-component.models';
56 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 57 export default abstract class LeafletMap {
59 58
... ... @@ -78,20 +77,20 @@ export default abstract class LeafletMap {
78 77 drawRoutes: boolean;
79 78 showPolygon: boolean;
80 79 updatePending = false;
  80 + editPolygons = false;
  81 + selectedEntity: FormattedData;
81 82 addMarkers: L.Marker[] = [];
82 83 addPolygons: L.Polygon[] = [];
83 84 // tslint:disable-next-line:no-string-literal
84 85 southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180);
85 86 // tslint:disable-next-line:no-string-literal
86 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 89 protected constructor(public ctx: WidgetContext,
92 90 public $container: HTMLElement,
93 91 options: UnitedMapSettings) {
94 92 this.options = options;
  93 + this.editPolygons = options.showPolygon && options.editablePolygon;
95 94 }
96 95
97 96 public initSettings(options: MapSettings) {
... ... @@ -102,16 +101,28 @@ export default abstract class LeafletMap {
102 101 removeOutsideVisibleBounds,
103 102 animate,
104 103 chunkedLoading,
  104 + spiderfyOnMaxZoom,
105 105 maxClusterRadius,
106 106 maxZoom }: MapSettings = options;
107 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 112 const clusteringSettings: MarkerClusterGroupOptions = {
109   - spiderfyOnMaxZoom: false,
  113 + spiderfyOnMaxZoom,
110 114 zoomToBoundsOnClick: zoomOnClick,
111 115 showCoverageOnHover,
112 116 removeOutsideVisibleBounds,
113 117 animate,
114   - chunkedLoading
  118 + chunkedLoading,
  119 + pmIgnore: true,
  120 + spiderLegPolylineOptions: {
  121 + pmIgnore: true
  122 + },
  123 + polygonOptions: {
  124 + pmIgnore: true
  125 + }
115 126 };
116 127 if (maxClusterRadius && maxClusterRadius > 0) {
117 128 clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius);
... ... @@ -119,183 +130,165 @@ export default abstract class LeafletMap {
119 130 if (maxZoom && maxZoom >= 0 && maxZoom < 19) {
120 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 293 public setLoading(loading: boolean) {
301 294 if (this.loading !== loading) {
... ... @@ -337,11 +330,10 @@ export default abstract class LeafletMap {
337 330 if (this.options.disableScrollZooming) {
338 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 338 if (this.options.useClusterMarkers) {
347 339 this.map.addLayer(this.markersCluster);
... ... @@ -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 396 createLatLng(lat: number, lng: number): L.LatLng {
... ... @@ -441,7 +474,7 @@ export default abstract class LeafletMap {
441 474 }
442 475
443 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 479 return {
447 480 [this.options.latKeyName]: position.lat,
... ... @@ -455,17 +488,18 @@ export default abstract class LeafletMap {
455 488 if (point.length) {
456 489 return this.convertToPolygonFormat(point);
457 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 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 518 }
485 519 this.updateMarkers(formattedData, false);
486 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 530 this.datasources = formattedData;
489 531 }
490 532 } else {
... ... @@ -577,10 +619,10 @@ export default abstract class LeafletMap {
577 619 }
578 620
579 621 dragMarker = (e, data = {} as FormattedData) => {
580   - if (e.type !== 'dragend') {
  622 + if (e === undefined) {
581 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 628 private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings,
... ... @@ -728,11 +770,15 @@ export default abstract class LeafletMap {
728 770
729 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 777 updatePolygons(polyData: FormattedData[], updateBounds = true) {
732 778 const keys: string[] = [];
733 779 this.polygonsData = deepClone(polyData);
734 780 polyData.forEach((data: FormattedData) => {
735   - if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) {
  781 + if (this.isValidPolygonPosition(data)) {
736 782 if (isString((data[this.options.polygonKeyName]))) {
737 783 data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]);
738 784 }
... ... @@ -758,15 +804,14 @@ export default abstract class LeafletMap {
758 804 }
759 805
760 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 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 817 createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {
... ...
... ... @@ -57,6 +57,7 @@ export type MapSettings = {
57 57 showCoverageOnHover: boolean,
58 58 animate: boolean,
59 59 maxClusterRadius: number,
  60 + spiderfyOnMaxZoom: boolean,
60 61 chunkedLoading: boolean,
61 62 removeOutsideVisibleBounds: boolean,
62 63 useCustomProvider: boolean,
... ...
... ... @@ -14,41 +14,23 @@
14 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 18 import LeafletMap from './leaflet-map';
25 19 import {
26 20 commonMapSettingsSchema,
27 21 mapPolygonSchema,
28   - mapProviderSchema,
29 22 markerClusteringSettingsSchema,
30 23 markerClusteringSettingsSchemaLeaflet,
31 24 routeMapSettingsSchema
32 25 } from './schemes';
33 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 28 import { WidgetContext } from '@app/modules/home/models/widget-component.models';
42 29 import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils';
43 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 31 import { TranslateService } from '@ngx-translate/core';
48 32 import { UtilsService } from '@core/services/utils.service';
49 33 import { EntityDataPageLink } from '@shared/models/query/query.models';
50   -import { isDefined } from '@core/utils';
51   -import { forkJoin, Observable, of } from 'rxjs';
52 34 import { providerClass } from '@home/components/widget/lib/maps/providers';
53 35
54 36 // @dynamic
... ... @@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface {
81 63 }
82 64 parseWithTranslation.setTranslate(this.translate);
83 65 this.map = new MapClass(this.ctx, $element, this.settings);
84   - this.map.saveMarkerLocation = this.setMarkerLocation;
85   - this.map.savePolygonLocation = this.savePolygonLocation;
86 66 this.pageLink = {
87 67 page: 0,
88 68 pageSize: this.settings.mapPageSize,
... ... @@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface {
178 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 161 initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings {
288 162 const functionParams = ['data', 'dsData', 'dsIndex'];
289 163 this.provider = settings.provider || this.mapProvider;
... ...
... ... @@ -29,6 +29,10 @@
29 29 box-shadow: none;
30 30 }
31 31
32   -.leaflet-container{
  32 +.leaflet-container {
33 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 42 constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings,
43 43 data?: FormattedData, dataSources?, onDragendListener?) {
44 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 47 this.markerOffset = [
50 48 isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5,
... ... @@ -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 197
200 198 createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } {
201 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 218 removeMarker() {
216 219 /* this.map$.subscribe(map =>
217 220 this.leafletMarker.addTo(map))*/
... ...
... ... @@ -17,7 +17,6 @@
17 17 import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
18 18 import { createTooltip } from './maps-utils';
19 19 import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils';
20   -import 'leaflet-editable/src/Leaflet.Editable';
21 20 import { FormattedData, PolygonSettings } from './map-models';
22 21
23 22 export class Polygon {
... ... @@ -37,14 +36,12 @@ export class Polygon {
37 36 color: settings.polygonStrokeColor,
38 37 weight: settings.polygonStrokeWeight,
39 38 fillOpacity: settings.polygonOpacity,
40   - opacity: settings.polygonStrokeOpacity
  39 + opacity: settings.polygonStrokeOpacity,
  40 + pmIgnore: !settings.editablePolygon
41 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 70 updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
74 71 this.data = data;
75 72 this.dataSources = dataSources;
76   - if (settings.editablePolygon) {
77   - this.leafletPoly.disableEdit();
78   - }
79 73 this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]);
80   - if (settings.editablePolygon) {
81   - this.leafletPoly.enableEdit(this.map);
82   - }
83 74 if (settings.showPolygonTooltip) {
84 75 this.updateTooltip(this.data);
85 76 }
... ...
... ... @@ -14,7 +14,8 @@
14 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 19 import 'leaflet-polylinedecorator';
19 20
20 21 import { FormattedData, PolylineSettings } from './map-models';
... ... @@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common
23 24 export class Polyline {
24 25
25 26 leafletPoly: L.Polyline;
26   - polylineDecorator: L.PolylineDecorator;
  27 + polylineDecorator: PolylineDecorator;
27 28 dataSources: FormattedData[];
28 29 data: FormattedData;
29 30
... ... @@ -36,7 +37,7 @@ export class Polyline {
36 37 ).addTo(this.map);
37 38
38 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 48 offset: settings.decoratorOffset,
48 49 endOffset: settings.endDecoratorOffset,
49 50 repeat: settings.decoratorRepeat,
50   - symbol: L.Symbol[settings.decoratorSymbol]({
  51 + symbol: Symbol[settings.decoratorSymbol]({
51 52 pixelSize: settings.decoratorSymbolSize,
52 53 polygon: false,
53 54 pathOptions: {
... ... @@ -78,7 +79,8 @@ export class Polyline {
78 79 opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction,
79 80 [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity),
80 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 38 this.loadGoogle(() => {
39 39 const map = L.map($container, {
40 40 attributionControl: false,
41   - editable: !!options.editablePolygon,
42 41 tap: L.Browser.safari && L.Browser.mobile
43 42 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
44 43 (L.gridLayer as any).googleMutant({
... ...
... ... @@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap {
23 23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
24 24 super(ctx, $container, options);
25 25 const map = L.map($container, {
26   - editable: !!options.editablePolygon,
27 26 tap: L.Browser.safari && L.Browser.mobile
28 27 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
29 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 22 import {
23 23 aspectCache,
24 24 calculateNewPointCoordinate,
25   - checkLngLat,
26 25 parseFunction
27 26 } from '@home/components/widget/lib/maps/common-maps-utils';
28 27 import { WidgetContext } from '@home/models/widget-component.models';
... ... @@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap {
221 220 zoom: 1,
222 221 crs: L.CRS.Simple,
223 222 attributionControl: false,
224   - editable: !!this.options.editablePolygon,
225 223 tap: L.Browser.safari && L.Browser.mobile
226 224 });
227 225 this.updateBounds(updateImage);
... ... @@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap {
263 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 271 const point = this.latLngToPoint(position);
268 272 const customX = calculateNewPointCoordinate(point.x, width);
269 273 const customY = calculateNewPointCoordinate(point.y, height);
... ... @@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap {
279 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 286 return {
285 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 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 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 23 constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
24 24 super(ctx, $container, options);
25 25 const map = L.map($container, {
26   - editable: !!options.editablePolygon,
27 26 tap: L.Browser.safari && L.Browser.mobile
28 27 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
29 28 let tileLayer;
... ...
... ... @@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap {
25 25 super(ctx, $container, options);
26 26 const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
27 27 const map = L.map($container, {
28   - editable: !!options.editablePolygon,
29 28 tap: L.Browser.safari && L.Browser.mobile
30 29 }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
31 30 const txLayer = L.tileLayer(txUrl, {
... ...
... ... @@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet =
728 728 type: 'number',
729 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 736 chunkedLoading: {
732 737 title: 'Use chunks for adding markers so that the page does not freeze',
733 738 type: 'boolean',
... ... @@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet =
747 752 'showCoverageOnHover',
748 753 'animate',
749 754 'maxClusterRadius',
  755 + 'spiderfyOnMaxZoom',
750 756 'chunkedLoading',
751 757 'removeOutsideVisibleBounds'
752 758 ]
... ...
... ... @@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
100 100 addGroupInfo(schema, 'Path Settings');
101 101 addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
102 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 107 addGroupInfo(schema, 'Polygon Settings');
105 108 return schema;
106 109 }
... ... @@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
115 118 rotationAngle: 0
116 119 };
117 120 this.settings = { ...settings, ...this.ctx.settings };
  121 + this.settings.editablePolygon = false;
118 122 this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
119 123 this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
120 124 this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
... ...
... ... @@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges-
41 41 import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component';
42 42 import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component';
43 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 46 @NgModule({
46 47 declarations:
... ... @@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi
62 63 NavigationCardsWidgetComponent,
63 64 NavigationCardWidgetComponent,
64 65 QrCodeWidgetComponent,
65   - MarkdownWidgetComponent
  66 + MarkdownWidgetComponent,
  67 + SelectEntityDialogComponent
66 68 ],
67 69 imports: [
68 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>
\ No newline at end of file
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 3238 "update-timeseries": "Update timeseries",
3239 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 3276 "icon": {
3244 3277 "icon": "Icon",
... ...
... ... @@ -3,7 +3,7 @@
3 3 "compilerOptions": {
4 4 "outDir": "../out-tsc/app",
5 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 8 "angularCompilerOptions": {
9 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 17 import * as L from 'leaflet';
18 18
19 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 20 "src/typings/jquery.flot.typings.d.ts",
21 21 "src/typings/jquery.jstree.typings.d.ts",
22 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 26 "paths": {
26 27 "@app/*": ["src/app/*"],
... ...
... ... @@ -1422,6 +1422,18 @@
1422 1422 "@types/flowjs" "2.13.3"
1423 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 1437 "@istanbuljs/schema@^0.1.2":
1426 1438 version "0.1.2"
1427 1439 resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
... ... @@ -1688,6 +1700,167 @@
1688 1700 resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
1689 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 1864 "@types/canvas-gauges@^2.1.2":
1692 1865 version "2.1.2"
1693 1866 resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210"
... ... @@ -1725,6 +1898,11 @@
1725 1898 resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
1726 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 1906 "@types/glob@^7.1.1":
1729 1907 version "7.1.3"
1730 1908 resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
... ... @@ -1791,34 +1969,48 @@
1791 1969 dependencies:
1792 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 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 1983 dependencies:
1799 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 1990 dependencies:
1806 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 1997 dependencies:
1813 1998 "@types/leaflet" "*"
1814 1999
1815   -"@types/leaflet@*", "@types/leaflet@1.5.17":
  2000 +"@types/leaflet@*":
1816 2001 version "1.5.17"
1817 2002 resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b"
1818 2003 integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g==
1819 2004 dependencies:
1820 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 2014 "@types/lodash@^4.14.170":
1823 2015 version "4.14.170"
1824 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 5050 resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
4859 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 5064 get-caller-file@^2.0.1, get-caller-file@^2.0.5:
4862 5065 version "2.0.5"
4863 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 6427 resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
6225 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 6430 leaflet-polylinedecorator@^1.6.0:
6233 6431 version "1.6.0"
6234 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 6434 dependencies:
6237 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 6442 leaflet-rotatedmarker@^0.2.0:
6245 6443 version "0.2.0"
6246 6444 resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277"
6247 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 6457 leaflet@^1.7.1:
6260 6458 version "1.7.1"
... ... @@ -6365,7 +6563,7 @@ lodash.uniq@^4.5.0:
6365 6563 resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
6366 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 6567 version "4.17.21"
6370 6568 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
6371 6569 integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
... ... @@ -7651,6 +7849,13 @@ pnp-webpack-plugin@1.6.4:
7651 7849 dependencies:
7652 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 7859 popper.js@1.16.1-lts:
7655 7860 version "1.16.1-lts"
7656 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 8396 resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
8192 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 8404 raf@^3.4.0, raf@^3.4.1:
8195 8405 version "3.4.1"
8196 8406 resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
... ... @@ -8243,6 +8453,13 @@ raw-loader@4.0.2:
8243 8453 loader-utils "^2.0.0"
8244 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 8463 rc-align@^4.0.0:
8247 8464 version "4.0.8"
8248 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 9515 dependencies:
9299 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 9523 split-string@^3.0.1, split-string@^3.0.2:
9302 9524 version "3.1.0"
9303 9525 resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
... ...