From c215a0ef1370e1f69813507667c2f178c062c098 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 17 Jan 2024 10:50:20 -0800 Subject: [PATCH] #489 DrawTool - Move (#490) * #489 Draggable DrawTool Features part 1 * #489 DrawTool - Move 2 --- src/essence/Tools/Draw/DrawTool_Editing.js | 193 ++++++++++++++++++--- src/essence/Tools/Draw/DrawTool_Shapes.js | 1 - src/external/Leaflet/Path.Drag.js | 144 +++++++++++++++ src/external/Leaflet/leaflet-editable.js | 4 +- src/index.js | 1 + 5 files changed, 314 insertions(+), 29 deletions(-) create mode 100644 src/external/Leaflet/Path.Drag.js diff --git a/src/essence/Tools/Draw/DrawTool_Editing.js b/src/essence/Tools/Draw/DrawTool_Editing.js index 8bc43925..b23e8837 100644 --- a/src/essence/Tools/Draw/DrawTool_Editing.js +++ b/src/essence/Tools/Draw/DrawTool_Editing.js @@ -50,7 +50,7 @@ var Editing = { index: index, fileid: fileid, } - //Don't treat the point drags and context menu clicks + // Don't treat the point drags and context menu clicks if ( DrawTool.contextMenuLayer && DrawTool.contextMenuLayer.justDragged @@ -166,10 +166,10 @@ var Editing = { shape.hasOwnProperty('feature') && shape.feature.properties.arrow == true ) - ) + ) { DrawTool.contextMenuLayer = shape._layers[Object.keys(shape._layers)[0]] - else { + } else { DrawTool.contextMenuLayer = shape currentPointLatLng = Object.assign( {}, @@ -215,6 +215,12 @@ var Editing = { hasLineCap = true hasLineJoin = true hasVisibilityRange = true + + DrawTool.contextMenuLayer.originalStart = + DrawTool.contextMenuLayer.start + + DrawTool.contextMenuLayer.originalEnd = + DrawTool.contextMenuLayer.end } else if ( DrawTool.contextMenuLayer.feature.properties.annotation === true ) { @@ -904,6 +910,17 @@ var Editing = { 'editable:editing', updateSelectionLayer ) + DrawTool.contextMenuLayer.off('editable:drag') + DrawTool.contextMenuLayer.on('editable:drag', updateSelectionLayer) + + DrawTool.contextMenuLayer.off('editable:dragstart') + DrawTool.contextMenuLayer.on('editable:dragstart', () => { + $('#drawToolMouseoverText').removeClass('active') + }) + DrawTool.contextMenuLayer.off('editable:dragend') + DrawTool.contextMenuLayer.on('editable:dragend', () => { + $('#drawToolMouseoverText').removeClass('active') + }) } function updateSelectionLayer() { @@ -948,6 +965,7 @@ var Editing = { ] DrawTool.contextMenuLayers[0].selectionLayer = sl } + DrawTool._updateSelectionLayer = updateSelectionLayer //RESET $('.drawToolContextMenuReset').on('click', function () { @@ -1014,8 +1032,8 @@ var Editing = { ) { L_.addArrowToMap( l.l_i_f.layer, - l.shape.start, - l.shape.end, + DrawTool.contextMenuLayer.originalStart, + DrawTool.contextMenuLayer.originalEnd, l.properties.style, l.shape.feature, l.l_i_f.index, @@ -1023,6 +1041,22 @@ var Editing = { DrawTool.populateShapes() } ) + DrawTool.contextMenuLayer.start = + DrawTool.contextMenuLayer.originalStart + + DrawTool.contextMenuLayer.end = + DrawTool.contextMenuLayer.originalEnd + + DrawTool.contextMenuLayer.feature.geometry.coordinates = [ + [ + DrawTool.contextMenuLayer.start.lng, + DrawTool.contextMenuLayer.start.lat, + ], + [ + DrawTool.contextMenuLayer.end.lng, + DrawTool.contextMenuLayer.end.lat, + ], + ] } else { DrawTool.contextMenuLayer.resetGeoJSON() } @@ -2210,11 +2244,16 @@ var Editing = { ) $('.drawToolShapeLi').removeClass('active') elm.find('.drawToolShapeLiItemCheck').removeClass('checked') - if (typeof DrawTool.contextMenuLayer.disableEdit === 'function') + if ( + typeof DrawTool.contextMenuLayer.disableEdit === 'function' + ) { DrawTool.contextMenuLayer.disableEdit() + } if (DrawTool.contextMenuLayer.snapediting) { DrawTool.contextMenuLayer.snapediting.disable() - } else DrawTool.cmLayerDragOff() + } else { + DrawTool.cmLayerDragOff() + } DrawTool.isEditing = false resetShape() } @@ -2425,6 +2464,11 @@ var Editing = { } } else { newGeometry = DrawTool.contextMenuLayer.feature.geometry + + DrawTool.contextMenuLayer.originalStart = + DrawTool.contextMenuLayer.start + DrawTool.contextMenuLayer.originalEnd = + DrawTool.contextMenuLayer.end } if (DrawTool.vars.demtilesets) { @@ -2735,7 +2779,7 @@ var Editing = { var l = e if (l.hasOwnProperty('_layers')) l = l._layers[Object.keys(l._layers)[0]] - //Ignore the same layer + // Ignore the same layer if (l != layer) guides.push(e) } } @@ -2752,6 +2796,20 @@ var Editing = { 'mousedown', DrawTool.cmLayerDown ) + } else if ( + DrawTool.contextMenuLayer.hasOwnProperty('feature') && + DrawTool.contextMenuLayer.feature.hasOwnProperty('properties') && + DrawTool.contextMenuLayer.feature.properties.arrow == true + ) { + const arrowSublayerKeys = Object.keys( + DrawTool.contextMenuLayer._layers + ) + for (let i = 0; i < arrowSublayerKeys.length; i++) { + DrawTool.contextMenuLayer._layers[arrowSublayerKeys[i]].on( + 'mousedown', + DrawTool.cmLayerDown + ) + } } else DrawTool.contextMenuLayer.on('mousedown', DrawTool.cmLayerDown) Map_.map.on('mouseup', DrawTool.cmLayerUp) Map_.map.on('mousemove', DrawTool.cmLayerMove) @@ -2771,16 +2829,34 @@ var Editing = { 'mousedown', DrawTool.cmLayerDown ) + } else if ( + DrawTool.contextMenuLayer.hasOwnProperty('feature') && + DrawTool.contextMenuLayer.feature.hasOwnProperty('properties') && + DrawTool.contextMenuLayer.feature.properties.arrow == true + ) { + const arrowSublayerKeys = Object.keys( + DrawTool.contextMenuLayer._layers + ) + for (let i = 0; i < arrowSublayerKeys.length; i++) { + DrawTool.contextMenuLayer._layers[arrowSublayerKeys[i]].on( + 'mousedown', + DrawTool.cmLayerDown + ) + } } else if (typeof DrawTool.contextMenuLayer.off === 'function') DrawTool.contextMenuLayer.off('mousedown', DrawTool.cmLayerDown) Map_.map.off('mouseup', DrawTool.cmLayerUp) Map_.map.off('mousemove', DrawTool.cmLayerMove) - DrawTool.contextMenuLayer.dragging = false + if (DrawTool.contextMenuLayer.dragging === true) + DrawTool.contextMenuLayer.dragging = false Map_.map.dragging.enable() }, - cmLayerDown: function () { + cmLayerDown: function (e) { DrawTool.contextMenuLayer.dragging = true + DrawTool.contextMenuLayer.draggingArrowhead = + e.layer?._parts?.[0]?.length === 3 + Map_.map.dragging.disable() Map_.rmNotNull(DrawTool.contextMenuLayers[0].selectionLayer) }, @@ -2790,28 +2866,91 @@ var Editing = { //So the layer itself can ignore the click to drag DrawTool.contextMenuLayer.justDragged = true Map_.map.dragging.enable() - var radius = - DrawTool.contextMenuLayers[0].selectionLayer.options.radius - if (DrawTool.lastDragPoint) { - DrawTool.contextMenuLayers[0].selectionLayer = L.circleMarker( - DrawTool.lastDragPoint, - { - color: 'white', - weight: 2, - fillOpacity: 0, - dashArray: '5 5', - radius: radius, - } - ) - .addTo(Map_.map) - .bringToBack() + if (DrawTool.contextMenuLayer.feature?.properties?.arrow === true) { + DrawTool.contextMenuLayer.justDragged = false + const l = + L_.layers.layer[Editing._draggedContextMenuLayerParams[0]][ + Editing._draggedContextMenuLayerParams[5] + ] + DrawTool.contextMenuLayer.end = l.end + DrawTool.contextMenuLayer.feature = l.feature + DrawTool.contextMenuLayer.start = l.start + DrawTool.contextMenuLayer._layers = l._layers + DrawTool.contextMenuLayer._leaflet_id = l._leaflet_id + + DrawTool._updateSelectionLayer() + DrawTool.populateShapes() + + DrawTool.cmLayerDragOn() + } else { + var radius = + DrawTool.contextMenuLayers[0].selectionLayer.options.radius + if (DrawTool.lastDragPoint) { + DrawTool.contextMenuLayers[0].selectionLayer = + L.circleMarker(DrawTool.lastDragPoint, { + color: 'white', + weight: 2, + fillOpacity: 0, + dashArray: '5 5', + radius: radius, + }) + .addTo(Map_.map) + .bringToBack() + } } } }, cmLayerMove: function (e) { if (DrawTool.contextMenuLayer.dragging) { - DrawTool.contextMenuLayer.setLatLng(e.latlng) - DrawTool.lastDragPoint = e.latlng + if (DrawTool.contextMenuLayer.feature?.properties?.arrow === true) { + $('#drawToolMouseoverText').removeClass('active') + + const layerMetadata = DrawTool.contextMenuLayers[0] + const lif = layerMetadata.l_i_f + let startLatLng + let endLatLng + if (DrawTool.contextMenuLayer.draggingArrowhead) { + startLatLng = { + lng: DrawTool.contextMenuLayer.feature.geometry + .coordinates[0][0], + lat: DrawTool.contextMenuLayer.feature.geometry + .coordinates[0][1], + } + endLatLng = e.latlng + } else { + startLatLng = e.latlng + endLatLng = { + lng: DrawTool.contextMenuLayer.feature.geometry + .coordinates[1][0], + lat: DrawTool.contextMenuLayer.feature.geometry + .coordinates[1][1], + } + } + Editing._draggedContextMenuLayerParams = [ + lif.layer, + startLatLng, + endLatLng, + layerMetadata.style, + DrawTool.contextMenuLayer.feature, + lif.index, + ] + DrawTool.contextMenuLayer.feature.geometry.coordinates = [ + [startLatLng.lng, startLatLng.lat], + [endLatLng.lng, endLatLng.lat], + ] + L_.addArrowToMap( + lif.layer, + startLatLng, + endLatLng, + layerMetadata.style, + DrawTool.contextMenuLayer.feature, + lif.index, + () => {} + ) + } else { + DrawTool.contextMenuLayer.setLatLng(e.latlng) + DrawTool.lastDragPoint = e.latlng + } } }, _addedTabEvents: [], diff --git a/src/essence/Tools/Draw/DrawTool_Shapes.js b/src/essence/Tools/Draw/DrawTool_Shapes.js index b213b33b..0c31eae3 100644 --- a/src/essence/Tools/Draw/DrawTool_Shapes.js +++ b/src/essence/Tools/Draw/DrawTool_Shapes.js @@ -198,7 +198,6 @@ var Shapes = { ) //if it's a non point layer f = shape._layers[Object.keys(shape._layers)[0]] - var properties = f.feature.properties if (f.hasOwnProperty('_layers')) f = f._layers diff --git a/src/external/Leaflet/Path.Drag.js b/src/external/Leaflet/Path.Drag.js new file mode 100644 index 00000000..23ed8beb --- /dev/null +++ b/src/external/Leaflet/Path.Drag.js @@ -0,0 +1,144 @@ +'use strict' + +/* A Draggable that does not update the element position +and takes care of only bubbling to targetted path in Canvas mode. */ +L.PathDraggable = L.Draggable.extend({ + initialize: function (path) { + this._path = path + this._canvas = path._map.getRenderer(path) instanceof L.Canvas + var element = this._canvas + ? this._path._map.getRenderer(this._path)._container + : this._path._path + L.Draggable.prototype.initialize.call(this, element, element, true) + }, + + _updatePosition: function () { + var e = { originalEvent: this._lastEvent } + this.fire('drag', e) + }, + + _onDown: function (e) { + var first = e.touches ? e.touches[0] : e + this._startPoint = new L.Point(first.clientX, first.clientY) + if ( + this._canvas && + !this._path._containsPoint( + this._path._map.mouseEventToLayerPoint(first) + ) + ) { + return + } + L.Draggable.prototype._onDown.call(this, e) + }, +}) + +L.Handler.PathDrag = L.Handler.extend({ + initialize: function (path) { + this._path = path + }, + + getEvents: function () { + return { + dragstart: this._onDragStart, + drag: this._onDrag, + dragend: this._onDragEnd, + } + }, + + addHooks: function () { + if (!this._draggable) { + this._draggable = new L.PathDraggable(this._path) + } + this._draggable.on(this.getEvents(), this).enable() + L.DomUtil.addClass(this._draggable._element, 'leaflet-path-draggable') + }, + + removeHooks: function () { + this._draggable.off(this.getEvents(), this).disable() + L.DomUtil.removeClass( + this._draggable._element, + 'leaflet-path-draggable' + ) + }, + + moved: function () { + return this._draggable && this._draggable._moved + }, + + _onDragStart: function () { + this._startPoint = this._draggable._startPoint + this._path.closePopup().fire('movestart').fire('dragstart') + }, + + _onDrag: function (e) { + var path = this._path, + event = + e.originalEvent.touches && e.originalEvent.touches.length === 1 + ? e.originalEvent.touches[0] + : e.originalEvent, + newPoint = L.point(event.clientX, event.clientY), + latlng = path._map.layerPointToLatLng(newPoint) + + this._offset = newPoint.subtract(this._startPoint) + this._startPoint = newPoint + + this._path.eachLatLng(this.updateLatLng, this) + path.redraw() + + e.latlng = latlng + e.offset = this._offset + path.fire('drag', e) + e.latlng = this._path.getCenter + ? this._path.getCenter() + : this._path.getLatLng() + path.fire('move', e) + }, + + _onDragEnd: function (e) { + if (this._path._bounds) this.resetBounds() + this._path.fire('moveend').fire('dragend', e) + }, + + latLngToLayerPoint: function (latlng) { + // Same as map.latLngToLayerPoint, but without the round(). + var projectedPoint = this._path._map.project(L.latLng(latlng)) + return projectedPoint._subtract(this._path._map.getPixelOrigin()) + }, + + updateLatLng: function (latlng) { + var oldPoint = this.latLngToLayerPoint(latlng) + oldPoint._add(this._offset) + var newLatLng = this._path._map.layerPointToLatLng(oldPoint) + latlng.lat = newLatLng.lat + latlng.lng = newLatLng.lng + }, + + resetBounds: function () { + this._path._bounds = new L.LatLngBounds() + this._path.eachLatLng(function (latlng) { + this._bounds.extend(latlng) + }) + }, +}) + +L.Path.include({ + eachLatLng: function (callback, context) { + context = context || this + var loop = function (latlngs) { + for (var i = 0; i < latlngs.length; i++) { + if (L.Util.isArray(latlngs[i])) loop(latlngs[i]) + else callback.call(context, latlngs[i]) + } + } + loop(this.getLatLngs ? this.getLatLngs() : [this.getLatLng()]) + }, +}) + +L.Path.addInitHook(function () { + this.dragging = new L.Handler.PathDrag(this) + if (this.options.draggable) { + this.once('add', function () { + this.dragging.enable() + }) + } +}) diff --git a/src/external/Leaflet/leaflet-editable.js b/src/external/Leaflet/leaflet-editable.js index 46ef1d2a..ec4b1eae 100644 --- a/src/external/Leaflet/leaflet-editable.js +++ b/src/external/Leaflet/leaflet-editable.js @@ -1841,7 +1841,9 @@ // 🍂method enableEdit(map?: L.Map): this.editor // Enable editing, by creating an editor if not existing, and then calling `enable` on it. enableEdit: function (map) { - if (!this.editor) this.createEditor(map) + if (!this.editor) { + this.createEditor(map) + } this.editor.enable() return this.editor }, diff --git a/src/index.js b/src/index.js index 56168bb7..2dd20414 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ import RefreshAuth from './pre/RefreshAuth' import $ from 'jquery' import L from './external/Leaflet/leaflet1.5.1' // './external/Leaflet/leaflet1.5.1_DEBUG' // import ld from './external/Leaflet/leaflet.draw' +import pd from './external/Leaflet/Path.Drag' import lgu from './external/Leaflet/leaflet.geometryutil' import ls from './external/Leaflet/leaflet.snap' import lc from './external/Leaflet/leaflet-corridor'