nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

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:
Msrc/lib/leaflet.control.track-list/track-list.js | 117++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/lib/leaflet.polyline-edit/edit_line.css | 7+++++--
Msrc/lib/leaflet.polyline-edit/index.js | 45+++++++++++++++++++++++++++++++++++++--------
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'); + } + } };