diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index a85fa0aa08..f71967800f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -30,6 +30,7 @@ import 'leaflet.markercluster/dist/leaflet.markercluster'; import { defaultSettings, FormattedData, + MapProviders, MapSettings, MarkerSettings, PolygonSettings, @@ -74,6 +75,8 @@ export default abstract class LeafletMap { drawRoutes: boolean; showPolygon: boolean; updatePending = false; + addMarkers: L.Marker[] = []; + addPolygons: L.Polygon[] = []; protected constructor(public ctx: WidgetContext, public $container: HTMLElement, @@ -133,6 +136,7 @@ export default abstract class LeafletMap { shadowSize: [41, 41] }); const newMarker = L.marker(mousePositionOnMap, { icon }).addTo(this.map); + this.addMarkers.push(newMarker); const datasourcesList = document.createElement('div'); const customLatLng = this.convertToCustomFormat(mousePositionOnMap); const header = document.createElement('p'); @@ -147,6 +151,10 @@ export default abstract class LeafletMap { const updatedEnttity = { ...ds, ...customLatLng }; this.saveMarkerLocation(updatedEnttity).subscribe(() => { this.map.removeLayer(newMarker); + const markerIndex = this.addMarkers.indexOf(newMarker); + if (markerIndex > -1) { + this.addMarkers.splice(markerIndex, 1); + } this.deleteMarker(ds.entityName); this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options); }); @@ -158,6 +166,10 @@ export default abstract class LeafletMap { 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.append(deleteBtn); const popup = L.popup(); @@ -196,14 +208,16 @@ export default abstract class LeafletMap { let mousePositionOnMap: L.LatLng[]; let addPolygon: L.Control; this.map.on('mousemove', (e: L.LeafletMouseEvent) => { + const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01; const latlng1 = e.latlng; - const latlng2 = L.latLng(e.latlng.lat, e.latlng.lng + 10); - const latlng3 = L.latLng(e.latlng.lat - 10, e.latlng.lng); + const latlng2 = L.latLng(e.latlng.lat, e.latlng.lng + polygonOffset); + const latlng3 = L.latLng(e.latlng.lat - polygonOffset, e.latlng.lng); mousePositionOnMap = [latlng1, latlng2, latlng3]; }); const dragListener = (e: L.DragEndEvent) => { if (e.type === 'dragend' && mousePositionOnMap) { const newPolygon = L.polygon(mousePositionOnMap).addTo(this.map); + this.addPolygons.push(newPolygon); const datasourcesList = document.createElement('div'); const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(mousePositionOnMap)}; const header = document.createElement('p'); @@ -218,6 +232,10 @@ export default abstract class LeafletMap { 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); }); }; @@ -228,6 +246,10 @@ export default abstract class LeafletMap { 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.append(deleteBtn); const popup = L.popup(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index f289fcfeed..1b20ddad01 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -26,7 +26,7 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { WidgetSubscriptionOptions } from '@core/api/widget-api.models'; import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; -const maxZoom = 4;// ? +const maxZoom = 4; // ? export class ImageMap extends LeafletMap { @@ -162,52 +162,64 @@ export class ImageMap extends LeafletMap { } onResize(updateImage?: boolean) { - let width = this.$container.clientWidth; - if (width > 0 && this.aspect) { - let height = width / this.aspect; - const imageMapHeight = this.$container.clientHeight; - if (imageMapHeight > 0 && height > imageMapHeight) { - height = imageMapHeight; - width = height * this.aspect; - } - width *= maxZoom; - const prevWidth = this.width; - const prevHeight = this.height; - if (this.width !== width || updateImage) { - this.width = width; - this.height = width / this.aspect; - if (!this.map) { - this.initMap(updateImage); - } else { - const lastCenterPos = this.latLngToPoint(this.map.getCenter()); - lastCenterPos.x /= prevWidth; - lastCenterPos.y /= prevHeight; - this.updateBounds(updateImage, lastCenterPos); - this.map.invalidateSize(true); - this.updateMarkers(this.markersData); - this.updatePolygons(this.polygonsData); - } - } + let width = this.$container.clientWidth; + if (width > 0 && this.aspect) { + let height = width / this.aspect; + const imageMapHeight = this.$container.clientHeight; + if (imageMapHeight > 0 && height > imageMapHeight) { + height = imageMapHeight; + width = height * this.aspect; } + width *= maxZoom; + const prevWidth = this.width; + const prevHeight = this.height; + if (this.width !== width || updateImage) { + this.width = width; + this.height = width / this.aspect; + if (!this.map) { + this.initMap(updateImage); + } else { + const lastCenterPos = this.latLngToPoint(this.map.getCenter()); + lastCenterPos.x /= prevWidth; + lastCenterPos.y /= prevHeight; + this.updateBounds(updateImage, lastCenterPos); + this.map.invalidateSize(true); + this.updateMarkers(this.markersData); + if (this.options.draggableMarker && this.addMarkers.length) { + this.addMarkers.forEach((marker) => { + const prevPoint = this.convertToCustomFormat(marker.getLatLng(), prevWidth, prevHeight); + marker.setLatLng(this.convertPosition(prevPoint)); + }); + } + this.updatePolygons(this.polygonsData); + if (this.options.showPolygon && this.options.editablePolygon && this.addPolygons.length) { + this.addPolygons.forEach((polygon) => { + const prevPolygonPoint = this.convertToPolygonFormat(polygon.getLatLngs(), prevWidth, prevHeight); + polygon.setLatLngs(this.convertPositionPolygon(prevPolygonPoint)); + }); + } + } + } + } } fitBounds(bounds: LatLngBounds, padding?: LatLngTuple) { } initMap(updateImage?: boolean) { - if (!this.map && this.aspect > 0) { - const center = this.pointToLatLng(this.width / 2, this.height / 2); - this.map = L.map(this.$container, { - minZoom: 1, - maxZoom, - scrollWheelZoom: !this.options.disableScrollZooming, - center, - zoom: 1, - crs: L.CRS.Simple, - attributionControl: false, - editable: !!this.options.editablePolygon - }); - this.updateBounds(updateImage); - } + if (!this.map && this.aspect > 0) { + const center = this.pointToLatLng(this.width / 2, this.height / 2); + this.map = L.map(this.$container, { + minZoom: 1, + maxZoom, + scrollWheelZoom: !this.options.disableScrollZooming, + center, + zoom: 1, + crs: L.CRS.Simple, + attributionControl: false, + editable: !!this.options.editablePolygon + }); + this.updateBounds(updateImage); + } } convertPosition(expression): L.LatLng { @@ -227,13 +239,14 @@ export class ImageMap extends LeafletMap { if (!Array.isArray(el[0]) && !Array.isArray(el[1]) && el.length === 2) { return this.pointToLatLng( el[0] * this.width, - el[1] * this.height) + el[1] * this.height + ); } else if (Array.isArray(el) && el.length) { return this.convertPositionPolygon(el as LatLngTuple[] | LatLngTuple[][]); } else { return null; } - }).filter(el => !!el) + }).filter(el => !!el); } pointToLatLng(x, y): L.LatLng { @@ -244,32 +257,32 @@ export class ImageMap extends LeafletMap { return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); } - convertToCustomFormat(position: L.LatLng): object { - const point = this.latLngToPoint(position); - return { - [this.options.xPosKeyName]: calculateNewPointCoordinate(point.x, this.width), - [this.options.yPosKeyName]: calculateNewPointCoordinate(point.y, this.height) - } + convertToCustomFormat(position: L.LatLng, width = this.width, height = this.height): object { + const point = this.latLngToPoint(position); + return { + [this.options.xPosKeyName]: calculateNewPointCoordinate(point.x, width), + [this.options.yPosKeyName]: calculateNewPointCoordinate(point.y, height) + }; } - convertToPolygonFormat(points: Array): Array { + convertToPolygonFormat(points: Array, width = this.width, height = this.height): Array { if (points.length) { - return points.map(point=> { + return points.map(point => { if (point.length) { - return this.convertToPolygonFormat(point); + return this.convertToPolygonFormat(point, width, height); } else { const pos = this.latLngToPoint(point); - return [calculateNewPointCoordinate(pos.x, this.width), calculateNewPointCoordinate(pos.y, this.height)]; + return [calculateNewPointCoordinate(pos.x, width), calculateNewPointCoordinate(pos.y, height)]; } - }) + }); } else { - return [] + return []; } } convertPolygonToCustomFormat(expression: any[][]): object { return { [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) - } + }; } }