commit 409ac13909cf98a1e5edcc649381efd86d64f33b
parent 7880bdaa392ebc141fa989530217e2aee31b401b
Author: Sergey Orlov <wladimirych@gmail.com>
Date: Wed, 1 Jul 2020 15:18:12 +0200
track list: add new feature - remove multiple nodes from track segment
Diffstat:
3 files changed, 155 insertions(+), 14 deletions(-)
diff --git a/src/lib/leaflet.control.track-list/track-list.js b/src/lib/leaflet.control.track-list/track-list.js
@@ -669,10 +669,7 @@ L.Control.TrackList = L.Control.extend({
}
polyline.startEdit();
this._editedLine = polyline;
- polyline.once('editend', function(e) {
- setTimeout(this.onLineEditEnd.bind(this, e), 0);
- }.bind(this)
- );
+ polyline.once('editend', this.onLineEditEnd, this);
this.fire('startedit');
},
@@ -831,6 +828,7 @@ L.Control.TrackList = L.Control.extend({
items.push({text: 'Join', callback: this.startLineJoinSelection.bind(this, e)});
}
items.push({text: 'Reverse', callback: this.reverseTrackSegment.bind(this, e.line)});
+ items.push({text: 'Shortcut', callback: this.startShortCutSelection.bind(this, e, true)});
items.push({text: 'Delete segment', callback: this.deleteTrackSegment.bind(this, e.line)});
items.push({text: 'New track from segment', callback: this.newTrackFromSegment.bind(this, e.line)});
items.push({
@@ -850,6 +848,7 @@ L.Control.TrackList = L.Control.extend({
callback: this.splitTrackSegment.bind(this, e.line, e.nodeIndex, e.mouseEvent.latlng)
},
{text: 'Reverse', callback: this.reverseTrackSegment.bind(this, e.line)},
+ {text: 'Shortcut', callback: this.startShortCutSelection.bind(this, e, false)},
{text: 'Delete segment', callback: this.deleteTrackSegment.bind(this, e.line)},
{text: 'New track from segment', callback: this.newTrackFromSegment.bind(this, e.line)},
{
@@ -926,6 +925,7 @@ L.Control.TrackList = L.Control.extend({
track.feature.on('mousemove', this.onMouseMoveOnLineForJoin, this);
}
this._lineJoinActive = true;
+ this._editedLine.disableEditOnLeftClick(true);
},
onMouseMoveOnLineForJoin: function(e) {
@@ -940,9 +940,118 @@ L.Control.TrackList = L.Control.extend({
for (let track of this.tracks()) {
track.feature.off('mousemove', this.onMouseMoveOnLineForJoin, this);
}
+ this.off('linecursorhide', this.onLineCursorHideForJoin, this);
+ this._editedLine.disableEditOnLeftClick(false);
this._lineJoinActive = false;
},
+ startShortCutSelection: function(e, startFromNode) {
+ const line = this._editedLine;
+ this._shortCut = {startNodeIndex: e.nodeIndex, startFromNode};
+ let cursorStart;
+ if (startFromNode) {
+ cursorStart = line.getLatLngs()[e.nodeIndex];
+ } else {
+ cursorStart = closestPointToLineSegment(line.getLatLngs(), e.nodeIndex, e.mouseEvent.latlng);
+ this._shortCut.startLatLng = cursorStart;
+ }
+ this.showLineCursor(cursorStart, e.mouseEvent.latlng);
+ line.nodeMarkers.on('mousemove', this.onMouseMoveOnNodeMarkerForShortCut, this);
+ line.segmentOverlays.on('mousemove', this.onMouseMoveOnLineSegmentForShortCut, this);
+ this.map.on('mousemove', this.onMouseMoveOnMapForShortCut, this);
+ line.nodeMarkers.on('click', this.onClickNodeMarkerForShortCut, this);
+ line.segmentOverlays.on('click', this.onClickLineSegmentForShortCut, this);
+ this.on('linecursorhide', this.onLineCursorHideForShortCut, this);
+ line.disableEditOnLeftClick(true);
+ },
+
+ onMouseMoveOnLineSegmentForShortCut: function(e) {
+ this.updateShortCutSelection(e, false);
+ },
+
+ onMouseMoveOnNodeMarkerForShortCut: function(e) {
+ this.updateShortCutSelection(e, true);
+ },
+
+ onMouseMoveOnMapForShortCut: function() {
+ this._editedLine.highlighNodesForDeletion();
+ },
+
+ updateShortCutSelection: function(e, endAtNode) {
+ L.DomEvent.stopPropagation(e);
+ const line = this._editedLine;
+ const {firstNodeToDelete, lastNodeToDelete, rangeValid} = this.getShortCutNodes(e, endAtNode);
+ this.updateLineCursor(e.latlng, rangeValid);
+ if (rangeValid) {
+ line.highlighNodesForDeletion(firstNodeToDelete, lastNodeToDelete);
+ } else {
+ line.highlighNodesForDeletion();
+ }
+ },
+
+ onLineCursorHideForShortCut: function() {
+ const line = this._editedLine;
+ line.highlighNodesForDeletion();
+ line.nodeMarkers.off('mousemove', this.onMouseMoveOnNodeMarkerForShortCut, this);
+ line.segmentOverlays.off('mousemove', this.onMouseMoveOnLineSegmentForShortCut, this);
+ this.map.off('mousemove', this.onMouseMoveOnMapForShortCut, this);
+ line.nodeMarkers.off('click', this.onClickNodeMarkerForShortCut, this);
+ line.segmentOverlays.off('click', this.onClickLineSegmentForShortCut, this);
+ this.off('linecursorhide', this.onLineCursorHideForShortCut, this);
+ line.disableEditOnLeftClick(false);
+ this._shortCut = null;
+ },
+
+ onClickLineSegmentForShortCut: function(e) {
+ this.shortCutSegment(e, false);
+ },
+
+ onClickNodeMarkerForShortCut: function(e) {
+ this.shortCutSegment(e, true);
+ },
+
+ getShortCutNodes: function(e, endAtNode) {
+ const line = this._editedLine;
+ let startFromNode = this._shortCut.startFromNode;
+ let startNodeIndex = this._shortCut.startNodeIndex;
+ let endNodeIndex = line[endAtNode ? 'getMarkerIndex' : 'getSegmentOverlayIndex'](e.layer);
+ const newNodes = [];
+ if (!startFromNode) {
+ newNodes.push(this._shortCut.startLatLng);
+ }
+ if (!endAtNode) {
+ newNodes.push(closestPointToLineSegment(line.getLatLngs(), endNodeIndex, e.latlng));
+ }
+ let firstNodeToDelete, lastNodeToDelete;
+ if (endNodeIndex > startNodeIndex) {
+ firstNodeToDelete = startNodeIndex + 1;
+ lastNodeToDelete = endNodeIndex - 1;
+ if (!endAtNode) {
+ lastNodeToDelete += 1;
+ }
+ } else {
+ newNodes.reverse();
+ firstNodeToDelete = endNodeIndex + 1;
+ lastNodeToDelete = startNodeIndex - 1;
+ if (!startFromNode) {
+ lastNodeToDelete += 1;
+ }
+ }
+ return {firstNodeToDelete, lastNodeToDelete, newNodes, rangeValid: lastNodeToDelete >= firstNodeToDelete};
+ },
+
+ shortCutSegment: function(e, endAtNode) {
+ L.DomEvent.stopPropagation(e);
+ const line = this._editedLine;
+ const {firstNodeToDelete, lastNodeToDelete, newNodes, rangeValid} = this.getShortCutNodes(e, endAtNode);
+ if (!rangeValid) {
+ return;
+ }
+ this.stopEditLine();
+ line.spliceLatLngs(firstNodeToDelete, lastNodeToDelete - firstNodeToDelete + 1, ...newNodes);
+ this.startEditTrackSegement(line);
+ },
+
onTrackMouseEnter: function(track) {
track.hover(true);
},
diff --git a/src/lib/leaflet.polyline-edit/edit_line.css b/src/lib/leaflet.polyline-edit/edit_line.css
@@ -40,4 +40,8 @@
.line-editor-node-marker-end {
background-color: rgb(90%, 20%, 20%);
z-index: 1000000 !important;
-}
-\ No newline at end of file
+}
+
+.highlight-delete .line-editor-node-marker {
+ border-color: red;
+}
diff --git a/src/lib/leaflet.polyline-edit/index.js b/src/lib/leaflet.polyline-edit/index.js
@@ -58,9 +58,17 @@ L.Polyline.EditMixin = {
);
},
+ getMarkerIndex: function(marker) {
+ return this.getLatLngs().indexOf(marker._lineNode);
+ },
+
+ getSegmentOverlayIndex: function(segmentOverlay) {
+ return this.getLatLngs().indexOf(segmentOverlay._lineNode);
+ },
+
onNodeMarkerDragEnd: function(e) {
var marker = e.target,
- nodeIndex = this.getLatLngs().indexOf(marker._lineNode);
+ nodeIndex = this.getMarkerIndex(marker);
this.replaceNode(nodeIndex, marker.getLatLng());
this._setupEndMarkers();
},
@@ -77,11 +85,14 @@ L.Polyline.EditMixin = {
},
onNodeMarkerDblClickedRemoveNode: function(e) {
+ if (this._disableEditOnLeftClick) {
+ return;
+ }
if (this.getLatLngs().length < 2 || (this._drawingDirection && this.getLatLngs().length === 2)) {
return;
}
var marker = e.target,
- nodeIndex = this.getLatLngs().indexOf(marker._lineNode);
+ nodeIndex = this.getMarkerIndex(marker);
this.removeNode(nodeIndex);
this._setupEndMarkers();
this.fire('nodeschanged');
@@ -217,7 +228,7 @@ L.Polyline.EditMixin = {
.on('contextmenu', function(e) {
this.stopDrawingLine();
this.fire('noderightclick', {
- nodeIndex: this.getLatLngs().indexOf(marker._lineNode),
+ nodeIndex: this.getMarkerIndex(marker),
line: this,
mouseEvent: e
}
@@ -230,10 +241,13 @@ L.Polyline.EditMixin = {
},
onNodeMarkerClickStartStopDrawing: function(e) {
+ if (this._disableEditOnLeftClick) {
+ return;
+ }
var marker = e.target,
latlngs = this.getLatLngs(),
latlngs_n = latlngs.length,
- nodeIndex = latlngs.indexOf(marker._lineNode);
+ nodeIndex = this.getMarkerIndex(marker);
if ((this._drawingDirection === -1 && nodeIndex === 1) ||
((this._drawingDirection === 1 && nodeIndex === latlngs_n - 2))) {
this.stopDrawingLine();
@@ -260,7 +274,7 @@ L.Polyline.EditMixin = {
segmentOverlay.on('contextmenu', function(e) {
this.stopDrawingLine();
this.fire('segmentrightclick', {
- nodeIndex: this.getLatLngs().indexOf(segmentOverlay._lineNode),
+ nodeIndex: this.getSegmentOverlayIndex(segmentOverlay),
mouseEvent: e,
line: this
}
@@ -273,12 +287,12 @@ L.Polyline.EditMixin = {
},
onSegmentMouseDownAddNode: function(e) {
- if (e.originalEvent.button !== 0) {
+ if (e.originalEvent.button !== 0 || this._disableEditOnLeftClick) {
return;
}
var segmentOverlay = e.target,
latlngs = this.getLatLngs(),
- nodeIndex = latlngs.indexOf(segmentOverlay._lineNode) + 1;
+ nodeIndex = this.getSegmentOverlayIndex(segmentOverlay) + 1;
const midPoint = L.latLngBounds(latlngs[nodeIndex], latlngs[nodeIndex - 1]).getCenter();
this.addNode(nodeIndex, wrapLatLngToTarget(e.latlng, midPoint));
if (L.Draggable._dragging) {
@@ -426,6 +440,21 @@ L.Polyline.EditMixin = {
end -= 1;
}
return this._latlngs.slice(start, end);
- }
+ },
+
+ disableEditOnLeftClick: function(disable) {
+ this._disableEditOnLeftClick = disable;
+ },
+ highlighNodesForDeletion: function(startNodeIndex, endNodeIndex) {
+ if (!this._editing) {
+ return;
+ }
+ const nodes = this.getLatLngs();
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+ const icon = node._nodeMarker._icon;
+ L.DomUtil[i >= startNodeIndex && i <= endNodeIndex ? 'addClass' : 'removeClass'](icon, 'highlight-delete');
+ }
+ }
};