Browse Source

UI: Improvement add/edit location marker/polygon in maps widgets

pull/5616/head
Vladyslav_Prykhodko 5 years ago
parent
commit
2e8b9b5cd7
  1. 1
      pom.xml
  2. 1
      ui-ngx/angular.json
  3. 17
      ui-ngx/package.json
  4. 54
      ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html
  5. 21
      ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss
  6. 56
      ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts
  7. 469
      ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
  8. 1
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
  9. 130
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts
  10. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss
  11. 31
      ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts
  12. 19
      ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts
  13. 12
      ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
  14. 1
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts
  15. 1
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts
  16. 21
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts
  17. 1
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts
  18. 1
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts
  19. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts
  20. 6
      ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts
  21. 4
      ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
  22. 1
      ui-ngx/src/assets/add_location.svg
  23. 3
      ui-ngx/src/assets/add_polygon.svg
  24. 35
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  25. BIN
      ui-ngx/src/assets/shadow.png
  26. 2
      ui-ngx/src/tsconfig.app.json
  27. 18
      ui-ngx/src/typings/leaflet-geoman-extend.d.ts
  28. 3
      ui-ngx/tsconfig.json
  29. 282
      ui-ngx/yarn.lock

1
pom.xml

@ -830,6 +830,7 @@
<exclude>src/.browserslistrc</exclude> <exclude>src/.browserslistrc</exclude>
<exclude>**/yarn.lock</exclude> <exclude>**/yarn.lock</exclude>
<exclude>**/*.raw</exclude> <exclude>**/*.raw</exclude>
<exclude>**/*.patch</exclude>
<exclude>**/apache/cassandra/io/**</exclude> <exclude>**/apache/cassandra/io/**</exclude>
<exclude>.run/**</exclude> <exclude>.run/**</exclude>
</excludes> </excludes>

1
ui-ngx/angular.json

@ -79,6 +79,7 @@
"src/app/modules/home/components/widget/lib/maps/markers.scss", "src/app/modules/home/components/widget/lib/maps/markers.scss",
"node_modules/leaflet.markercluster/dist/MarkerCluster.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.css",
"node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css",
"node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css",
"node_modules/prismjs/themes/prism.css", "node_modules/prismjs/themes/prism.css",
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
], ],

17
ui-ngx/package.json

@ -28,6 +28,7 @@
"@date-io/date-fns": "^2.10.11", "@date-io/date-fns": "^2.10.11",
"@flowjs/flow.js": "^2.14.1", "@flowjs/flow.js": "^2.14.1",
"@flowjs/ngx-flow": "~0.4.6", "@flowjs/ngx-flow": "~0.4.6",
"@geoman-io/leaflet-geoman-free": "^2.11.3",
"@juggle/resize-observer": "^3.3.1", "@juggle/resize-observer": "^3.3.1",
"@mat-datetimepicker/core": "~6.0.2", "@mat-datetimepicker/core": "~6.0.2",
"@material-ui/core": "^4.11.4", "@material-ui/core": "^4.11.4",
@ -57,11 +58,10 @@
"jstree-bootstrap-theme": "^1.0.1", "jstree-bootstrap-theme": "^1.0.1",
"jszip": "^3.6.0", "jszip": "^3.6.0",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"leaflet-editable": "^1.2.0",
"leaflet-polylinedecorator": "^1.6.0", "leaflet-polylinedecorator": "^1.6.0",
"leaflet-providers": "^1.12.0", "leaflet-providers": "^1.13.0",
"leaflet.gridlayer.googlemutant": "0.10.2", "leaflet.gridlayer.googlemutant": "^0.13.4",
"leaflet.markercluster": "^1.5.0", "leaflet.markercluster": "^1.5.3",
"material-design-icons": "^3.0.1", "material-design-icons": "^3.0.1",
"messageformat": "^2.3.0", "messageformat": "^2.3.0",
"moment": "^2.29.1", "moment": "^2.29.1",
@ -113,10 +113,11 @@
"@types/jquery": "^3.5.2", "@types/jquery": "^3.5.2",
"@types/js-beautify": "^1.13.1", "@types/js-beautify": "^1.13.1",
"@types/jstree": "^3.3.40", "@types/jstree": "^3.3.40",
"@types/leaflet": "1.5.17", "@types/leaflet": "^1.7.6",
"@types/leaflet-editable": "^1.2.1", "@types/leaflet-polylinedecorator": "^1.6.1",
"@types/leaflet-polylinedecorator": "^1.6.0", "@types/leaflet-providers": "^1.2.1",
"@types/leaflet.markercluster": "^1.4.4", "@types/leaflet.gridlayer.googlemutant": "^0.4.6",
"@types/leaflet.markercluster": "^1.4.6",
"@types/lodash": "^4.14.170", "@types/lodash": "^4.14.170",
"@types/moment-timezone": "^0.5.30", "@types/moment-timezone": "^0.5.30",
"@types/mousetrap": "1.6.3", "@types/mousetrap": "1.6.3",

54
ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html

@ -0,0 +1,54 @@
<!--
Copyright © 2016-2021 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<form #addEntityForm="ngForm" [formGroup]="selectEntityFormGroup" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<h2 translate>widgets.maps.select-entity</h2>
<span fxFlex></span>
<button mat-icon-button [matDialogClose]="null" type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content>
<mat-form-field class="mat-block" style="min-width: 280px">
<mat-label translate>entity.entity</mat-label>
<mat-select formControlName="entity">
<mat-option *ngFor="let entity of data.entities" [value]="entity">
{{ entity.entityName }}
</mat-option>
</mat-select>
</mat-form-field>
<div class="tb-hint" translate>widgets.maps.select-entity-hint</div>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
[matDialogClose]="null"
cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
<button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">
{{ 'action.add' | translate }}
</button>
</div>
</form>

21
ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss

@ -0,0 +1,21 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.tb-hint {
margin-top: -1.25em;
max-width: fit-content;
}
}

56
ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts

@ -0,0 +1,56 @@
///
/// Copyright © 2016-2021 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, Inject } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { FormattedData } from '@home/components/widget/lib/maps/map-models';
export interface SelectEntityDialogData {
entities: FormattedData[];
}
@Component({
selector: 'tb-select-entity-dialog',
templateUrl: './select-entity-dialog.component.html',
styleUrls: ['./select-entity-dialog.component.scss']
})
export class SelectEntityDialogComponent extends DialogComponent<SelectEntityDialogComponent, FormattedData> {
selectEntityFormGroup: FormGroup;
constructor(protected store: Store<AppState>,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: SelectEntityDialogData,
public dialogRef: MatDialogRef<SelectEntityDialogComponent, FormattedData>,
public fb: FormBuilder) {
super(store, router, dialogRef);
this.selectEntityFormGroup = this.fb.group(
{
entity: ['', Validators.required]
}
);
}
save(): void {
this.dialogRef.close(this.selectEntityFormGroup.value.entity);
}
}

469
ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts

@ -14,23 +14,15 @@
/// limitations under the License. /// limitations under the License.
/// ///
import L, { import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet';
FeatureGroup,
Icon,
LatLngBounds,
LatLngTuple,
markerClusterGroup,
MarkerClusterGroup,
MarkerClusterGroupOptions, Projection
} from 'leaflet';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import 'leaflet-providers'; import 'leaflet-providers';
import 'leaflet.markercluster/dist/leaflet.markercluster'; import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster';
import '@geoman-io/leaflet-geoman-free';
import { import {
defaultSettings, defaultSettings,
FormattedData, FormattedData,
MapProviders,
MapSettings, MapSettings,
MarkerSettings, MarkerSettings,
PolygonSettings, PolygonSettings,
@ -39,12 +31,10 @@ import {
UnitedMapSettings UnitedMapSettings
} from './map-models'; } from './map-models';
import { Marker } from './markers'; import { Marker } from './markers';
import { Observable, of } from 'rxjs'; import { forkJoin, Observable, of } from 'rxjs';
import { Polyline } from './polyline'; import { Polyline } from './polyline';
import { Polygon } from './polygon'; import { Polygon } from './polygon';
import { import { createTooltip } from '@home/components/widget/lib/maps/maps-utils';
createTooltip,
} from '@home/components/widget/lib/maps/maps-utils';
import { import {
checkLngLat, checkLngLat,
createLoadingDiv, createLoadingDiv,
@ -54,6 +44,15 @@ import {
} from '@home/components/widget/lib/maps/common-maps-utils'; } from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils';
import { TranslateService } from '@ngx-translate/core';
import {
SelectEntityDialogComponent,
SelectEntityDialogData
} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { AttributeService } from '@core/http/attribute.service';
import { EntityId } from '@shared/models/id/entity-id';
import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
export default abstract class LeafletMap { export default abstract class LeafletMap {
@ -78,20 +77,20 @@ export default abstract class LeafletMap {
drawRoutes: boolean; drawRoutes: boolean;
showPolygon: boolean; showPolygon: boolean;
updatePending = false; updatePending = false;
editPolygons = false;
selectedEntity: FormattedData;
addMarkers: L.Marker[] = []; addMarkers: L.Marker[] = [];
addPolygons: L.Polygon[] = []; addPolygons: L.Polygon[] = [];
// tslint:disable-next-line:no-string-literal // tslint:disable-next-line:no-string-literal
southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180);
// tslint:disable-next-line:no-string-literal // tslint:disable-next-line:no-string-literal
northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180);
mousePositionOnMap: L.LatLng;
addMarker: L.Control;
addPolygon: L.Control;
protected constructor(public ctx: WidgetContext, protected constructor(public ctx: WidgetContext,
public $container: HTMLElement, public $container: HTMLElement,
options: UnitedMapSettings) { options: UnitedMapSettings) {
this.options = options; this.options = options;
this.editPolygons = options.showPolygon && options.editablePolygon;
} }
public initSettings(options: MapSettings) { public initSettings(options: MapSettings) {
@ -102,16 +101,28 @@ export default abstract class LeafletMap {
removeOutsideVisibleBounds, removeOutsideVisibleBounds,
animate, animate,
chunkedLoading, chunkedLoading,
spiderfyOnMaxZoom,
maxClusterRadius, maxClusterRadius,
maxZoom }: MapSettings = options; maxZoom }: MapSettings = options;
if (useClusterMarkers) { if (useClusterMarkers) {
// disabled marker cluster icon
(L as any).MarkerCluster = (L as any).MarkerCluster.extend({
options: { pmIgnore: true, ...L.Icon.prototype.options }
});
const clusteringSettings: MarkerClusterGroupOptions = { const clusteringSettings: MarkerClusterGroupOptions = {
spiderfyOnMaxZoom: false, spiderfyOnMaxZoom,
zoomToBoundsOnClick: zoomOnClick, zoomToBoundsOnClick: zoomOnClick,
showCoverageOnHover, showCoverageOnHover,
removeOutsideVisibleBounds, removeOutsideVisibleBounds,
animate, animate,
chunkedLoading chunkedLoading,
pmIgnore: true,
spiderLegPolylineOptions: {
pmIgnore: true
},
polygonOptions: {
pmIgnore: true
}
}; };
if (maxClusterRadius && maxClusterRadius > 0) { if (maxClusterRadius && maxClusterRadius > 0) {
clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius); clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius);
@ -119,183 +130,165 @@ export default abstract class LeafletMap {
if (maxZoom && maxZoom >= 0 && maxZoom < 19) { if (maxZoom && maxZoom >= 0 && maxZoom < 19) {
clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom); clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom);
} }
this.markersCluster = markerClusterGroup(clusteringSettings); this.markersCluster = new MarkerClusterGroup(clusteringSettings);
} }
} }
addMarkerControl() { private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable<FormattedData> {
if (this.options.draggableMarker) { let entities;
this.map.on('mousemove', (e: L.LeafletMouseEvent) => { switch (shapes) {
this.mousePositionOnMap = e.latlng; case 'Polygon':
}); case 'Rectangle':
const dragListener = (e: L.DragEndEvent) => { entities = this.datasources.filter(pData => !this.isValidPolygonPosition(pData));
if (e.type === 'dragend' && this.mousePositionOnMap) { break;
const icon = L.icon({ case 'Marker':
iconRetinaUrl: 'marker-icon-2x.png', entities = this.datasources.filter(mData => !this.convertPosition(mData));
iconUrl: 'marker-icon.png', break;
shadowUrl: 'marker-shadow.png', default:
iconSize: [25, 41], return of(null);
iconAnchor: [12, 41], }
popupAnchor: [1, -34], if (entities.length === 1) {
tooltipAnchor: [16, -28], return of(entities[0]);
shadowSize: [41, 41] }
}); const dialog = this.ctx.$injector.get(MatDialog);
const customLatLng = this.convertToCustomFormat(this.mousePositionOnMap); return dialog.open<SelectEntityDialogComponent, SelectEntityDialogData, FormattedData>(SelectEntityDialogComponent,
this.mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; {
this.mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
const newMarker = L.marker(this.mousePositionOnMap, { icon }).addTo(this.map); data: {
this.addMarkers.push(newMarker); entities
const datasourcesList = document.createElement('div'); }
const header = document.createElement('p'); }).afterClosed();
header.appendChild(document.createTextNode('Select entity:')); }
header.setAttribute('style', 'font-size: 14px; margin: 8px 0');
datasourcesList.appendChild(header); private selectEntityWithoutLocation(type: string) {
this.datasources.forEach(ds => { this.selectEntityWithoutLocationDialog(type.substring(2)).subscribe((data) => {
const dsItem = document.createElement('p'); if (data !== null) {
dsItem.appendChild(document.createTextNode(ds.entityName)); this.selectedEntity = data;
dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer'); this.toggleDrawMode(type);
dsItem.onclick = () => { } else {
const updatedEnttity = { ...ds, ...customLatLng }; this.map.pm.Toolbar.toggleButton(type, false);
this.saveMarkerLocation(updatedEnttity).subscribe(() => {
this.map.removeLayer(newMarker);
const markerIndex = this.addMarkers.indexOf(newMarker);
if (markerIndex > -1) {
this.addMarkers.splice(markerIndex, 1);
}
this.deleteMarker(ds.entityName);
this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options);
});
};
datasourcesList.appendChild(dsItem);
});
datasourcesList.appendChild(document.createElement('br'));
const deleteBtn = document.createElement('a');
deleteBtn.appendChild(document.createTextNode('Discard changes'));
deleteBtn.onclick = () => {
this.map.removeLayer(newMarker);
const markerIndex = this.addMarkers.indexOf(newMarker);
if (markerIndex > -1) {
this.addMarkers.splice(markerIndex, 1);
}
};
datasourcesList.appendChild(deleteBtn);
const popup = L.popup();
popup.setContent(datasourcesList);
newMarker.bindPopup(popup).openPopup();
}
this.addMarker.setPosition('topright');
};
const addMarker = L.Control.extend({
onAdd() {
const img = L.DomUtil.create('img') as any;
img.src = `assets/add_location.svg`;
img.style.width = '32px';
img.style.height = '32px';
img.title = 'Drag and drop to add marker';
img.onclick = this.dragMarker;
img.draggable = true;
const draggableImg = new L.Draggable(img);
draggableImg.enable();
draggableImg.on('dragend', dragListener);
return img;
},
onRemove() {
},
dragMarker: this.dragMarker
} as any);
const addMarkerControl = (opts) => {
return new addMarker(opts);
};
this.addMarker = addMarkerControl({ position: 'topright' }).addTo(this.map);
} }
});
}
private toggleDrawMode(type: string) {
this.map.pm.Draw[type].toggle();
} }
addPolygonControl() { addEditControl() {
if (this.options.showPolygon && this.options.editablePolygon) { // Customize edit marker
this.map.on('mousemove', (e: L.LeafletMouseEvent) => { if (this.options.draggableMarker) {
this.mousePositionOnMap = e.latlng; const actions = [{
text: L.PM.Utils.getTranslation('actions.cancel'),
onClick: () => this.toggleDrawMode('tbMarker')
}];
this.map.pm.Toolbar.copyDrawControl('Marker', {
name: 'tbMarker',
afterClick: () => this.selectEntityWithoutLocation('tbMarker'),
disabled: true,
actions
});
}
// Customize edit polygon
if (this.editPolygons) {
const rectangleActions = [
{
text: L.PM.Utils.getTranslation('actions.cancel'),
onClick: () => this.toggleDrawMode('tbRectangle')
}
];
const polygonActions = [
'finish' as const,
'removeLastVertex' as const,
{
text: L.PM.Utils.getTranslation('actions.cancel'),
onClick: () => this.toggleDrawMode('tbPolygon')
}
];
this.map.pm.Toolbar.copyDrawControl('Rectangle', {
name: 'tbRectangle',
afterClick: () => this.selectEntityWithoutLocation('tbRectangle'),
disabled: true,
actions: rectangleActions
});
this.map.pm.Toolbar.copyDrawControl('Polygon', {
name: 'tbPolygon',
afterClick: () => this.selectEntityWithoutLocation('tbPolygon'),
disabled: true,
actions: polygonActions
});
}
const translateService = this.ctx.$injector.get(TranslateService);
this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en');
this.map.pm.addControls({
position: 'topleft',
drawMarker: false,
drawCircle: false,
drawCircleMarker: false,
drawRectangle: false,
drawPolyline: false,
drawPolygon: false,
editMode: this.editPolygons,
cutPolygon: this.editPolygons,
rotateMode: this.editPolygons
}); });
const dragListener = (e: L.DragEndEvent) => { this.map.on('pm:create', (e) => {
if (e.type === 'dragend') { if (e.shape === 'tbMarker') {
const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01; // @ts-ignore
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {
const convert = this.convertToCustomFormat(this.mousePositionOnMap, polygonOffset); });
this.mousePositionOnMap.lat = convert[this.options.latKeyName]; } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') {
this.mousePositionOnMap.lng = convert[this.options.lngKeyName]; // @ts-ignore
this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => {
const latlng1 = this.mousePositionOnMap;
const latlng2 = L.latLng(this.mousePositionOnMap.lat, this.mousePositionOnMap.lng + polygonOffset);
const latlng3 = L.latLng(this.mousePositionOnMap.lat - polygonOffset, this.mousePositionOnMap.lng);
const polygonPoints = [latlng1, latlng2, latlng3];
const newPolygon = L.polygon(polygonPoints).addTo(this.map);
this.addPolygons.push(newPolygon);
const datasourcesList = document.createElement('div');
const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(polygonPoints)};
const header = document.createElement('p');
header.appendChild(document.createTextNode('Select entity:'));
header.setAttribute('style', 'font-size: 14px; margin: 8px 0');
datasourcesList.appendChild(header);
this.datasources.forEach(ds => {
const dsItem = document.createElement('p');
dsItem.appendChild(document.createTextNode(ds.entityName));
dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer');
dsItem.onclick = () => {
const updatedEnttity = { ...ds, ...customLatLng };
this.savePolygonLocation(updatedEnttity).subscribe(() => {
this.map.removeLayer(newPolygon);
const polygonIndex = this.addPolygons.indexOf(newPolygon);
if (polygonIndex > -1) {
this.addPolygons.splice(polygonIndex, 1);
}
this.deletePolygon(ds.entityName);
});
};
datasourcesList.appendChild(dsItem);
}); });
datasourcesList.appendChild(document.createElement('br'));
const deleteBtn = document.createElement('a');
deleteBtn.appendChild(document.createTextNode('Discard changes'));
deleteBtn.onclick = () => {
this.map.removeLayer(newPolygon);
const polygonIndex = this.addPolygons.indexOf(newPolygon);
if (polygonIndex > -1) {
this.addPolygons.splice(polygonIndex, 1);
}
};
datasourcesList.appendChild(deleteBtn);
const popup = L.popup();
popup.setContent(datasourcesList);
newPolygon.bindPopup(popup).openPopup();
} }
this.addPolygon.setPosition('topright'); // @ts-ignore
}; e.layer._pmTempLayer = true;
const addPolygon = L.Control.extend({ e.layer.remove();
onAdd() { });
const img = L.DomUtil.create('img') as any;
img.src = `assets/add_polygon.svg`; this.map.on('pm:cut', (e) => {
img.style.width = '32px'; // @ts-ignore
img.style.height = '32px'; e.originalLayer.setLatLngs(e.layer.getLatLngs());
img.title = 'Drag and drop to add Polygon'; e.originalLayer.addTo(this.map);
img.onclick = this.dragPolygonVertex; // @ts-ignore
img.draggable = true; e.originalLayer._pmTempLayer = false;
const draggableImg = new L.Draggable(img); const iterator = this.polygons.values();
draggableImg.enable(); let result = iterator.next();
draggableImg.on('dragend', dragListener); while (!result.done && e.originalLayer !== result.value.leafletPoly) {
return img; result = iterator.next();
}, }
onRemove() { // @ts-ignore
}, e.layer._pmTempLayer = true;
dragPolygonVertex: this.dragPolygonVertex e.layer.remove();
} as any); });
const addPolygonControl = (opts) => {
return new addPolygon(opts); this.map.on('pm:remove', (e) => {
}; if (e.shape === 'Marker') {
this.addPolygon = addPolygonControl({ position: 'topright' }).addTo(this.map); const iterator = this.markers.values();
let result = iterator.next();
while (!result.done && e.layer !== result.value.leafletMarker) {
result = iterator.next();
}
this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {});
} else if (e.shape === 'Polygon') {
const iterator = this.polygons.values();
let result = iterator.next();
while (!result.done && e.layer !== result.value.leafletPoly) {
result = iterator.next();
}
this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {});
}
});
} }
}
public setLoading(loading: boolean) { public setLoading(loading: boolean) {
if (this.loading !== loading) { if (this.loading !== loading) {
@ -337,11 +330,10 @@ export default abstract class LeafletMap {
if (this.options.disableScrollZooming) { if (this.options.disableScrollZooming) {
this.map.scrollWheelZoom.disable(); this.map.scrollWheelZoom.disable();
} }
if (this.options.draggableMarker) { if (this.options.draggableMarker || this.editPolygons) {
this.addMarkerControl(); this.addEditControl();
} } else {
if (this.options.editablePolygon) { this.map.pm.disableDraw();
this.addPolygonControl();
} }
if (this.options.useClusterMarkers) { if (this.options.useClusterMarkers) {
this.map.addLayer(this.markersCluster); this.map.addLayer(this.markersCluster);
@ -352,12 +344,53 @@ export default abstract class LeafletMap {
} }
} }
public saveMarkerLocation(datasource: FormattedData, lat?: number, lng?: number): Observable<any> { private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable<any> {
return of(null); const attributeService = this.ctx.$injector.get(AttributeService);
} const attributes = [];
const timeseries = [];
const entityId: EntityId = {
entityType: e.$datasource.entityType,
id: e.$datasource.entityId
};
public savePolygonLocation(datasource: FormattedData, coordinates?: Array<[number, number]>): Observable<any> { for (const dataKeyName of Object.keys(values)) {
return of(null); for (const key of e.$datasource.dataKeys) {
if (dataKeyName === key.name) {
const value = {
key: key.name,
value: values[dataKeyName]
};
if (key.type === DataKeyType.attribute) {
attributes.push(value);
} else if (key.type === DataKeyType.timeseries) {
timeseries.push(value);
}
break;
}
}
}
const observables: Observable<any>[] = [];
if (timeseries.length) {
observables.push(attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
timeseries
));
}
if (attributes.length) {
observables.push(attributeService.saveEntityAttributes(
entityId,
AttributeScope.SERVER_SCOPE,
attributes
));
}
if (observables.length) {
return forkJoin(observables);
} else {
return of(null);
}
} }
createLatLng(lat: number, lng: number): L.LatLng { createLatLng(lat: number, lng: number): L.LatLng {
@ -441,7 +474,7 @@ export default abstract class LeafletMap {
} }
convertToCustomFormat(position: L.LatLng, offset = 0): object { convertToCustomFormat(position: L.LatLng, offset = 0): object {
position = checkLngLat(position, this.southWest, this.northEast, offset); position = position ? checkLngLat(position, this.southWest, this.northEast, offset) : {lat: null, lng: null} as L.LatLng;
return { return {
[this.options.latKeyName]: position.lat, [this.options.latKeyName]: position.lat,
@ -455,17 +488,18 @@ export default abstract class LeafletMap {
if (point.length) { if (point.length) {
return this.convertToPolygonFormat(point); return this.convertToPolygonFormat(point);
} else { } else {
return [point.lat, point.lng]; const convertPoint = checkLngLat(point, this.southWest, this.northEast);
return [convertPoint.lat, convertPoint.lng];
} }
}); });
} else {
return [];
} }
return [];
} }
convertPolygonToCustomFormat(expression: any[][]): object { convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
return { return {
[this.options.polygonKeyName] : this.convertToPolygonFormat(expression) [this.options.polygonKeyName]: coordinate
}; };
} }
@ -484,7 +518,15 @@ export default abstract class LeafletMap {
} }
this.updateMarkers(formattedData, false); this.updateMarkers(formattedData, false);
this.updateBoundsInternal(); this.updateBoundsInternal();
if (this.options.draggableMarker || this.options.editablePolygon) { if (this.options.draggableMarker) {
const foundEntityWithoutLocation = formattedData.some(mData => !this.convertPosition(mData));
this.map.pm.Toolbar.setButtonDisabled('tbMarker', !foundEntityWithoutLocation);
this.datasources = formattedData;
}
if (this.editPolygons) {
const foundEntityWithoutPolygon = formattedData.some(pData => !this.isValidPolygonPosition(pData));
this.map.pm.Toolbar.setButtonDisabled('tbPolygon', !foundEntityWithoutPolygon);
this.map.pm.Toolbar.setButtonDisabled('tbRectangle', !foundEntityWithoutPolygon);
this.datasources = formattedData; this.datasources = formattedData;
} }
} else { } else {
@ -577,10 +619,10 @@ export default abstract class LeafletMap {
} }
dragMarker = (e, data = {} as FormattedData) => { dragMarker = (e, data = {} as FormattedData) => {
if (e.type !== 'dragend') { if (e === undefined) {
return; return;
} }
this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }).subscribe(); this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe();
} }
private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings,
@ -728,11 +770,15 @@ export default abstract class LeafletMap {
// Polygon // Polygon
isValidPolygonPosition(data: FormattedData): boolean {
return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]);
}
updatePolygons(polyData: FormattedData[], updateBounds = true) { updatePolygons(polyData: FormattedData[], updateBounds = true) {
const keys: string[] = []; const keys: string[] = [];
this.polygonsData = deepClone(polyData); this.polygonsData = deepClone(polyData);
polyData.forEach((data: FormattedData) => { polyData.forEach((data: FormattedData) => {
if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) { if (this.isValidPolygonPosition(data)) {
if (isString((data[this.options.polygonKeyName]))) { if (isString((data[this.options.polygonKeyName]))) {
data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]); data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]);
} }
@ -758,15 +804,14 @@ export default abstract class LeafletMap {
} }
dragPolygonVertex = (e?, data = {} as FormattedData) => { dragPolygonVertex = (e?, data = {} as FormattedData) => {
if (e === undefined || (e.type !== 'editable:vertex:dragend' && e.type !== 'editable:vertex:deleted')) { if (e === undefined) {
return; return;
} }
if (this.options.provider !== MapProviders.image) { let coordinates = e.layer.getLatLngs();
for (const key of Object.keys(e.layer._latlngs[0])) { if (coordinates.length === 1) {
e.layer._latlngs[0][key] = checkLngLat(e.layer._latlngs[0][key], this.southWest, this.northEast); coordinates = coordinates[0];
}
} }
this.savePolygonLocation({ ...data, ...this.convertPolygonToCustomFormat(e.layer._latlngs) }).subscribe(); this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {});
} }
createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) { createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) {

1
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts

@ -57,6 +57,7 @@ export type MapSettings = {
showCoverageOnHover: boolean, showCoverageOnHover: boolean,
animate: boolean, animate: boolean,
maxClusterRadius: number, maxClusterRadius: number,
spiderfyOnMaxZoom: boolean,
chunkedLoading: boolean, chunkedLoading: boolean,
removeOutsideVisibleBounds: boolean, removeOutsideVisibleBounds: boolean,
useCustomProvider: boolean, useCustomProvider: boolean,

130
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts

@ -14,41 +14,23 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models';
defaultSettings,
FormattedData,
hereProviders,
MapProviders,
UnitedMapSettings
} from './map-models';
import LeafletMap from './leaflet-map'; import LeafletMap from './leaflet-map';
import { import {
commonMapSettingsSchema, commonMapSettingsSchema,
mapPolygonSchema, mapPolygonSchema,
mapProviderSchema,
markerClusteringSettingsSchema, markerClusteringSettingsSchema,
markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchemaLeaflet,
routeMapSettingsSchema routeMapSettingsSchema
} from './schemes'; } from './schemes';
import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
import { import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
addCondition,
addGroupInfo,
addToSchema,
initSchema,
mergeSchemes
} from '@core/schema-utils';
import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { WidgetContext } from '@app/modules/home/models/widget-component.models';
import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils'; import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils';
import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models';
import { EntityId } from '@shared/models/id/entity-id';
import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { AttributeService } from '@core/http/attribute.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { EntityDataPageLink } from '@shared/models/query/query.models'; import { EntityDataPageLink } from '@shared/models/query/query.models';
import { isDefined } from '@core/utils';
import { forkJoin, Observable, of } from 'rxjs';
import { providerClass } from '@home/components/widget/lib/maps/providers'; import { providerClass } from '@home/components/widget/lib/maps/providers';
// @dynamic // @dynamic
@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface {
} }
parseWithTranslation.setTranslate(this.translate); parseWithTranslation.setTranslate(this.translate);
this.map = new MapClass(this.ctx, $element, this.settings); this.map = new MapClass(this.ctx, $element, this.settings);
this.map.saveMarkerLocation = this.setMarkerLocation;
this.map.savePolygonLocation = this.savePolygonLocation;
this.pageLink = { this.pageLink = {
page: 0, page: 0,
pageSize: this.settings.mapPageSize, pageSize: this.settings.mapPageSize,
@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface {
}, entityName, null, entityLabel); }, entityName, null, entityLabel);
} }
setMarkerLocation = (e: FormattedData, lat?: number, lng?: number) => {
const attributeService = this.ctx.$injector.get(AttributeService);
const entityId: EntityId = {
entityType: e.$datasource.entityType,
id: e.$datasource.entityId
};
const attributes = [];
const timeseries = [];
const latProperties = [this.settings.latKeyName, this.settings.xPosKeyName];
const lngProperties = [this.settings.lngKeyName, this.settings.yPosKeyName];
e.$datasource.dataKeys.forEach(key => {
let value;
if (latProperties.includes(key.name)) {
value = {
key: key.name,
value: isDefined(lat) ? lat : e[key.name]
};
} else if (lngProperties.includes(key.name)) {
value = {
key: key.name,
value: isDefined(lng) ? lng : e[key.name]
};
}
if (value) {
if (key.type === DataKeyType.attribute) {
attributes.push(value);
}
if (key.type === DataKeyType.timeseries) {
timeseries.push(value);
}
}
});
const observables: Observable<any>[] = [];
if (timeseries.length) {
observables.push(attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
timeseries
));
}
if (attributes.length) {
observables.push(attributeService.saveEntityAttributes(
entityId,
AttributeScope.SERVER_SCOPE,
attributes
));
}
if (observables.length) {
return forkJoin(observables);
} else {
return of(null);
}
}
savePolygonLocation = (e: FormattedData, coordinates?: Array<any>) => {
const attributeService = this.ctx.$injector.get(AttributeService);
const entityId: EntityId = {
entityType: e.$datasource.entityType,
id: e.$datasource.entityId
};
const attributes = [];
const timeseries = [];
const coordinatesProperties = this.settings.polygonKeyName;
e.$datasource.dataKeys.forEach(key => {
let value;
if (coordinatesProperties === key.name) {
value = {
key: key.name,
value: isDefined(coordinates) ? coordinates : e[key.name]
};
}
if (value) {
if (key.type === DataKeyType.attribute) {
attributes.push(value);
}
if (key.type === DataKeyType.timeseries) {
timeseries.push(value);
}
}
});
const observables: Observable<any>[] = [];
if (timeseries.length) {
observables.push(attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
timeseries
));
}
if (attributes.length) {
observables.push(attributeService.saveEntityAttributes(
entityId,
AttributeScope.SERVER_SCOPE,
attributes
));
}
if (observables.length) {
return forkJoin(observables);
} else {
return of(null);
}
}
initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings {
const functionParams = ['data', 'dsData', 'dsIndex']; const functionParams = ['data', 'dsData', 'dsIndex'];
this.provider = settings.provider || this.mapProvider; this.provider = settings.provider || this.mapProvider;

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss

@ -29,6 +29,10 @@
box-shadow: none; box-shadow: none;
} }
.leaflet-container{ .leaflet-container {
background-color: white; background-color: white;
} }
.leaflet-buttons-control-button.pm-disabled {
pointer-events: none;
}

31
ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts

@ -42,9 +42,7 @@ export class Marker {
constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings, constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings,
data?: FormattedData, dataSources?, onDragendListener?) { data?: FormattedData, dataSources?, onDragendListener?) {
this.setDataSources(data, dataSources); this.setDataSources(data, dataSources);
this.leafletMarker = L.marker(location, { this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker});
draggable: settings.draggableMarker
});
this.markerOffset = [ this.markerOffset = [
isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5, isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5,
@ -72,8 +70,8 @@ export class Marker {
}); });
} }
if (onDragendListener) { if (settings.draggableMarker && onDragendListener) {
this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data)); this.leafletMarker.on('pm:dragend', (e) => onDragendListener(e, this.data));
} }
} }
@ -199,19 +197,24 @@ export class Marker {
createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } { createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } {
return { return {
size: [21, 34], size: [21, 34],
icon: L.icon({ icon: L.icon({
iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color.toHex(), iconUrl: this.createColorIconURI(color),
iconSize: [21, 34], iconSize: [21, 34],
iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]],
popupAnchor: [0, -34], popupAnchor: [0, -34],
shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', shadowUrl: 'assets/shadow.png',
shadowSize: [40, 37], shadowSize: [40, 37],
shadowAnchor: [12, 35] shadowAnchor: [12, 35]
}) })
}; };
} }
createColorIconURI(color: tinycolor.Instance): string {
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>`;
return 'data:image/svg+xml;base64,' + btoa(svg);
}
removeMarker() { removeMarker() {
/* this.map$.subscribe(map => /* this.map$.subscribe(map =>
this.leafletMarker.addTo(map))*/ this.leafletMarker.addTo(map))*/

