|
|
|
@ -21,6 +21,7 @@ import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markerclu |
|
|
|
import '@geoman-io/leaflet-geoman-free'; |
|
|
|
|
|
|
|
import { |
|
|
|
CircleData, |
|
|
|
defaultSettings, |
|
|
|
FormattedData, |
|
|
|
MapSettings, |
|
|
|
@ -36,7 +37,8 @@ import { Marker } from './markers'; |
|
|
|
import { Observable, of } from 'rxjs'; |
|
|
|
import { Polyline } from './polyline'; |
|
|
|
import { Polygon } from './polygon'; |
|
|
|
import { createTooltip } from '@home/components/widget/lib/maps/maps-utils'; |
|
|
|
import { Circle } from './circle'; |
|
|
|
import { createTooltip, isCutPolygon, isJSON } from '@home/components/widget/lib/maps/maps-utils'; |
|
|
|
import { |
|
|
|
checkLngLat, |
|
|
|
createLoadingDiv, |
|
|
|
@ -45,19 +47,21 @@ import { |
|
|
|
safeExecute |
|
|
|
} from '@home/components/widget/lib/maps/common-maps-utils'; |
|
|
|
import { WidgetContext } from '@home/models/widget-component.models'; |
|
|
|
import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; |
|
|
|
import { deepClone, isDefinedAndNotNull, isNotEmptyStr, 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 ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; |
|
|
|
|
|
|
|
export default abstract class LeafletMap { |
|
|
|
|
|
|
|
markers: Map<string, Marker> = new Map(); |
|
|
|
polylines: Map<string, Polyline> = new Map(); |
|
|
|
polygons: Map<string, Polygon> = new Map(); |
|
|
|
circles: Map<string, Circle> = new Map(); |
|
|
|
map: L.Map; |
|
|
|
options: UnitedMapSettings; |
|
|
|
bounds: L.LatLngBounds; |
|
|
|
@ -66,22 +70,25 @@ export default abstract class LeafletMap { |
|
|
|
points: FeatureGroup; |
|
|
|
markersData: FormattedData[] = []; |
|
|
|
polygonsData: FormattedData[] = []; |
|
|
|
circleData: FormattedData[] = []; |
|
|
|
defaultMarkerIconInfo: MarkerIconInfo; |
|
|
|
loadingDiv: JQuery<HTMLElement>; |
|
|
|
loading = false; |
|
|
|
replaceInfoLabelMarker: Array<ReplaceInfo> = []; |
|
|
|
markerLabelText: string; |
|
|
|
polygonLabelText: string; |
|
|
|
circleLabelText: string; |
|
|
|
replaceInfoLabelPolygon: Array<ReplaceInfo> = []; |
|
|
|
replaceInfoTooltipMarker: Array<ReplaceInfo> = []; |
|
|
|
replaceInfoTooltipCircle: Array<ReplaceInfo> = []; |
|
|
|
markerTooltipText: string; |
|
|
|
drawRoutes: boolean; |
|
|
|
showPolygon: boolean; |
|
|
|
updatePending = false; |
|
|
|
editPolygons = false; |
|
|
|
editCircle = false; |
|
|
|
selectedEntity: FormattedData; |
|
|
|
addMarkers: L.Marker[] = []; |
|
|
|
addPolygons: L.Polygon[] = []; |
|
|
|
ignoreUpdateBounds = false; |
|
|
|
// tslint:disable-next-line:no-string-literal
|
|
|
|
southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); |
|
|
|
// tslint:disable-next-line:no-string-literal
|
|
|
|
@ -90,12 +97,14 @@ export default abstract class LeafletMap { |
|
|
|
saveMarkerLocation: (e: FormattedData, lat?: number, lng?: number) => Observable<any>; |
|
|
|
savePolygonLocation: (e: FormattedData, coordinates?: Array<any>) => Observable<any>; |
|
|
|
translateService: TranslateService; |
|
|
|
tooltipInstances: ITooltipsterInstance[] = []; |
|
|
|
|
|
|
|
protected constructor(public ctx: WidgetContext, |
|
|
|
public $container: HTMLElement, |
|
|
|
options: UnitedMapSettings) { |
|
|
|
this.options = options; |
|
|
|
this.editPolygons = options.showPolygon && options.editablePolygon; |
|
|
|
this.editCircle = options.showCircle && options.editableCircle; |
|
|
|
L.Icon.Default.imagePath = '/'; |
|
|
|
this.translateService = this.ctx.$injector.get(TranslateService); |
|
|
|
} |
|
|
|
@ -151,6 +160,9 @@ export default abstract class LeafletMap { |
|
|
|
case 'Marker': |
|
|
|
entities = this.datasources.filter(mData => !this.convertPosition(mData)); |
|
|
|
break; |
|
|
|
case 'Circle': |
|
|
|
entities = this.datasources.filter(mData => !this.isValidCircle(mData)); |
|
|
|
break; |
|
|
|
default: |
|
|
|
return of(null); |
|
|
|
} |
|
|
|
@ -181,6 +193,16 @@ export default abstract class LeafletMap { |
|
|
|
// @ts-ignore
|
|
|
|
this.map.pm.Draw.tbMarker._hintMarker.setTooltipContent(tooltipText); |
|
|
|
break; |
|
|
|
case 'tbCircle': |
|
|
|
tooltipText = this.translateService.instant('widgets.maps.tooltips.startCircle', {entityName: data.entityName}); |
|
|
|
// @ts-ignore
|
|
|
|
this.map.pm.Draw.tbCircle._hintMarker.setTooltipContent(tooltipText); |
|
|
|
customTranslation = { |
|
|
|
tooltips: { |
|
|
|
finishCircle: this.translateService.instant('widgets.maps.tooltips.finishCircle', {entityName: data.entityName}) |
|
|
|
} |
|
|
|
}; |
|
|
|
break; |
|
|
|
case 'tbRectangle': |
|
|
|
tooltipText = this.translateService.instant('widgets.maps.tooltips.firstVertex', {entityName: data.entityName}); |
|
|
|
// @ts-ignore
|
|
|
|
@ -190,7 +212,6 @@ export default abstract class LeafletMap { |
|
|
|
finishRect: this.translateService.instant('widgets.maps.tooltips.finishRect', {entityName: data.entityName}) |
|
|
|
} |
|
|
|
}; |
|
|
|
this.map.pm.setLang('en', customTranslation, 'en'); |
|
|
|
break; |
|
|
|
case 'tbPolygon': |
|
|
|
tooltipText = this.translateService.instant('widgets.maps.tooltips.firstVertex', {entityName: data.entityName}); |
|
|
|
@ -202,9 +223,12 @@ export default abstract class LeafletMap { |
|
|
|
finishPoly: this.translateService.instant('widgets.maps.tooltips.finishPoly', {entityName: data.entityName}) |
|
|
|
} |
|
|
|
}; |
|
|
|
this.map.pm.setLang('en', customTranslation); |
|
|
|
break; |
|
|
|
} |
|
|
|
if (customTranslation) { |
|
|
|
this.map.pm.setLang('en', customTranslation, 'en'); |
|
|
|
this.createdControlButtonTooltip(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
// @ts-ignore
|
|
|
|
this.map.pm.Toolbar.toggleButton(type, false); |
|
|
|
@ -265,6 +289,48 @@ export default abstract class LeafletMap { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// Customize edit circle
|
|
|
|
if (this.editCircle && !this.options.hideDrawControlButton) { |
|
|
|
const actions = [{ |
|
|
|
text: L.PM.Utils.getTranslation('actions.cancel'), |
|
|
|
onClick: () => this.toggleDrawMode('tbCircle') |
|
|
|
}]; |
|
|
|
|
|
|
|
this.map.pm.Toolbar.copyDrawControl('Circle', { |
|
|
|
name: 'tbCircle', |
|
|
|
afterClick: () => this.selectEntityWithoutLocation('tbCircle'), |
|
|
|
disabled: true, |
|
|
|
actions |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
if (this.editPolygons && !this.options.hideEditControlButton) { |
|
|
|
this.map.pm.Toolbar.copyDrawControl('cutPolygon', { |
|
|
|
name: 'tbCut', |
|
|
|
title: this.translateService.instant('widgets.maps.buttonTitles.cutButton'), |
|
|
|
block: 'edit', |
|
|
|
onClick: () => { |
|
|
|
this.map.pm.setLang('en', { |
|
|
|
tooltips: { |
|
|
|
firstVertex: this.translateService.instant('widgets.maps.tooltips.firstVertex-cut'), |
|
|
|
continueLine: this.translateService.instant('widgets.maps.tooltips.continueLine-cut'), |
|
|
|
finishPoly: this.translateService.instant('widgets.maps.tooltips.finishPoly-cut') |
|
|
|
} |
|
|
|
}, 'en'); |
|
|
|
this.createdControlButtonTooltip(); |
|
|
|
}, |
|
|
|
// @ts-ignore
|
|
|
|
afterClick: (e, ctx) => { |
|
|
|
this.map.pm.Draw[ctx.button._button.jsClass].toggle({ |
|
|
|
snappable: this.options.snappable, |
|
|
|
cursorMarker: true, |
|
|
|
allowSelfIntersection: false, |
|
|
|
}); |
|
|
|
}, |
|
|
|
}); |
|
|
|
this.map.pm.Toolbar.changeControlOrder(['tbMarker', 'tbRectangle', 'tbPolygon', 'tbCircle', 'editMode', 'dragMode', 'tbCut', 'removalMode', 'rotateMode']); |
|
|
|
} |
|
|
|
|
|
|
|
this.map.pm.setLang('en', this.translateService.instant('widgets.maps'), 'en'); |
|
|
|
if (!this.options.hideAllControlButton) { |
|
|
|
this.map.pm.addControls({ |
|
|
|
@ -277,8 +343,8 @@ export default abstract class LeafletMap { |
|
|
|
drawPolyline: false, |
|
|
|
drawPolygon: false, |
|
|
|
dragMode: !this.options.hideEditControlButton, |
|
|
|
editMode: this.editPolygons && !this.options.hideEditControlButton, |
|
|
|
cutPolygon: this.editPolygons && !this.options.hideEditControlButton, |
|
|
|
editMode: (this.editPolygons || this.editCircle) && !this.options.hideEditControlButton, |
|
|
|
cutPolygon: false, |
|
|
|
removalMode: !this.options.hideRemoveControlButton, |
|
|
|
rotateMode: this.editPolygons && !this.options.hideEditControlButton |
|
|
|
}); |
|
|
|
@ -286,25 +352,39 @@ export default abstract class LeafletMap { |
|
|
|
|
|
|
|
if (this.options.initDragMode) { |
|
|
|
this.map.pm.enableGlobalDragMode(); |
|
|
|
this.ignoreUpdateBounds = true; |
|
|
|
} |
|
|
|
|
|
|
|
this.map.on('pm:globaldrawmodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
this.map.on('pm:globaleditmodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
this.map.on('pm:globaldragmodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
this.map.on('pm:globalremovalmodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
this.map.on('pm:globalcutmodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
this.map.on('pm:globalrotatemodetoggled', (e) => this.ignoreUpdateBounds = e.enabled); |
|
|
|
|
|
|
|
this.map.on('pm:create', (e) => { |
|
|
|
if (e.shape === 'tbMarker') { |
|
|
|
// @ts-ignore
|
|
|
|
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => { |
|
|
|
}); |
|
|
|
} else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') { |
|
|
|
let coordinates; |
|
|
|
if (e.shape === 'tbRectangle') { |
|
|
|
switch (e.shape) { |
|
|
|
case 'tbMarker': |
|
|
|
// @ts-ignore
|
|
|
|
const bounds: L.LatLngBounds = e.layer.getBounds(); |
|
|
|
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()]; |
|
|
|
} else { |
|
|
|
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {}); |
|
|
|
break; |
|
|
|
case 'tbRectangle': |
|
|
|
case 'tbPolygon': |
|
|
|
let coordinates; |
|
|
|
if (e.shape === 'tbRectangle') { |
|
|
|
// @ts-ignore
|
|
|
|
const bounds: L.LatLngBounds = e.layer.getBounds(); |
|
|
|
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()]; |
|
|
|
} else { |
|
|
|
// @ts-ignore
|
|
|
|
coordinates = e.layer.getLatLngs()[0]; |
|
|
|
} |
|
|
|
this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); |
|
|
|
break; |
|
|
|
case 'tbCircle': |
|
|
|
// @ts-ignore
|
|
|
|
coordinates = e.layer.getLatLngs()[0]; |
|
|
|
} |
|
|
|
this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => { |
|
|
|
}); |
|
|
|
this.saveLocation(this.selectedEntity, this.convertCircleToCustomFormat(e.layer.getLatLng(), e.layer.getRadius())) |
|
|
|
.subscribe(() => {}); |
|
|
|
} |
|
|
|
// @ts-ignore
|
|
|
|
e.layer._pmTempLayer = true; |
|
|
|
@ -342,6 +422,13 @@ export default abstract class LeafletMap { |
|
|
|
result = iterator.next(); |
|
|
|
} |
|
|
|
this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {}); |
|
|
|
} else if (e.shape === 'Circle') { |
|
|
|
const iterator = this.circles.values(); |
|
|
|
let result = iterator.next(); |
|
|
|
while (!result.done && e.layer !== result.value.leafletCircle) { |
|
|
|
result = iterator.next(); |
|
|
|
} |
|
|
|
this.saveLocation(result.value.data, this.convertCircleToCustomFormat(null, 0)).subscribe(() => {}); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -386,7 +473,7 @@ export default abstract class LeafletMap { |
|
|
|
if (this.options.disableScrollZooming) { |
|
|
|
this.map.scrollWheelZoom.disable(); |
|
|
|
} |
|
|
|
if (this.options.draggableMarker || this.editPolygons) { |
|
|
|
if (this.options.draggableMarker || this.editPolygons || this.editCircle) { |
|
|
|
map.pm.setGlobalOptions({ snappable: false } as L.PM.GlobalOptions); |
|
|
|
map.pm.applyGlobalOptions(); |
|
|
|
this.addEditControl(); |
|
|
|
@ -405,6 +492,12 @@ export default abstract class LeafletMap { |
|
|
|
|
|
|
|
private createdControlButtonTooltip() { |
|
|
|
import('tooltipster').then(() => { |
|
|
|
if ($.tooltipster) { |
|
|
|
this.tooltipInstances.forEach((instance) => { |
|
|
|
instance.destroy(); |
|
|
|
}); |
|
|
|
this.tooltipInstances = []; |
|
|
|
} |
|
|
|
$(this.ctx.$container) |
|
|
|
.find('a[role="button"]:not(.leaflet-pm-action)') |
|
|
|
.each((index, element) => { |
|
|
|
@ -416,7 +509,7 @@ export default abstract class LeafletMap { |
|
|
|
title = element.title; |
|
|
|
$(element).removeAttr('title'); |
|
|
|
} |
|
|
|
$(element).tooltipster( |
|
|
|
const tooltip = $(element).tooltipster( |
|
|
|
{ |
|
|
|
content: title, |
|
|
|
theme: 'tooltipster-shadow', |
|
|
|
@ -432,6 +525,7 @@ export default abstract class LeafletMap { |
|
|
|
trackOrigin: true |
|
|
|
} |
|
|
|
); |
|
|
|
this.tooltipInstances.push(tooltip.tooltipster('instance')); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -559,15 +653,18 @@ export default abstract class LeafletMap { |
|
|
|
if (showPolygon) { |
|
|
|
this.updatePolygons(formattedData, false); |
|
|
|
} |
|
|
|
if (this.options.showCircle) { |
|
|
|
this.updateCircle(formattedData, false); |
|
|
|
} |
|
|
|
this.updateMarkers(formattedData, false); |
|
|
|
this.updateBoundsInternal(); |
|
|
|
if (this.options.draggableMarker || this.editPolygons) { |
|
|
|
let foundEntityWithoutLocation = false; |
|
|
|
if (this.options.draggableMarker || this.editPolygons || this.editCircle) { |
|
|
|
let foundEntityWithLocation = false; |
|
|
|
let foundEntityWithoutPolygon = false; |
|
|
|
let foundEntityWithPolygon = false; |
|
|
|
let foundEntityWithCircle = false; |
|
|
|
|
|
|
|
if (this.options.draggableMarker && !this.options.hideDrawControlButton && !this.options.hideAllControlButton) { |
|
|
|
let foundEntityWithoutLocation = false; |
|
|
|
for (const mData of formattedData) { |
|
|
|
const position = this.convertPosition(mData); |
|
|
|
if (!position) { |
|
|
|
@ -587,6 +684,7 @@ export default abstract class LeafletMap { |
|
|
|
} |
|
|
|
|
|
|
|
if (this.editPolygons && !this.options.hideDrawControlButton && !this.options.hideAllControlButton) { |
|
|
|
let foundEntityWithoutPolygon = false; |
|
|
|
for (const pData of formattedData) { |
|
|
|
const isValidPolygon = this.isValidPolygonPosition(pData); |
|
|
|
if (!isValidPolygon) { |
|
|
|
@ -605,22 +703,47 @@ export default abstract class LeafletMap { |
|
|
|
} |
|
|
|
this.datasources = formattedData; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.editCircle && !this.options.hideDrawControlButton && !this.options.hideAllControlButton) { |
|
|
|
let foundEntityWithoutCircle = false; |
|
|
|
for (const cData of formattedData) { |
|
|
|
const isValidCircle = this.isValidCircle(cData); |
|
|
|
if (!isValidCircle) { |
|
|
|
foundEntityWithoutCircle = true; |
|
|
|
} else if (isValidCircle) { |
|
|
|
foundEntityWithCircle = true; |
|
|
|
} |
|
|
|
if (foundEntityWithoutCircle && foundEntityWithCircle) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// @ts-ignore
|
|
|
|
if (this.map.pm.Toolbar.getButtons().tbCircle.disable !== foundEntityWithoutCircle) { |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('tbCircle', !foundEntityWithoutCircle); |
|
|
|
} |
|
|
|
this.datasources = formattedData; |
|
|
|
} |
|
|
|
|
|
|
|
if (!this.options.hideRemoveControlButton && !this.options.hideAllControlButton) { |
|
|
|
const disabledButton = !foundEntityWithLocation && !foundEntityWithPolygon; |
|
|
|
const disabledButton = !foundEntityWithLocation && !foundEntityWithPolygon && !foundEntityWithCircle; |
|
|
|
if (disabledButton && this.map.pm.globalRemovalModeEnabled()) { |
|
|
|
this.map.pm.toggleGlobalRemovalMode(); |
|
|
|
} |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('removalMode', disabledButton); |
|
|
|
} |
|
|
|
if (!this.options.hideEditControlButton && !this.options.hideAllControlButton) { |
|
|
|
const disabledButton = !foundEntityWithLocation && !foundEntityWithPolygon; |
|
|
|
const disabledButton = !foundEntityWithLocation && !foundEntityWithPolygon && !foundEntityWithCircle; |
|
|
|
// @ts-ignore
|
|
|
|
if (this.map.pm.Toolbar.getButtons().dragMode.disable !== disabledButton) { |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('dragMode', disabledButton); |
|
|
|
const foundEntityWithPoly = foundEntityWithPolygon || foundEntityWithCircle; |
|
|
|
// @ts-ignore
|
|
|
|
if (this.editPolygons && this.map.pm.Toolbar.getButtons().editMode.disable !== foundEntityWithPolygon) { |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('editMode', !foundEntityWithPolygon); |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('cutPolygon', !foundEntityWithPolygon); |
|
|
|
if ((this.editPolygons || this.editCircle) && this.map.pm.Toolbar.getButtons().editMode.disable !== foundEntityWithPoly) { |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('editMode', !foundEntityWithPoly); |
|
|
|
} |
|
|
|
// @ts-ignore
|
|
|
|
if (this.editPolygons && this.map.pm.Toolbar.getButtons().tbCut.disable !== foundEntityWithPolygon) { |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('tbCut', !foundEntityWithPolygon); |
|
|
|
this.map.pm.Toolbar.setButtonDisabled('rotateMode', !foundEntityWithPolygon); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -643,6 +766,11 @@ export default abstract class LeafletMap { |
|
|
|
bounds.extend(polygon.leafletPoly.getBounds()); |
|
|
|
}); |
|
|
|
} |
|
|
|
if (this.options.showCircle) { |
|
|
|
this.circles.forEach((polygon) => { |
|
|
|
bounds.extend(polygon.leafletCircle.getBounds()); |
|
|
|
}); |
|
|
|
} |
|
|
|
if ((this.options as MarkerSettings).useClusterMarkers && this.markersCluster.getBounds().isValid()) { |
|
|
|
bounds.extend(this.markersCluster.getBounds()); |
|
|
|
} else { |
|
|
|
@ -655,7 +783,9 @@ export default abstract class LeafletMap { |
|
|
|
if (bounds.isValid() && (!this.bounds || !this.bounds.isValid() || !this.bounds.equals(bounds) |
|
|
|
&& this.options.fitMapBounds ? !mapBounds.contains(bounds) : false)) { |
|
|
|
this.bounds = bounds; |
|
|
|
this.fitBounds(bounds); |
|
|
|
if (!this.ignoreUpdateBounds) { |
|
|
|
this.fitBounds(bounds); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -797,7 +927,8 @@ export default abstract class LeafletMap { |
|
|
|
if (!this.options.pointTooltipOnRightPanel) { |
|
|
|
point.on('click', () => getTooltip(pdata, dsData)); |
|
|
|
} else { |
|
|
|
createTooltip(point, this.options, pdata.$datasource, getTooltip(pdata, dsData)); |
|
|
|
createTooltip(point, this.options, pdata.$datasource, this.options.autocloseTooltip, |
|
|
|
this.options.showTooltipAction, getTooltip(pdata, dsData)); |
|
|
|
} |
|
|
|
this.points.addLayer(point); |
|
|
|
} |
|
|
|
@ -868,7 +999,8 @@ export default abstract class LeafletMap { |
|
|
|
// Polygon
|
|
|
|
|
|
|
|
isValidPolygonPosition(data: FormattedData): boolean { |
|
|
|
return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]); |
|
|
|
return data && ((isNotEmptyStr(data[this.options.polygonKeyName]) && !isJSON(data[this.options.polygonKeyName]) |
|
|
|
|| Array.isArray(data[this.options.polygonKeyName]))); |
|
|
|
} |
|
|
|
|
|
|
|
updatePolygons(polyData: FormattedData[], updateBounds = true) { |
|
|
|
@ -908,7 +1040,7 @@ export default abstract class LeafletMap { |
|
|
|
if (coordinates.length === 1) { |
|
|
|
coordinates = coordinates[0]; |
|
|
|
} |
|
|
|
if (e.shape === 'Rectangle' && coordinates.length === 1) { |
|
|
|
if (e.shape === 'Rectangle' && !isCutPolygon(coordinates)) { |
|
|
|
// @ts-ignore
|
|
|
|
const bounds: L.LatLngBounds = e.layer.getBounds(); |
|
|
|
const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()]; |
|
|
|
@ -951,5 +1083,88 @@ export default abstract class LeafletMap { |
|
|
|
this.map.remove(); |
|
|
|
this.map = null; |
|
|
|
} |
|
|
|
this.tooltipInstances.forEach((instance) => { |
|
|
|
instance.destroy(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// Circle
|
|
|
|
isValidCircle(data: FormattedData): boolean { |
|
|
|
return data && isNotEmptyStr(data[this.options.circleKeyName]) && isJSON(data[this.options.circleKeyName]); |
|
|
|
} |
|
|
|
|
|
|
|
convertCircleToCustomFormat(expression: L.LatLng, radius: number): {[key: string]: CircleData} { |
|
|
|
let circleDara: CircleData = null; |
|
|
|
if (expression) { |
|
|
|
const position = checkLngLat(expression, this.southWest, this.northEast); |
|
|
|
circleDara = { |
|
|
|
latitude: position.lat, |
|
|
|
longitude: position.lng, |
|
|
|
radius |
|
|
|
}; |
|
|
|
} |
|
|
|
return { |
|
|
|
[this.options.circleKeyName]: circleDara |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
convertToCircleFormat(circle: CircleData): CircleData { |
|
|
|
const centerPoint = checkLngLat(new L.LatLng(circle.latitude, circle.longitude), this.southWest, this.northEast); |
|
|
|
circle.latitude = centerPoint.lat; |
|
|
|
circle.longitude = centerPoint.lng; |
|
|
|
return circle; |
|
|
|
} |
|
|
|
|
|
|
|
dragCircleVertex = (e?, data = {} as FormattedData) => { |
|
|
|
if (e === undefined) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const center = e.layer.getLatLng(); |
|
|
|
const radius = e.layer.getRadius(); |
|
|
|
this.saveLocation(data, this.convertCircleToCustomFormat(center, radius)).subscribe(() => {}); |
|
|
|
} |
|
|
|
|
|
|
|
updateCircle(circlesData: FormattedData[], updateBounds = true) { |
|
|
|
const toDelete = new Set(Array.from(this.circles.keys())); |
|
|
|
const rawCircles = circlesData.filter(cdata => this.isValidCircle(cdata)); |
|
|
|
rawCircles.forEach(data => { |
|
|
|
if (this.circles.get(data.entityName)) { |
|
|
|
this.updatedCircle(data, circlesData, updateBounds); |
|
|
|
} else { |
|
|
|
this.createdCircle(data, circlesData, updateBounds); |
|
|
|
} |
|
|
|
toDelete.delete(data.entityName); |
|
|
|
}); |
|
|
|
toDelete.forEach((key) => { |
|
|
|
this.removeCircle(key); |
|
|
|
}); |
|
|
|
this.circleData = circlesData; |
|
|
|
} |
|
|
|
|
|
|
|
updatedCircle(data: FormattedData, dataSources: FormattedData[], updateBounds = true) { |
|
|
|
const circle = this.circles.get(data.entityName); |
|
|
|
const oldBounds = circle.leafletCircle.getBounds(); |
|
|
|
circle.updateCircle(data, dataSources); |
|
|
|
const newBounds = circle.leafletCircle.getBounds(); |
|
|
|
if (updateBounds && oldBounds.toBBoxString() !== newBounds.toBBoxString()) { |
|
|
|
this.fitBounds(newBounds); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
createdCircle(data: FormattedData, dataSources: FormattedData[], updateBounds = true) { |
|
|
|
const circle = new Circle(this, data, dataSources, this.options, this.dragCircleVertex); |
|
|
|
if (updateBounds) { |
|
|
|
const bounds = circle.leafletCircle.getBounds(); |
|
|
|
this.fitBounds(bounds); |
|
|
|
} |
|
|
|
this.circles.set(data.entityName, circle); |
|
|
|
} |
|
|
|
|
|
|
|
removeCircle(name: string) { |
|
|
|
const circle = this.circles.get(name); |
|
|
|
if (circle) { |
|
|
|
this.map.removeLayer(circle.leafletCircle); |
|
|
|
this.circles.delete(name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|