diff --git a/src/modules/InteractivePoly.ts b/src/modules/InteractivePoly.ts index 2208f48..5b07d5f 100644 --- a/src/modules/InteractivePoly.ts +++ b/src/modules/InteractivePoly.ts @@ -7,9 +7,9 @@ import { divIcon, LayerGroup, LatLng, - LeafletMouseEvent, latLng, + LeafletMouseEvent, latLng, LatLngLiteral, } from 'leaflet'; -import { pointBetweenPoints, pointInArea } from "$utils/geom"; +import { distKm, getPolyLength, pointBetweenPoints, pointInArea } from "$utils/geom"; interface InteractivePolylineOptions extends PolylineOptions { maxMarkers?: number, @@ -31,6 +31,7 @@ export class Component extends Polyline { setPoints = (latlngs: LatLng[]) => { this.setLatLngs(latlngs); this.recreateMarkers(); + this.recalcDistance(); }; createHintMarker = (latlng: LatLng): Marker => marker(latlng, { @@ -50,6 +51,7 @@ export class Component extends Polyline { iconAnchor: [6, 6] }) }) + .on('contextmenu', this.dropMarker) .on('drag', this.onMarkerDrag) .on('dragstart', this.onMarkerDragStart) .on('dragend', this.onMarkerDragEnd) @@ -153,11 +155,11 @@ export class Component extends Polyline { this.hintMarker.setLatLng(latlng); }; - hideDragHint = ({ latlng }: LeafletMouseEvent): void => { + hideDragHint = (): void => { this._map.removeLayer(this.hintMarker); }; - showDragHint = ({ latlng }: LeafletMouseEvent): void => { + showDragHint = (): void => { this._map.addLayer(this.hintMarker); }; @@ -197,9 +199,7 @@ export class Component extends Polyline { stopDragHintMove = (): void => { this._map.dragging.enable(); - this.is_dragging = false; - this.constrLine.removeFrom(this._map); this._map.off('mousemove', this.dragHintMove); @@ -208,11 +208,29 @@ export class Component extends Polyline { }; dragHintAddMarker = ({ latlng }: LeafletMouseEvent): void => { - this.markers.splice((this.hint_prev_marker + 1), 0, this.createMarker(latlng)) + this.dragHintChangeDistance(this.hint_prev_marker, latlng); + + this.markers.splice((this.hint_prev_marker + 1), 0, this.createMarker(latlng)); this.insertLatLng(latlng, this.hint_prev_marker + 1); this.stopDragHintMove(); }; + dragHintChangeDistance = (index: number, current: LatLngLiteral): void => { + const prev = this.markers[index]; + const next = this.markers[index + 1]; + + const initial_distance = distKm(prev.getLatLng(), next.getLatLng()); + + const current_distance = ( + ((prev && distKm(prev.getLatLng(), current)) || 0) + + ((next && distKm(next.getLatLng(), current)) || 0) + ); + + this.distance += (current_distance - initial_distance); + + this.fire('distancechange', { distance: this.distance }); + }; + dragHintFindNearest = (latlng: LatLng): any => { const latlngs = this.getLatLngs(); @@ -261,6 +279,9 @@ export class Component extends Polyline { }; onMarkerDragEnd = ({ target }: { target: Marker}): void => { + const latlngs = this.getLatLngs() as LatLngLiteral[]; + this.markerDragChangeDistance(this.vertex_index, latlngs[this.vertex_index], target.getLatLng()); + this.replaceLatlng(target.getLatLng(), this.vertex_index); this.is_dragging = false; @@ -273,6 +294,25 @@ export class Component extends Polyline { this.fire('vertexdragend', { index: this.vertex_index, vertex: target }); }; + markerDragChangeDistance = (index: number, initial: LatLngLiteral, current: LatLngLiteral): void => { + const prev = index > 0 ? this.markers[index - 1] : null; + const next = index <= (this.markers.length + 1) ? this.markers[index + 1] : null; + + const initial_distance = ( + ((prev && distKm(prev.getLatLng(), initial)) || 0) + + ((next && distKm(next.getLatLng(), initial)) || 0) + ); + + const current_distance = ( + ((prev && distKm(prev.getLatLng(), current)) || 0) + + ((next && distKm(next.getLatLng(), current)) || 0) + ); + + this.distance += (current_distance - initial_distance); + + this.fire('distancechange', { distance: this.distance }); + }; + startDrawing = (): void => { this.setConstraints([]); this.constrLine.addTo(this._map); @@ -306,6 +346,8 @@ export class Component extends Polyline { this.stopDrawing(); const latlngs = this.getLatLngs() as any[]; + this.drawingChangeDistance(latlng); + if (this.drawing_direction === 'forward') { latlngs.push(latlng); this.markers.push(this.createMarker(latlng)); @@ -317,8 +359,18 @@ export class Component extends Polyline { this.startDrawing(); }; + drawingChangeDistance = (latlng: LatLngLiteral): void => { + const latlngs = this.getLatLngs() as LatLngLiteral[]; + const point = this.drawing_direction === 'forward' + ? latlngs[latlngs.length - 1] + : latlngs[0]; + + this.distance += distKm(point, latlng); + this.fire('distancechange', { distance: this.distance }); + }; + replaceLatlng = (latlng: LatLng, index: number): void => { - const latlngs = this.getLatLngs(); + const latlngs = this.getLatLngs() as LatLngLiteral[]; latlngs.splice(index, 1, latlng); this.setLatLngs(latlngs); }; @@ -333,6 +385,45 @@ export class Component extends Polyline { this.constrLine.setLatLngs(coords); }; + dropMarker = ({ target }: LeafletMouseEvent): void => { + const index = this.markers.indexOf(target); + const latlngs = this.getLatLngs(); + + if (typeof index === 'undefined' || latlngs.length <= 2) return; + + this.dropMarkerDistanceChange(index); + this._map.removeLayer(this.markers[index]); + this.markers.splice(index, 1); + latlngs.splice(index, 1); + this.setLatLngs(latlngs); + }; + + dropMarkerDistanceChange = (index: number): void => { + const latlngs = this.getLatLngs() as LatLngLiteral[]; + + const prev = index > 0 ? latlngs[index - 1] : null; + const current = latlngs[index]; + const next = index <= (latlngs.length + 1) ? latlngs[index + 1] : null; + + const initial_distance = ( + ((prev && distKm(prev, current)) || 0) + + ((next && distKm(next, current)) || 0) + ); + + const current_distance = (prev && next && distKm(prev, next)) || 0; + + this.distance += (current_distance - initial_distance); + + this.fire('distancechange', { distance: this.distance }); + }; + + recalcDistance = () => { + const latlngs = this.getLatLngs() as LatLngLiteral[]; + this.distance = getPolyLength(latlngs); + + this.fire('distancechange', { distance: this.distance }); + }; + markers: Marker[] = []; maxMarkers: InteractivePolylineOptions['maxMarkers'] = 2; markerLayer: LayerGroup = new LayerGroup(); @@ -394,4 +485,6 @@ export const InteractivePoly = Component; editordisable editorenable + + distancechange */ diff --git a/src/modules/Poly.ts b/src/modules/Poly.ts index 9fec7f0..9682385 100644 --- a/src/modules/Poly.ts +++ b/src/modules/Poly.ts @@ -1,4 +1,4 @@ -import { Map, LayerGroup, Polyline } from 'leaflet'; +import { Map, LayerGroup, Polyline, LatLng } from 'leaflet'; import { EditablePolyline } from '$utils/EditablePolyline'; import { simplify } from '$utils/simplify'; import { findDistance, getPolyLength, middleCoord } from '$utils/geom'; @@ -173,9 +173,9 @@ export class Poly { clearArrows = (): LayerGroup => this.arrows.clearLayers(); - dumpData = (): Array => this.latlngs; + dumpData = (): Array => this.latlngs; - get latlngs(): Array { + get latlngs(): Array { return ( this.poly && this.poly.getLatLngs().length && this.poly.getLatLngs().map(el => ({ ...el }))) || []; diff --git a/src/utils/geom.ts b/src/utils/geom.ts index 03eeb55..8177e2e 100644 --- a/src/utils/geom.ts +++ b/src/utils/geom.ts @@ -33,26 +33,22 @@ export const findDistance = (t1: number, n1: number, t2: number, n2: number): nu return (Math.round(dk * 1000) / 1000); }; +export const distKm = (A: LatLngLiteral, B: LatLngLiteral): number => findDistance(A.lat, A.lng, B.lat, B.lng); + export const getLabelDirection = (angle: number): 'left' | 'right' => ( ((angle % Math.PI) >= -(Math.PI / 2) && (angle % Math.PI) <= (Math.PI / 2)) ? 'left' : 'right' ); -// export const getPolyLength = (latlngs: ILatLng[]): number => latlngs.reduce((distance, latlng, i) => ( -// i < latlngs.length -// ? distance + findDistance(latlng.lat, latlng.lng, latlngs[i + 1].lat, latlngs[i + 1].lng) -// : distance -// ), 0); +export const getPolyLength = (latlngs: LatLngLiteral[]): number => { + if (latlngs.length < 2) return 0; -export const getPolyLength = (latlngs: ILatLng[]): number => { - console.log('latlngs', latlngs); - - return 0; + return latlngs.reduce((dist, item, index) => ( + index < (latlngs.length - 1) + ? dist + distKm(item, latlngs[index + 1]) + : dist + ), 0) }; -const distanceBetweenPoints = (A: LatLng, B: LatLng): number => ( - parseFloat(Math.sqrt(((A.lat - B.lat) ** 2) + ((A.lng - B.lng) ** 2)).toFixed(3)) -); - // if C between A and B export const pointInArea = (A: LatLng, B: LatLng, C: LatLng): boolean => ( C.lat >= Math.min(A.lat, B.lat) &&