19
ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts

@ -17,7 +17,6 @@
import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
import { createTooltip } from './maps-utils'; import { createTooltip } from './maps-utils';
import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils';
import 'leaflet-editable/src/Leaflet.Editable';
import { FormattedData, PolygonSettings } from './map-models'; import { FormattedData, PolygonSettings } from './map-models';
export class Polygon { export class Polygon {
@ -37,14 +36,12 @@ export class Polygon {
color: settings.polygonStrokeColor, color: settings.polygonStrokeColor,
weight: settings.polygonStrokeWeight, weight: settings.polygonStrokeWeight,
fillOpacity: settings.polygonOpacity, fillOpacity: settings.polygonOpacity,
opacity: settings.polygonStrokeOpacity opacity: settings.polygonStrokeOpacity,
pmIgnore: !settings.editablePolygon
}).addTo(this.map); }).addTo(this.map);
if (settings.editablePolygon) {
this.leafletPoly.enableEdit(this.map); if (settings.editablePolygon && onDragendListener) {
if (onDragendListener) { this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data));
this.leafletPoly.on('editable:vertex:dragend', e => onDragendListener(e, this.data));
this.leafletPoly.on('editable:vertex:deleted', e => onDragendListener(e, this.data));
}
} }
@ -73,13 +70,7 @@ export class Polygon {
updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
this.data = data; this.data = data;
this.dataSources = dataSources; this.dataSources = dataSources;
if (settings.editablePolygon) {
this.leafletPoly.disableEdit();
}
this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]);
if (settings.editablePolygon) {
this.leafletPoly.enableEdit(this.map);
}
if (settings.showPolygonTooltip) { if (settings.showPolygonTooltip) {
this.updateTooltip(this.data); this.updateTooltip(this.data);
} }

