stickers stops dragging

This commit is contained in:
Fedor Katurov 2019-12-30 15:07:59 +07:00
parent fca52df9f5
commit 58eefd5670
10 changed files with 388 additions and 175 deletions

View file

@ -15,23 +15,29 @@ import {
LatLng,
LeafletMouseEvent,
latLng,
LatLngLiteral,
} from 'leaflet';
LatLngLiteral
} from "leaflet";
import { distKm, distToSegment, getPolyLength, pointInArea } from "$utils/geom";
interface InteractivePolylineOptions extends PolylineOptions {
maxMarkers?: number,
constraintsStyle?: PolylineOptions,
kmMarksEnabled?: boolean,
kmMarksStep?: number,
maxMarkers?: number;
constraintsStyle?: PolylineOptions;
kmMarksEnabled?: boolean;
kmMarksStep?: number;
}
export class InteractivePoly extends Polyline {
constructor(latlngs: LatLngExpression[] | LatLngExpression[][], options?: InteractivePolylineOptions) {
constructor(
latlngs: LatLngExpression[] | LatLngExpression[][],
options?: InteractivePolylineOptions
) {
super(latlngs, options);
this.constraintsStyle = { ...this.constraintsStyle, ...options.constraintsStyle };
this.constraintsStyle = {
...this.constraintsStyle,
...options.constraintsStyle
};
this.maxMarkers = options.maxMarkers || this.maxMarkers;
this.constrLine = new Polyline([], this.constraintsStyle);
@ -43,36 +49,41 @@ export class InteractivePoly extends Polyline {
this.touchHinter.setLatLngs(latlngs);
};
setPoints = (latlngs: LatLng[]) => {
setPoints = (latlngs: LatLng[], emitEvent = false) => {
this.setLatLngs(latlngs);
this.recreateMarkers();
this.recalcDistance();
this.touchHinter.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
if (emitEvent) {
this.fire("latlngschange", { latlngs });
}
};
createHintMarker = (latlng: LatLng): Marker => marker(latlng, {
draggable: false,
icon: divIcon({
className: 'leaflet-vertex-drag-helper',
iconSize: [11, 11],
iconAnchor: [6, 6]
})
});
createHintMarker = (latlng: LatLng): Marker =>
marker(latlng, {
draggable: false,
icon: divIcon({
className: "leaflet-vertex-drag-helper",
iconSize: [11, 11],
iconAnchor: [6, 6]
})
});
createMarker = (latlng: LatLng): Marker => marker(latlng, {
draggable: true,
icon: divIcon({
className: 'leaflet-vertex-icon',
iconSize: [11, 11],
iconAnchor: [6, 6]
createMarker = (latlng: LatLng): Marker =>
marker(latlng, {
draggable: true,
icon: divIcon({
className: "leaflet-vertex-icon",
iconSize: [11, 11],
iconAnchor: [6, 6]
})
})
})
.on('contextmenu', this.dropMarker)
.on('drag', this.onMarkerDrag)
.on('dragstart', this.onMarkerDragStart)
.on('dragend', this.onMarkerDragEnd)
.addTo(this.markerLayer);
.on("contextmenu", this.dropMarker)
.on("drag", this.onMarkerDrag)
.on("dragstart", this.onMarkerDragStart)
.on("dragend", this.onMarkerDragEnd)
.addTo(this.markerLayer);
recreateMarkers = () => {
this.clearAllMarkers();
@ -99,14 +110,14 @@ export class InteractivePoly extends Polyline {
if (this._map.hasLayer(this.markerLayer)) return;
this._map.addLayer(this.markerLayer);
this.fire('allvertexshow');
this.fire("allvertexshow");
};
hideAllMarkers = (): void => {
if (!this._map.hasLayer(this.markerLayer)) return;
this._map.removeLayer(this.markerLayer);
this.fire('allvertexhide');
this.fire("allvertexhide");
};
showVisibleMarkers = (): void => {
@ -115,15 +126,19 @@ export class InteractivePoly extends Polyline {
const northEast = this._map.getBounds().getNorthEast();
const southWest = this._map.getBounds().getSouthWest();
const { visible, hidden } = this.markers.reduce((obj, marker) => {
const { lat, lng } = marker.getLatLng();
const is_hidden = (lat > northEast.lat || lng > northEast.lng || lat < southWest.lat || lng < southWest.lng);
const { visible, hidden } = this.markers.reduce(
(obj, marker) => {
const { lat, lng } = marker.getLatLng();
const is_hidden =
lat > northEast.lat ||
lng > northEast.lng ||
lat < southWest.lat ||
lng < southWest.lng;
return is_hidden
? { ...obj, hidden: [...obj.hidden, marker] }
: { ...obj, visible: [...obj.visible, marker] }
},
return is_hidden
? { ...obj, hidden: [...obj.hidden, marker] }
: { ...obj, visible: [...obj.visible, marker] };
},
{ visible: [], hidden: [] }
);
@ -136,7 +151,8 @@ export class InteractivePoly extends Polyline {
});
hidden.forEach(marker => {
if (this.markerLayer.hasLayer(marker)) this.markerLayer.removeLayer(marker);
if (this.markerLayer.hasLayer(marker))
this.markerLayer.removeLayer(marker);
});
};
@ -147,7 +163,7 @@ export class InteractivePoly extends Polyline {
this.stopDragHinting();
this.stopDrawing();
this.touchHinter.removeFrom(this._map);
this.fire('editordisable');
this.fire("editordisable");
},
enable: () => {
this.is_editing = true;
@ -155,16 +171,16 @@ export class InteractivePoly extends Polyline {
this.startDragHinting();
this.touchHinter.addTo(this._map);
this.fire('editorenable');
this.fire("editorenable");
},
continue: () => {
this.is_drawing = true;
this.drawing_direction = 'forward';
this.drawing_direction = "forward";
this.startDrawing();
},
prepend: () => {
this.is_drawing = true;
this.drawing_direction = 'backward';
this.drawing_direction = "backward";
this.startDrawing();
}
};
@ -174,7 +190,8 @@ export class InteractivePoly extends Polyline {
};
hideDragHint = (): void => {
if (this._map.hasLayer(this.hintMarker)) this._map.removeLayer(this.hintMarker);
if (this._map.hasLayer(this.hintMarker))
this._map.removeLayer(this.hintMarker);
};
showDragHint = (): void => {
@ -182,17 +199,17 @@ export class InteractivePoly extends Polyline {
};
startDragHinting = (): void => {
this.touchHinter.on('mousemove', this.moveDragHint);
this.touchHinter.on('mousedown', this.startDragHintMove);
this.touchHinter.on('mouseover', this.showDragHint);
this.touchHinter.on('mouseout', this.hideDragHint);
this.touchHinter.on("mousemove", this.moveDragHint);
this.touchHinter.on("mousedown", this.startDragHintMove);
this.touchHinter.on("mouseover", this.showDragHint);
this.touchHinter.on("mouseout", this.hideDragHint);
};
stopDragHinting = (): void => {
this.touchHinter.off('mousemove', this.moveDragHint);
this.touchHinter.off('mousedown', this.startDragHintMove);
this.touchHinter.off('mouseover', this.showDragHint);
this.touchHinter.off('mouseout', this.hideDragHint);
this.touchHinter.off("mousemove", this.moveDragHint);
this.touchHinter.off("mousedown", this.startDragHintMove);
this.touchHinter.off("mouseover", this.showDragHint);
this.touchHinter.off("mouseout", this.hideDragHint);
};
startDragHintMove = (event: LeafletMouseEvent): void => {
@ -216,9 +233,9 @@ export class InteractivePoly extends Polyline {
this.is_dragging = true;
this._map.on('mousemove', this.dragHintMove);
this._map.on('mouseup', this.dragHintAddMarker);
this._map.on('mouseout', this.stopDragHintMove);
this._map.on("mousemove", this.dragHintMove);
this._map.on("mouseup", this.dragHintAddMarker);
this._map.on("mouseout", this.stopDragHintMove);
};
stopDragHintMove = (): void => {
@ -226,23 +243,28 @@ export class InteractivePoly extends Polyline {
this.constrLine.removeFrom(this._map);
this._map.off('mousemove', this.dragHintMove);
this._map.off('mouseup', this.dragHintAddMarker);
this._map.off('mouseout', this.stopDragHintMove);
this._map.off("mousemove", this.dragHintMove);
this._map.off("mouseup", this.dragHintAddMarker);
this._map.off("mouseout", this.stopDragHintMove);
if (this.is_drawing) this.startDrawing();
setTimeout(() => { this.is_dragging = false; }, 0);
setTimeout(() => {
this.is_dragging = false;
}, 0);
};
dragHintAddMarker = ({ latlng }: LeafletMouseEvent): void => {
this.dragHintChangeDistance(this.hint_prev_marker, latlng);
this.markers.splice((this.hint_prev_marker + 1), 0, this.createMarker(latlng));
this.markers.splice(
this.hint_prev_marker + 1,
0,
this.createMarker(latlng)
);
this.insertLatLng(latlng, this.hint_prev_marker + 1);
this.hideDragHint();
this.stopDragHintMove();
};
dragHintChangeDistance = (index: number, current: LatLngLiteral): void => {
@ -251,28 +273,30 @@ export class InteractivePoly extends Polyline {
const initial_distance = distKm(prev.getLatLng(), next.getLatLng());
const current_distance = (
const current_distance =
((prev && distKm(prev.getLatLng(), current)) || 0) +
((next && distKm(next.getLatLng(), current)) || 0)
);
((next && distKm(next.getLatLng(), current)) || 0);
this.distance += (current_distance - initial_distance);
this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
};
dragHintFindNearest = (latlng: LatLng): any => {
const latlngs = this.getLatLngs() as LatLng[];
const neighbours = latlngs.filter((current, index) => {
const next = latlngs[index + 1] as LatLng;
const neighbours = latlngs
.filter((current, index) => {
const next = latlngs[index + 1] as LatLng;
return (next && pointInArea(current, next, latlng));
})
return next && pointInArea(current, next, latlng);
})
.map(el => latlngs.indexOf(el))
.sort((a, b) => (
distToSegment(latlngs[a], latlngs[a + 1], latlng) - distToSegment(latlngs[b], latlngs[b + 1], latlng)
));
.sort(
(a, b) =>
distToSegment(latlngs[a], latlngs[a + 1], latlng) -
distToSegment(latlngs[b], latlngs[b + 1], latlng)
);
return neighbours.length > 0 ? neighbours[0] : -1;
};
@ -284,22 +308,30 @@ export class InteractivePoly extends Polyline {
this.setConstraints([
this.markers[this.hint_prev_marker].getLatLng(),
event.latlng,
this.markers[this.hint_prev_marker + 1].getLatLng(),
this.markers[this.hint_prev_marker + 1].getLatLng()
]);
};
onMarkerDrag = ({ target }: { target: Marker}) => {
onMarkerDrag = ({ target }: { target: Marker }) => {
const coords = new Array(0)
.concat((this.vertex_index > 0 && this.markers[this.vertex_index - 1].getLatLng()) || [])
.concat(
(this.vertex_index > 0 &&
this.markers[this.vertex_index - 1].getLatLng()) ||
[]
)
.concat(target.getLatLng())
.concat((this.vertex_index < (this.markers.length - 1) && this.markers[this.vertex_index + 1].getLatLng()) || []);
.concat(
(this.vertex_index < this.markers.length - 1 &&
this.markers[this.vertex_index + 1].getLatLng()) ||
[]
);
this.setConstraints(coords);
this.fire('vertexdrag', { index: this.vertex_index, vertex: target });
this.fire("vertexdrag", { index: this.vertex_index, vertex: target });
};
onMarkerDragStart = ({ target }: { target: Marker}) => {
onMarkerDragStart = ({ target }: { target: Marker }) => {
if (this.is_drawing) {
this.stopDrawing();
this.is_drawing = true;
@ -312,12 +344,16 @@ export class InteractivePoly extends Polyline {
this.is_dragging = true;
this.constrLine.addTo(this._map);
this.fire('vertexdragstart', { index: this.vertex_index, vertex: target });
this.fire("vertexdragstart", { index: this.vertex_index, vertex: target });
};
onMarkerDragEnd = ({ target }: { target: Marker}): void => {
onMarkerDragEnd = ({ target }: { target: Marker }): void => {
const latlngs = this.getLatLngs() as LatLngLiteral[];
this.markerDragChangeDistance(this.vertex_index, latlngs[this.vertex_index], target.getLatLng());
this.markerDragChangeDistance(
this.vertex_index,
latlngs[this.vertex_index],
target.getLatLng()
);
this.replaceLatlng(target.getLatLng(), this.vertex_index);
@ -328,40 +364,43 @@ export class InteractivePoly extends Polyline {
if (this.is_drawing) this.startDrawing();
this.fire('vertexdragend', { index: this.vertex_index, vertex: target });
this.fire("vertexdragend", { index: this.vertex_index, vertex: target });
};
markerDragChangeDistance = (index: number, initial: LatLngLiteral, current: LatLngLiteral): void => {
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 next =
index <= this.markers.length + 1 ? this.markers[index + 1] : null;
const initial_distance = (
const initial_distance =
((prev && distKm(prev.getLatLng(), initial)) || 0) +
((next && distKm(next.getLatLng(), initial)) || 0)
);
((next && distKm(next.getLatLng(), initial)) || 0);
const current_distance = (
const current_distance =
((prev && distKm(prev.getLatLng(), current)) || 0) +
((next && distKm(next.getLatLng(), current)) || 0)
);
((next && distKm(next.getLatLng(), current)) || 0);
this.distance += (current_distance - initial_distance);
this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
};
startDrawing = (): void => {
this.is_drawing = true;
this.setConstraints([]);
this.constrLine.addTo(this._map);
this._map.on('mousemove', this.onDrawingMove);
this._map.on('click', this.onDrawingClick);
this._map.on("mousemove", this.onDrawingMove);
this._map.on("click", this.onDrawingClick);
};
stopDrawing = (): void => {
this.constrLine.removeFrom(this._map);
this._map.off('mousemove', this.onDrawingMove);
this._map.off('click', this.onDrawingClick);
this._map.off("mousemove", this.onDrawingMove);
this._map.off("click", this.onDrawingClick);
this.is_drawing = false;
};
@ -371,11 +410,13 @@ export class InteractivePoly extends Polyline {
return;
}
if (!this._map.hasLayer(this.constrLine)) this._map.addLayer(this.constrLine);
if (!this._map.hasLayer(this.constrLine))
this._map.addLayer(this.constrLine);
const marker = this.drawing_direction === 'forward'
? this.markers[this.markers.length - 1]
: this.markers[0];
const marker =
this.drawing_direction === "forward"
? this.markers[this.markers.length - 1]
: this.markers[0];
this.setConstraints([latlng, marker.getLatLng()]);
};
@ -391,7 +432,7 @@ export class InteractivePoly extends Polyline {
this.drawingChangeDistance(latlng);
if (this.drawing_direction === 'forward') {
if (this.drawing_direction === "forward") {
latlngs.push(latlng);
this.markers.push(this.createMarker(latlng));
} else {
@ -400,7 +441,7 @@ export class InteractivePoly extends Polyline {
}
this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
this.fire("latlngschange", { latlngs });
this.showVisibleMarkers();
this.startDrawing();
};
@ -410,30 +451,31 @@ export class InteractivePoly extends Polyline {
if (latlngs.length < 1) {
this.distance = 0;
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
return;
}
const point = this.drawing_direction === 'forward'
? latlngs[latlngs.length - 1]
: latlngs[0];
const point =
this.drawing_direction === "forward"
? latlngs[latlngs.length - 1]
: latlngs[0];
this.distance += distKm(point, latlng);
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
};
replaceLatlng = (latlng: LatLng, index: number): void => {
const latlngs = this.getLatLngs() as LatLngLiteral[];
latlngs.splice(index, 1, latlng);
this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
this.fire("latlngschange", { latlngs });
};
insertLatLng = (latlng, index): void => {
const latlngs = this.getLatLngs();
latlngs.splice(index, 0, latlng);
this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
this.fire("latlngschange", { latlngs });
};
setConstraints = (coords: LatLng[]) => {
@ -444,7 +486,7 @@ export class InteractivePoly extends Polyline {
const index = this.markers.indexOf(target);
const latlngs = this.getLatLngs();
if (typeof index === 'undefined' || latlngs.length <= 2) return;
if (typeof index === "undefined" || latlngs.length <= 2) return;
this.dropMarkerDistanceChange(index);
this._map.removeLayer(this.markers[index]);
@ -452,7 +494,7 @@ export class InteractivePoly extends Polyline {
latlngs.splice(index, 1);
this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
this.fire("latlngschange", { latlngs });
};
dropMarkerDistanceChange = (index: number): void => {
@ -460,43 +502,42 @@ export class InteractivePoly extends Polyline {
const prev = index > 0 ? latlngs[index - 1] : null;
const current = latlngs[index];
const next = index <= (latlngs.length + 1) ? latlngs[index + 1] : null;
const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null;
const initial_distance = (
const initial_distance =
((prev && distKm(prev, current)) || 0) +
((next && distKm(next, current)) || 0)
);
((next && distKm(next, current)) || 0);
const current_distance = (prev && next && distKm(prev, next)) || 0;
this.distance += (current_distance - initial_distance);
this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
};
recalcDistance = () => {
const latlngs = this.getLatLngs() as LatLngLiteral[];
this.distance = getPolyLength(latlngs);
this.fire('distancechange', { distance: this.distance });
this.fire("distancechange", { distance: this.distance });
};
markers: Marker[] = [];
maxMarkers: InteractivePolylineOptions['maxMarkers'] = 2;
maxMarkers: InteractivePolylineOptions["maxMarkers"] = 2;
markerLayer: LayerGroup = new LayerGroup();
constraintsStyle: InteractivePolylineOptions['constraintsStyle'] = {
constraintsStyle: InteractivePolylineOptions["constraintsStyle"] = {
weight: 6,
color: 'red',
dashArray: '10, 12',
color: "red",
dashArray: "10, 12",
opacity: 0.5,
interactive: false,
interactive: false
};
touchHinter: Polyline = new Polyline([], {
weight: 24,
smoothFactor: 3,
className: 'touch-hinter-poly'
className: "touch-hinter-poly"
});
hintMarker: Marker = this.createHintMarker(latLng({ lat: 0, lng: 0 }));
@ -507,28 +548,28 @@ export class InteractivePoly extends Polyline {
is_dragging: boolean = false;
is_drawing: boolean = false;
drawing_direction: 'forward' | 'backward' = 'forward';
drawing_direction: "forward" | "backward" = "forward";
vertex_index?: number = null;
hint_prev_marker: number = null;
distance: number = 0;
}
InteractivePoly.addInitHook(function () {
this.once('add', (event) => {
InteractivePoly.addInitHook(function() {
this.once("add", event => {
if (event.target instanceof InteractivePoly) {
this.map = event.target._map;
this.map.on('touch', console.log);
this.map.on("touch", console.log);
this.markerLayer.addTo(event.target._map);
this.hintMarker.addTo(event.target._map);
this.constrLine.addTo(event.target._map);
this.touchHinter.addTo(event.target._map);
this.map.on('moveend', this.updateMarkers);
this.map.on("moveend", this.updateMarkers);
this.on('latlngschange', this.updateTouchHinter);
this.on("latlngschange", this.updateTouchHinter);
if (window.innerWidth < 768) {
this.touchHinter.setStyle({ weight: 32 });
@ -536,14 +577,14 @@ InteractivePoly.addInitHook(function () {
}
});
this.once('remove', (event) => {
this.once("remove", event => {
if (event.target instanceof InteractivePoly) {
this.markerLayer.removeFrom(this._map);
this.hintMarker.removeFrom(this._map);
this.constrLine.removeFrom(this._map);
this.touchHinter.removeFrom(this._map);
this.map.off('moveend', this.updateMarkers);
this.map.off("moveend", this.updateMarkers);
}
});
});