12
ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts

@ -14,7 +14,8 @@
/// limitations under the License. /// limitations under the License.
/// ///
import L, { PolylineDecoratorOptions } from 'leaflet'; // @ts-ignore
import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet';
import 'leaflet-polylinedecorator'; import 'leaflet-polylinedecorator';
import { FormattedData, PolylineSettings } from './map-models'; import { FormattedData, PolylineSettings } from './map-models';
@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common
export class Polyline { export class Polyline {
leafletPoly: L.Polyline; leafletPoly: L.Polyline;
polylineDecorator: L.PolylineDecorator; polylineDecorator: PolylineDecorator;
dataSources: FormattedData[]; dataSources: FormattedData[];
data: FormattedData; data: FormattedData;
@ -36,7 +37,7 @@ export class Polyline {
).addTo(this.map); ).addTo(this.map);
if (settings.usePolylineDecorator) { if (settings.usePolylineDecorator) {
this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); this.polylineDecorator = new PolylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map);
} }
} }
@ -47,7 +48,7 @@ export class Polyline {
offset: settings.decoratorOffset, offset: settings.decoratorOffset,
endOffset: settings.endDecoratorOffset, endOffset: settings.endDecoratorOffset,
repeat: settings.decoratorRepeat, repeat: settings.decoratorRepeat,
symbol: L.Symbol[settings.decoratorSymbol]({ symbol: Symbol[settings.decoratorSymbol]({
pixelSize: settings.decoratorSymbolSize, pixelSize: settings.decoratorSymbolSize,
polygon: false, polygon: false,
pathOptions: { pathOptions: {
@ -78,7 +79,8 @@ export class Polyline {
opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction, opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction,
[this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity), [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity),
weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction, weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction,
[this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight) [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight),
pmIgnore: true
}; };
} }

1
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts

@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap {
this.loadGoogle(() => { this.loadGoogle(() => {
const map = L.map($container, { const map = L.map($container, {
attributionControl: false, attributionControl: false,
editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
(L.gridLayer as any).googleMutant({ (L.gridLayer as any).googleMutant({

1
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts

@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
super(ctx, $container, options); super(ctx, $container, options);
const map = L.map($container, { const map = L.map($container, {
editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials);

21
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts

@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators';
import { import {
aspectCache, aspectCache,
calculateNewPointCoordinate, calculateNewPointCoordinate,
checkLngLat,
parseFunction parseFunction
} from '@home/components/widget/lib/maps/common-maps-utils'; } from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap {
zoom: 1, zoom: 1,
crs: L.CRS.Simple, crs: L.CRS.Simple,
attributionControl: false, attributionControl: false,
editable: !!this.options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile tap: L.Browser.safari && L.Browser.mobile
}); });
this.updateBounds(updateImage); this.updateBounds(updateImage);
@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap {
return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
} }
convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): object { convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} {
if (!position) {
return {
[this.options.xPosKeyName]: null,
[this.options.yPosKeyName]: null
};
}
const point = this.latLngToPoint(position); const point = this.latLngToPoint(position);
const customX = calculateNewPointCoordinate(point.x, width); const customX = calculateNewPointCoordinate(point.x, width);
const customY = calculateNewPointCoordinate(point.y, height); const customY = calculateNewPointCoordinate(point.y, height);
@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap {
point.y = height; point.y = height;
} }
const customLatLng = checkLngLat(this.pointToLatLng(point.x, point.y), this.southWest, this.northEast, offset);
return { return {
[this.options.xPosKeyName]: customX, [this.options.xPosKeyName]: customX,
[this.options.yPosKeyName]: customY, [this.options.yPosKeyName]: customY
[this.options.latKeyName]: customLatLng.lat,
[this.options.lngKeyName]: customLatLng.lng
}; };
} }
@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap {
} }
} }
convertPolygonToCustomFormat(expression: any[][]): object { convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} {
const coordinate = expression ? this.convertToPolygonFormat(expression) : null;
return { return {
[this.options.polygonKeyName] : this.convertToPolygonFormat(expression) [this.options.polygonKeyName]: coordinate
}; };
} }
} }

1
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts

@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) {
super(ctx, $container, options); super(ctx, $container, options);
const map = L.map($container, { const map = L.map($container, {
editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
let tileLayer; let tileLayer;

1
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts

@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap {
super(ctx, $container, options); super(ctx, $container, options);
const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
const map = L.map($container, { const map = L.map($container, {
editable: !!options.editablePolygon,
tap: L.Browser.safari && L.Browser.mobile tap: L.Browser.safari && L.Browser.mobile
}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
const txLayer = L.tileLayer(txUrl, { const txLayer = L.tileLayer(txUrl, {

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts

@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet =
type: 'number', type: 'number',
default: 80 default: 80
}, },
spiderfyOnMaxZoom: {
title: 'Spiderfy at the max zoom level (to see all cluster markers)',
type: 'boolean',
default: false
},
chunkedLoading: { chunkedLoading: {
title: 'Use chunks for adding markers so that the page does not freeze', title: 'Use chunks for adding markers so that the page does not freeze',
type: 'boolean', type: 'boolean',
@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet =
'showCoverageOnHover', 'showCoverageOnHover',
'animate', 'animate',
'maxClusterRadius', 'maxClusterRadius',
'spiderfyOnMaxZoom',
'chunkedLoading', 'chunkedLoading',
'removeOutsideVisibleBounds' 'removeOutsideVisibleBounds'
] ]

6
ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts

@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
addGroupInfo(schema, 'Path Settings'); addGroupInfo(schema, 'Path Settings');
addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints'])); addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
addGroupInfo(schema, 'Path Points Settings'); addGroupInfo(schema, 'Path Points Settings');
addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon'])); const mapPolygonSchemaWithoutEdit = mapPolygonSchema;
delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon;
mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1);
addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon']));
addGroupInfo(schema, 'Polygon Settings'); addGroupInfo(schema, 'Polygon Settings');
return schema; return schema;
} }
@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
rotationAngle: 0 rotationAngle: 0
}; };
this.settings = { ...settings, ...this.ctx.settings }; this.settings = { ...settings, ...this.ctx.settings };
this.settings.editablePolygon = false;
this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);

4
ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts

@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges-
import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component';
import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component';
import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component';
import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi
NavigationCardsWidgetComponent, NavigationCardsWidgetComponent,
NavigationCardWidgetComponent, NavigationCardWidgetComponent,
QrCodeWidgetComponent, QrCodeWidgetComponent,
MarkdownWidgetComponent MarkdownWidgetComponent,
SelectEntityDialogComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,

1
ui-ngx/src/assets/add_location.svg

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 219 B

3
ui-ngx/src/assets/add_polygon.svg

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
<polygon points="2,46 46,46 24,2" style="fill:transparent;stroke:black;stroke-width:2"/>
</svg>

Before

Width:  |  Height:  |  Size: 182 B

35
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3238,7 +3238,40 @@
"update-timeseries": "Update timeseries", "update-timeseries": "Update timeseries",
"value": "Value" "value": "Value"
}, },
"invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type" "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type",
"maps": {
"select-entity": "Select entity",
"select-entity-hint": "Hint: after selection click at the map to set position",
"tooltips": {
"placeMarker": "Click to place marker",
"firstVertex": "Click to place first point",
"continueLine": "Click to continue drawing",
"finishLine": "Click any existing marker to finish",
"finishPoly": "Click first marker to finish and save",
"finishRect": "Click to finish and save",
"startCircle": "Click to place circle center",
"finishCircle": "Click to finish circle",
"placeCircleMarker": "Click to place circle marker"
},
"actions": {
"finish": "Finish",
"cancel": "Cancel",
"removeLastVertex": "Remove last point"
},
"buttonTitles": {
"drawMarkerButton": "Create marker",
"drawPolyButton": "Create polygon",
"drawLineButton": "Create Polyline",
"drawCircleButton": "Create Circle",
"drawRectButton": "Create rectangle",
"editButton": "Edit mode",
"dragButton": "Drag-drop mode",
"cutButton": "Cut polygon area",
"deleteButton": "Remove",
"drawCircleMarkerButton": "Create circle marker",
"rotateButton": "Rotate polygon"
}
}
}, },
"icon": { "icon": {
"icon": "Icon", "icon": "Icon",

BIN
ui-ngx/src/assets/shadow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

2
ui-ngx/src/tsconfig.app.json

@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/app", "outDir": "../out-tsc/app",
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify",
"react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet.markercluster", "leaflet-editable"] "react", "react-dom", "jstree", "raphael", "canvas-gauges"]
}, },
"angularCompilerOptions": { "angularCompilerOptions": {
"fullTemplateTypeCheck": true "fullTemplateTypeCheck": true

18
ui-ngx/src/typings/add-marker.d.ts → ui-ngx/src/typings/leaflet-geoman-extend.d.ts

@ -17,15 +17,13 @@
import * as L from 'leaflet'; import * as L from 'leaflet';
declare module 'leaflet' { declare module 'leaflet' {
namespace PM {
namespace Control { interface PMMapToolbar {
class AddMarker extends L.Control { } toggleButton(
class AddPolygon extends L.Control { } name: string,
} status: boolean,
disableOthers?: boolean
namespace control { ): void;
function addMarker(options): Control.AddMarker;
function addPolygon(options): Control.AddPolygon;
} }
}
} }

3
ui-ngx/tsconfig.json

@ -20,7 +20,8 @@
"src/typings/jquery.flot.typings.d.ts", "src/typings/jquery.flot.typings.d.ts",
"src/typings/jquery.jstree.typings.d.ts", "src/typings/jquery.jstree.typings.d.ts",
"src/typings/split.js.typings.d.ts", "src/typings/split.js.typings.d.ts",
"src/typings/add-marker.d.ts" "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.d.ts",
"src/typings/leaflet-geoman-extend.d.ts"
], ],
"paths": { "paths": {
"@app/*": ["src/app/*"], "@app/*": ["src/app/*"],

282
ui-ngx/yarn.lock

@ -1422,6 +1422,18 @@
"@types/flowjs" "2.13.3" "@types/flowjs" "2.13.3"
tslib "^1.9.0" tslib "^1.9.0"
"@geoman-io/leaflet-geoman-free@^2.11.3":
version "2.11.3"
resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36"
integrity sha512-LsiurEgKEHBcTnAVl8h7EfS5V/doCuxePzPE9SnfrhtJBN7IzP6UwkEo35Agwko+BnIuw/o2bE4F7irvKwQzjw==
dependencies:
"@turf/boolean-contains" "6.3.0"
"@turf/kinks" "6.3.0"
"@turf/line-intersect" "6.3.0"
"@turf/line-split" "6.3.0"
lodash "4.17.21"
polygon-clipping "0.15.3"
"@istanbuljs/schema@^0.1.2": "@istanbuljs/schema@^0.1.2":
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
@ -1688,6 +1700,167 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
"@turf/bbox@*", "@turf/bbox@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5"
integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/meta" "^6.5.0"
"@turf/bearing@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/bearing/-/bearing-6.5.0.tgz#462a053c6c644434bdb636b39f8f43fb0cd857b0"
integrity sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/boolean-contains@6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.3.0.tgz#fe4fc359e408c8c3c89e7fb159c9d31fde48779a"
integrity sha512-1MW7B5G5tIu1lnAv3pXyFzl75wfBYnbA2GhwHDb4okIXMhloy/r5uIqAZHo0fOXykKVJS/gIfA/MioKIftoTug==
dependencies:
"@turf/bbox" "^6.3.0"
"@turf/boolean-point-in-polygon" "^6.3.0"
"@turf/boolean-point-on-line" "^6.3.0"
"@turf/helpers" "^6.3.0"
"@turf/invariant" "^6.3.0"
"@turf/boolean-point-in-polygon@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz#6d2e9c89de4cd2e4365004c1e51490b7795a63cf"
integrity sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/boolean-point-on-line@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz#a8efa7bad88760676f395afb9980746bc5b376e9"
integrity sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/destination@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/destination/-/destination-6.5.0.tgz#30a84702f9677d076130e0440d3223ae503fdae1"
integrity sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/distance@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.5.0.tgz#21f04d5f86e864d54e2abde16f35c15b4f36149a"
integrity sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/helpers@6.x", "@turf/helpers@^6.3.0", "@turf/helpers@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e"
integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==
"@turf/invariant@^6.3.0", "@turf/invariant@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.5.0.tgz#970afc988023e39c7ccab2341bd06979ddc7463f"
integrity sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/kinks@6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@turf/kinks/-/kinks-6.3.0.tgz#a16b4ccc5a5aae139d43e36271e0a0494fdb4bf7"
integrity sha512-BLWvbl2/fa4SeJzVMbleT6Vo1cmzwmzRfxL2xxMei2jmf6JSvqDoMJFwIHGXrLZXvhOCb1b2C+MhBfhtc7kYkQ==
dependencies:
"@turf/helpers" "^6.3.0"
"@turf/line-intersect@6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.3.0.tgz#726a50edc66bb7b5e798b052b103fb0da4d1c4f4"
integrity sha512-3naxR7XpkPd2vst3Mw6DFry4C9m3o0/f2n/xu5UAyxb88Ie4m2k+1eqkhzMMx/0L+E6iThWpLx7DASM6q6o9ow==
dependencies:
"@turf/helpers" "^6.3.0"
"@turf/invariant" "^6.3.0"
"@turf/line-segment" "^6.3.0"
"@turf/meta" "^6.3.0"
geojson-rbush "3.x"
"@turf/line-intersect@^6.3.0", "@turf/line-intersect@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz#dea48348b30c093715d2195d2dd7524aee4cf020"
integrity sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/line-segment" "^6.5.0"
"@turf/meta" "^6.5.0"
geojson-rbush "3.x"
"@turf/line-segment@^6.3.0", "@turf/line-segment@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/line-segment/-/line-segment-6.5.0.tgz#ee73f3ffcb7c956203b64ed966d96af380a4dd65"
integrity sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/meta" "^6.5.0"
"@turf/line-split@6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@turf/line-split/-/line-split-6.3.0.tgz#ee218f66cd65ce84eafc4956c24083663f6082ea"
integrity sha512-Q0nUJ0vczy11piyEz0FaKScFwSQtb1HJ2RPEMCw1coUJhTCB02KBWQLImhYqwsD3uLg+H/fxaJ1Gva6EPWoDNQ==
dependencies:
"@turf/bbox" "^6.3.0"
"@turf/helpers" "^6.3.0"
"@turf/invariant" "^6.3.0"
"@turf/line-intersect" "^6.3.0"
"@turf/line-segment" "^6.3.0"
"@turf/meta" "^6.3.0"
"@turf/nearest-point-on-line" "^6.3.0"
"@turf/square" "^6.3.0"
"@turf/truncate" "^6.3.0"
geojson-rbush "3.x"
"@turf/meta@6.x", "@turf/meta@^6.3.0", "@turf/meta@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca"
integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/nearest-point-on-line@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz#8e1cd2cdc0b5acaf4c8d8b3b33bb008d3cb99e7b"
integrity sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==
dependencies:
"@turf/bearing" "^6.5.0"
"@turf/destination" "^6.5.0"
"@turf/distance" "^6.5.0"
"@turf/helpers" "^6.5.0"
"@turf/invariant" "^6.5.0"
"@turf/line-intersect" "^6.5.0"
"@turf/meta" "^6.5.0"
"@turf/square@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/square/-/square-6.5.0.tgz#ab43eef99d39c36157ab5b80416bbeba1f6b2122"
integrity sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==
dependencies:
"@turf/distance" "^6.5.0"
"@turf/helpers" "^6.5.0"
"@turf/truncate@^6.3.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/truncate/-/truncate-6.5.0.tgz#c3a16cad959f1be1c5156157d5555c64b19185d8"
integrity sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/meta" "^6.5.0"
"@types/canvas-gauges@^2.1.2": "@types/canvas-gauges@^2.1.2":
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210" resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210"
@ -1725,6 +1898,11 @@
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==
"@types/geojson@7946.0.8":
version "7946.0.8"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
"@types/glob@^7.1.1": "@types/glob@^7.1.1":
version "7.1.3" version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
@ -1791,34 +1969,48 @@
dependencies: dependencies:
"@types/jquery" "*" "@types/jquery" "*"
"@types/leaflet-editable@^1.2.1": "@types/leaflet-polylinedecorator@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.1.tgz#b6522f9dae52146bf73da249e4bedfbab200c6e4"
integrity sha512-9etweJ2U4SWqcV/AR3i0NdWJByeMn6+zMUNlO6jVbpL8UI6qrMKybu8v9/s6UR4oXvsV4lZT6vzAsNAAMq5Ssg==
dependencies:
"@types/leaflet" "*"
"@types/leaflet-providers@^1.2.1":
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/leaflet-editable/-/leaflet-editable-1.2.1.tgz#12f1bd1d9af7beafbac256216062e97fe2ee4d55" resolved "https://registry.yarnpkg.com/@types/leaflet-providers/-/leaflet-providers-1.2.1.tgz#620669b828959740a2d8572e0c0288a2382d3564"
integrity sha512-7Oms1HgulWiclkI0s1XLmr1yRylNoJX8sVUfAv9+28JzwWbKbLcQ6//vhFEOmoMlBQyL5veogKpUUb5qeF+Qyg== integrity sha512-uNyuXiNV2q3fmgNjQji2P6RjQISmL40bbOL91/3OAwiE3XhkLKPmSAtAcfe11MAIz45iEjdFZJWppq9QyfnPIw==
dependencies: dependencies:
"@types/leaflet" "*" "@types/leaflet" "*"
"@types/leaflet-polylinedecorator@^1.6.0": "@types/leaflet.gridlayer.googlemutant@^0.4.6":
version "1.6.0" version "0.4.6"
resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#1572131ffedb3154c6e18e682d2fb700e203af19" resolved "https://registry.yarnpkg.com/@types/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.4.6.tgz#86d3ba9d432dec29b4796e37d815c233680e7fcb"
integrity sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw== integrity sha512-L0J7NadcZp5bcKQrv4DVlsEbQ90xLsOKScckAMnxoghh/wogk0GVkauYOYHBKeKDkx9qkMRzTf8oO+fKeYD7oQ==
dependencies: dependencies:
"@types/leaflet" "*" "@types/leaflet" "*"
"@types/leaflet.markercluster@^1.4.4": "@types/leaflet.markercluster@^1.4.6":
version "1.4.4" version "1.4.6"
resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.4.tgz#4b4772c86182923e920061a0c25cb3e53543ad35" resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.6.tgz#1159460b374ba5e329cb678d0e427f99dca75be5"
integrity sha512-BQAilNWlBpYl4+PrsJXLOh4vyv7KfWi5kh3Fclg5y4gEeNeXKqhS6y1zzBB4+wcTuVUnMWfm2G0MfqA4yA5A5A== integrity sha512-MD+bUDzxHznY0zOlSBUAMNQUGB2+xpJPKrR2MNEoBAAKa3QTKJJySBtCqWyGLvYNNO+Cdyc2c64aF2IFwe4fcQ==
dependencies: dependencies:
"@types/leaflet" "*" "@types/leaflet" "*"
"@types/leaflet@*", "@types/leaflet@1.5.17": "@types/leaflet@*":
version "1.5.17" version "1.5.17"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b" resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b"
integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g== integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g==
dependencies: dependencies:
"@types/geojson" "*" "@types/geojson" "*"
"@types/leaflet@^1.7.6":
version "1.7.6"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.6.tgz#6580f4babb648972c5af3abc3d66866753fa9311"
integrity sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA==
dependencies:
"@types/geojson" "*"
"@types/lodash@^4.14.170": "@types/lodash@^4.14.170":
version "4.14.170" version "4.14.170"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
@ -4858,6 +5050,17 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
geojson-rbush@3.x:
version "3.2.0"
resolved "https://registry.yarnpkg.com/geojson-rbush/-/geojson-rbush-3.2.0.tgz#8b543cf0d56f99b78faf1da52bb66acad6dfc290"
integrity sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==
dependencies:
"@turf/bbox" "*"
"@turf/helpers" "6.x"
"@turf/meta" "6.x"
"@types/geojson" "7946.0.8"
rbush "^3.0.1"
get-caller-file@^2.0.1, get-caller-file@^2.0.5: get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
@ -6224,11 +6427,6 @@ klona@^2.0.4:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
leaflet-editable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/leaflet-editable/-/leaflet-editable-1.2.0.tgz#a3a01001764ba58ea923381ee6a1c814708a0b84"
integrity sha512-wG11JwpL8zqIbypTop6xCRGagMuWw68ihYu4uqrqc5Ep0wnEJeyob7NB2Rt5t74Oih4rwJ3OfwaGbzdowOGfYQ==
leaflet-polylinedecorator@^1.6.0: leaflet-polylinedecorator@^1.6.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#9ef79fd1b5302d67b72efe959a8ecd2553f27266" resolved "https://registry.yarnpkg.com/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#9ef79fd1b5302d67b72efe959a8ecd2553f27266"
@ -6236,25 +6434,25 @@ leaflet-polylinedecorator@^1.6.0:
dependencies: dependencies:
leaflet-rotatedmarker "^0.2.0" leaflet-rotatedmarker "^0.2.0"
leaflet-providers@^1.12.0: leaflet-providers@^1.13.0:
version "1.12.0" version "1.13.0"
resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.12.0.tgz#bf407f580d9564480e2346bc1e6412ef696624cf" resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-1.13.0.tgz#10c843a23d5823a65096d40ad53f27029e13434b"
integrity sha512-pU/mR4B+NbayBGCg5/88dmRq7t1EGiNPhsVGV3yqHuDn594vIwus4CiPVW0RtiKJNKg8Vf1pILAbFl0i+yk+lQ== integrity sha512-f/sN5wdgBbVA2jcCYzScIfYNxKdn2wBJP9bu+5cRX9Xj6g8Bt1G9Sr8WgJAt/ckIFIc3LVVxCBNFpSCfTuUElg==
leaflet-rotatedmarker@^0.2.0: leaflet-rotatedmarker@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277" resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277"
integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc= integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc=
leaflet.gridlayer.googlemutant@0.10.2: leaflet.gridlayer.googlemutant@0.13.4:
version "0.10.2" version "0.13.4"
resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.10.2.tgz#3c5351db4230beac1b1ea1f774d9288cfb0b6283" resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.13.4.tgz#0add37d240c70c999e1f1d341208e6fea2372c40"
integrity sha512-r3le0W8izKmF2aeCCYp6P+dLQvPadV/vpJkres0ltDHiWac6qt3fQPNWjQl+8WCsCmcGTb1y5bmHOx0Yj6HA7g== integrity sha512-oC6xUSFJ9HP4WIupXakgiYckdBHuHQeSaxTXsVlcvcpfsuYoJ/HFIrz1bmK4Qr/qKO4fY1MDM6AoewU7Bph8ZQ==
leaflet.markercluster@^1.5.0: leaflet.markercluster@^1.5.3:
version "1.5.0" version "1.5.3"
resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.0.tgz#54db42485da32fc3d92c7ae22d0d7982879e0b67" resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz#9cdb52a4eab92671832e1ef9899669e80efc4056"
integrity sha512-Fvf/cq4o806mJL50n+fZW9+QALDDLPvt7vuAjlD2vfnxx3srMDs2vWINJze4nKYJYRY45OC6tM/669C3pLwMCA== integrity sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==
leaflet@^1.7.1: leaflet@^1.7.1:
version "1.7.1" version "1.7.1"
@ -6365,7 +6563,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21: lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -7651,6 +7849,13 @@ pnp-webpack-plugin@1.6.4:
dependencies: dependencies:
ts-pnp "^1.1.6" ts-pnp "^1.1.6"
polygon-clipping@0.15.3:
version "0.15.3"
resolved "https://registry.yarnpkg.com/polygon-clipping/-/polygon-clipping-0.15.3.tgz#0215840438470ba2e9e6593625e4ea5c1087b4b7"
integrity sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==
dependencies:
splaytree "^3.1.0"
popper.js@1.16.1-lts: popper.js@1.16.1-lts:
version "1.16.1-lts" version "1.16.1-lts"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
@ -8191,6 +8396,11 @@ querystringify@^2.1.1:
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
quickselect@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
raf@^3.4.0, raf@^3.4.1: raf@^3.4.0, raf@^3.4.1:
version "3.4.1" version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
@ -8243,6 +8453,13 @@ raw-loader@4.0.2:
loader-utils "^2.0.0" loader-utils "^2.0.0"
schema-utils "^3.0.0" schema-utils "^3.0.0"
rbush@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf"
integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
dependencies:
quickselect "^2.0.0"
rc-align@^4.0.0: rc-align@^4.0.0:
version "4.0.8" version "4.0.8"
resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668" resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668"
@ -9298,6 +9515,11 @@ speed-measure-webpack-plugin@1.4.2:
dependencies: dependencies:
chalk "^4.1.0" chalk "^4.1.0"
splaytree@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/splaytree/-/splaytree-3.1.0.tgz#17d4a0108a6da3627579690b7b847241e18ddec8"
integrity sha512-gvUGR7xnOy0fLKTCxDeUZYgU/I1Tdf8M/lM1Qrf8L2TIOR5ipZjGk02uYcdv0o2x7WjVRgpm3iS2clLyuVAt0Q==
split-string@^3.0.1, split-string@^3.0.2: split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"

Loading…
Cancel
Save