nakarte

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

index.js (16394B)


      1 import L from 'leaflet';
      2 import './edit_line.css';
      3 import {wrapLatLngToTarget} from '~/lib/leaflet.fixes/fixWorldCopyJump';
      4 
      5 L.Polyline.EditMixinOptions = {
      6     className: 'leaflet-editable-line'
      7 };
      8 
      9 L.Polyline.EditMixin = {
     10     _nodeMarkersZOffset: 10000,
     11 
     12     startEdit: function() {
     13         if (this._map && !this._editing) {
     14             this._editing = true;
     15             this._drawingDirection = 0;
     16             this.setupMarkers();
     17             this.on('remove', this.stopEdit.bind(this));
     18             this._map
     19                 .on('click', this.onMapClick, this)
     20                 .on('dragend', this.onMapEndDrag, this);
     21             L.DomEvent.on(document, 'keyup', this.onKeyPress, this);
     22             this._storedStyle = {weight: this.options.weight, opacity: this.options.opacity};
     23             this.setStyle({weight: 1.5, opacity: 1});
     24             L.DomUtil.addClass(this._map._container, 'leaflet-line-editing');
     25             this.fire('editstart', {target: this});
     26         }
     27     },
     28 
     29     stopEdit: function(userCancelled) {
     30         if (this._editing) {
     31             this.stopDrawingLine();
     32             this._editing = false;
     33             this.removeMarkers();
     34             L.DomEvent.off(document, 'keyup', this.onKeyPress, this);
     35             this.off('remove', this.stopEdit.bind(this));
     36             this._map
     37                 .off('click', this.onMapClick, this)
     38                 .off('dragend', this.onMapEndDrag, this);
     39             this.setStyle(this._storedStyle);
     40             L.DomUtil.removeClass(this._map._container, 'leaflet-line-editing');
     41             this.fire('editend', {target: this, userCancelled});
     42         }
     43     },
     44 
     45     removeMarkers: function() {
     46         this.getLatLngs().forEach(function(node) {
     47                 if (node._nodeMarker) {
     48                     this.nodeMarkers.removeLayer(node._nodeMarker);
     49                     delete node._nodeMarker._lineNode;
     50                     delete node._nodeMarker;
     51                 }
     52                 if (node._segmentOverlay) {
     53                     this.segmentOverlays.removeLayer(node._segmentOverlay);
     54                     delete node._segmentOverlay._lineNode;
     55                     delete node._segmentOverlay;
     56                 }
     57             }.bind(this)
     58         );
     59     },
     60 
     61     getMarkerIndex: function(marker) {
     62         return this.getLatLngs().indexOf(marker._lineNode);
     63     },
     64 
     65     getSegmentOverlayIndex: function(segmentOverlay) {
     66         return this.getLatLngs().indexOf(segmentOverlay._lineNode);
     67     },
     68 
     69     onNodeMarkerDragEnd: function(e) {
     70         var marker = e.target,
     71             nodeIndex = this.getMarkerIndex(marker);
     72         this.replaceNode(nodeIndex, marker.getLatLng());
     73         this._setupEndMarkers();
     74     },
     75 
     76     onNodeMarkerMovedChangeNode: function(e) {
     77         var marker = e.target,
     78             latlng = marker.getLatLng(),
     79             node = marker._lineNode;
     80         node.lat = latlng.lat;
     81         node.lng = latlng.lng;
     82         this.redraw();
     83         this.fire('nodeschanged');
     84     },
     85 
     86     onNodeMarkerDblClickedRemoveNode: function(e) {
     87         if (this._disableEditOnLeftClick) {
     88             return;
     89         }
     90         if (this.getLatLngs().length < 2 || (this._drawingDirection && this.getLatLngs().length === 2)) {
     91             return;
     92         }
     93         var marker = e.target,
     94             nodeIndex = this.getMarkerIndex(marker);
     95         this.removeNode(nodeIndex);
     96         this._setupEndMarkers();
     97     },
     98 
     99     onMapClick: function(e) {
    100         if (this._drawingDirection) {
    101             let newNodeIndex,
    102                 refNodeIndex;
    103             if (this._drawingDirection === -1) {
    104                 newNodeIndex = 1;
    105                 refNodeIndex = 0;
    106             } else {
    107                 newNodeIndex = this._latlngs.length - 1;
    108                 refNodeIndex = this._latlngs.length - 1;
    109             }
    110             this.addNode(newNodeIndex, wrapLatLngToTarget(e.latlng, this._latlngs[refNodeIndex]));
    111         } else {
    112             if (!this.preventStopEdit) {
    113                 this.stopEdit(true);
    114             }
    115         }
    116     },
    117 
    118     onMapEndDrag: function(e) {
    119         if (e.distance < 15) {
    120             // get mouse position from map drag handler
    121             var handler = e.target.dragging._draggable;
    122             var mousePos = handler._startPoint.add(handler._newPos).subtract(handler._startPos);
    123             var latlng = e.target.mouseEventToLatLng({clientX: mousePos.x, clientY: mousePos.y});
    124             this.onMapClick({latlng: latlng});
    125         }
    126     },
    127 
    128     startDrawingLine: function(direction, e) {
    129         if (!this._editing) {
    130             return;
    131         }
    132         if (direction === undefined) {
    133             direction = 1;
    134         }
    135         if (this._drawingDirection === direction) {
    136             return;
    137         }
    138         this.stopDrawingLine();
    139         this._drawingDirection = direction;
    140         if (e) {
    141             var newNodeIndex = this._drawingDirection === -1 ? 0 : this.getLatLngs().length;
    142             this.spliceLatLngs(newNodeIndex, 0, e.latlng);
    143             this._setupEndMarkers();
    144         }
    145 
    146         this._map.on('mousemove', this.onMouseMoveFollowEndNode, this);
    147         L.DomUtil.addClass(this._map._container, 'leaflet-line-drawing');
    148         this._map.clickLocked = true;
    149     },
    150 
    151     stopDrawingLine: function() {
    152         if (!this._drawingDirection) {
    153             return;
    154         }
    155         this._map.off('mousemove', this.onMouseMoveFollowEndNode, this);
    156         var nodeIndex = this._drawingDirection === -1 ? 0 : this.getLatLngs().length - 1;
    157         this.spliceLatLngs(nodeIndex, 1);
    158         this._drawingDirection = 0;
    159         L.DomUtil.removeClass(this._map._container, 'leaflet-line-drawing');
    160         this._map.clickLocked = false;
    161         this._setupEndMarkers();
    162         this.fire('drawend');
    163     },
    164 
    165     onKeyPress: function(e) {
    166         if (e.target.tagName.toLowerCase() === 'input') {
    167             return;
    168         }
    169         var code = e.keyCode;
    170         switch (code) {
    171             case 27:
    172             case 13:
    173                 if (this._drawingDirection) {
    174                     this.stopDrawingLine();
    175                 } else {
    176                     if (!this.preventStopEdit) {
    177                         this.stopEdit(true);
    178                     }
    179                 }
    180                 L.DomEvent.stop(e);
    181                 break;
    182             case 8:
    183             case 46:
    184                 if (this._drawingDirection && this.getLatLngs().length > 2) {
    185                     const nodeIndex = this._drawingDirection === 1 ? this.getLatLngs().length - 2 : 1;
    186                     this.removeNode(nodeIndex);
    187                     L.DomEvent.preventDefault(e);
    188                 }
    189                 break;
    190 
    191             default:
    192         }
    193     },
    194 
    195     onMouseMoveFollowEndNode: function(e) {
    196         var nodeIndex = this._drawingDirection === -1 ? 0 : this.getLatLngs().length - 1;
    197         let latlng = e.latlng;
    198         if (this._latlngs.length > 0) {
    199             latlng = wrapLatLngToTarget(latlng, this._latlngs[nodeIndex]);
    200         }
    201         this.spliceLatLngs(nodeIndex, 1, latlng);
    202     },
    203 
    204     makeNodeMarker: function(nodeIndex) {
    205         var node = this.getLatLngs()[nodeIndex],
    206             marker = L.marker(node.clone(), {
    207                     icon: L.divIcon({
    208                         className: 'line-editor-node-marker-halo',
    209                         html: '<div class="line-editor-node-marker"></div>'
    210                     }),
    211                     draggable: true,
    212                     zIndexOffset: this._nodeMarkersZOffset,
    213                     projectedShift: () => this.shiftProjectedFitMapView()
    214                 }
    215             );
    216         marker
    217             .on('drag', this.onNodeMarkerMovedChangeNode, this)
    218             // .on('dragstart', this.fire.bind(this, 'editingstart'))
    219             .on('dragend', this.onNodeMarkerDragEnd, this)
    220             .on('dblclick', this.onNodeMarkerDblClickedRemoveNode, this)
    221             .on('click', this.onNodeMarkerClickStartStopDrawing, this)
    222             .on('contextmenu', function(e) {
    223                     this.stopDrawingLine();
    224                     this.fire('noderightclick', {
    225                             nodeIndex: this.getMarkerIndex(marker),
    226                             line: this,
    227                             mouseEvent: e
    228                         }
    229                     );
    230                 }, this
    231             );
    232         marker._lineNode = node;
    233         node._nodeMarker = marker;
    234         marker.addTo(this.nodeMarkers);
    235     },
    236 
    237     onNodeMarkerClickStartStopDrawing: function(e) {
    238         if (this._disableEditOnLeftClick) {
    239             return;
    240         }
    241         var marker = e.target,
    242             latlngs = this.getLatLngs(),
    243             latlngs_n = latlngs.length,
    244             nodeIndex = this.getMarkerIndex(marker);
    245         if ((this._drawingDirection === -1 && nodeIndex === 1) ||
    246             ((this._drawingDirection === 1 && nodeIndex === latlngs_n - 2))) {
    247             this.stopDrawingLine();
    248         } else if (nodeIndex === this.getLatLngs().length - 1) {
    249             this.startDrawingLine(1, e);
    250         } else if (nodeIndex === 0) {
    251             this.startDrawingLine(-1, e);
    252         }
    253     },
    254 
    255     makeSegmentOverlay: function(nodeIndex) {
    256         const latlngs = this.getLatLngs(),
    257             p1 = latlngs[nodeIndex],
    258             p2 = latlngs[nodeIndex + 1];
    259         if (!p2) {
    260             return;
    261         }
    262         const segmentOverlay = L.polyline([p1, p2], {
    263             weight: 10,
    264             opacity: 0.0,
    265             projectedShift: () => this.shiftProjectedFitMapView()
    266         });
    267         segmentOverlay.on('mousedown', this.onSegmentMouseDownAddNode, this);
    268         segmentOverlay.on('contextmenu', function(e) {
    269                 this.stopDrawingLine();
    270                 this.fire('segmentrightclick', {
    271                         nodeIndex: this.getSegmentOverlayIndex(segmentOverlay),
    272                         mouseEvent: e,
    273                         line: this
    274                     }
    275                 );
    276             }, this
    277         );
    278         segmentOverlay._lineNode = p1;
    279         p1._segmentOverlay = segmentOverlay;
    280         segmentOverlay.addTo(this.segmentOverlays);
    281     },
    282 
    283     onSegmentMouseDownAddNode: function(e) {
    284         if (e.originalEvent.button !== 0 || this._disableEditOnLeftClick) {
    285             return;
    286         }
    287         var segmentOverlay = e.target,
    288             latlngs = this.getLatLngs(),
    289             nodeIndex = this.getSegmentOverlayIndex(segmentOverlay) + 1;
    290         const midPoint = L.latLngBounds(latlngs[nodeIndex], latlngs[nodeIndex - 1]).getCenter();
    291         this.addNode(nodeIndex, wrapLatLngToTarget(e.latlng, midPoint));
    292         if (L.Draggable._dragging) {
    293             L.Draggable._dragging.finishDrag();
    294         }
    295         latlngs[nodeIndex]._nodeMarker.dragging._draggable._onDown(e.originalEvent);
    296     },
    297 
    298     addNode: function(index, latlng) {
    299         var nodes = this.getLatLngs(),
    300             isAddingLeft = (index === 1 && this._drawingDirection === -1),
    301             isAddingRight = (index === nodes.length - 1 && this._drawingDirection === 1);
    302         latlng = latlng.clone();
    303         this.spliceLatLngs(index, 0, latlng);
    304         this.makeNodeMarker(index);
    305         if (!isAddingLeft && (index >= 1)) {
    306             if (!isAddingRight) {
    307                 var prevNode = nodes[index - 1];
    308                 this.segmentOverlays.removeLayer(prevNode._segmentOverlay);
    309                 delete prevNode._segmentOverlay._lineNode;
    310                 delete prevNode._segmentOverlay;
    311             }
    312             this.makeSegmentOverlay(index - 1);
    313         }
    314         if (!isAddingRight) {
    315             this.makeSegmentOverlay(index);
    316         }
    317         if (nodes.length < 3) {
    318             this._setupEndMarkers();
    319         }
    320     },
    321 
    322     removeNode: function(index) {
    323         var nodes = this.getLatLngs(),
    324             node = nodes[index],
    325             marker = node._nodeMarker;
    326         delete node._nodeMarker;
    327         delete marker._lineNode;
    328         this.spliceLatLngs(index, 1);
    329         this.nodeMarkers.removeLayer(marker);
    330         if (node._segmentOverlay) {
    331             this.segmentOverlays.removeLayer(node._segmentOverlay);
    332             delete node._segmentOverlay._lineNode;
    333             delete node._segmentOverlay;
    334         }
    335         var prevNode = nodes[index - 1];
    336         if (prevNode && prevNode._segmentOverlay) {
    337             this.segmentOverlays.removeLayer(prevNode._segmentOverlay);
    338             delete prevNode._segmentOverlay._lineNode;
    339             delete prevNode._segmentOverlay;
    340             if ((index < nodes.length - 1) || (index < nodes.length && this._drawingDirection !== 1)) {
    341                 this.makeSegmentOverlay(index - 1);
    342             }
    343         }
    344     },
    345 
    346     replaceNode: function(index, latlng) {
    347         var nodes = this.getLatLngs(),
    348             oldNode = nodes[index],
    349             oldMarker = oldNode._nodeMarker;
    350         this.nodeMarkers.removeLayer(oldNode._nodeMarker);
    351         delete oldNode._nodeMarker;
    352         delete oldMarker._lineNode;
    353         latlng = latlng.clone();
    354         this.spliceLatLngs(index, 1, latlng);
    355         this.makeNodeMarker(index);
    356         if (oldNode._segmentOverlay) {
    357             this.segmentOverlays.removeLayer(oldNode._segmentOverlay);
    358             delete oldNode._segmentOverlay._lineNode;
    359             delete oldNode._segmentOverlay;
    360             this.makeSegmentOverlay(index);
    361         }
    362         var prevNode = nodes[index - 1];
    363         if (prevNode && prevNode._segmentOverlay) {
    364             this.segmentOverlays.removeLayer(prevNode._segmentOverlay);
    365             delete prevNode._segmentOverlay._lineNode;
    366             delete prevNode._segmentOverlay;
    367             this.makeSegmentOverlay(index - 1);
    368         }
    369     },
    370 
    371     _setupEndMarkers: function() {
    372         const nodesCount = this._latlngs.length;
    373         if (nodesCount === 0) {
    374             return;
    375         }
    376         const startIndex = this._drawingDirection === -1 ? 1 : 0;
    377         const endIndex = this._drawingDirection === 1 ? nodesCount - 2 : nodesCount - 1;
    378         const startIcon = this._latlngs[startIndex]._nodeMarker._icon;
    379         L.DomUtil[this._drawingDirection === -1 ? 'removeClass' : 'addClass'](
    380             startIcon, 'line-editor-node-marker-start'
    381         );
    382         if (endIndex >= 0) {
    383             const endIcon = this._latlngs[endIndex]._nodeMarker._icon;
    384             let func;
    385             if (this._drawingDirection !== 1 && endIndex > 0) {
    386                 func = L.DomUtil.addClass;
    387             } else {
    388                 func = L.DomUtil.removeClass;
    389             }
    390             func(endIcon, 'line-editor-node-marker-end');
    391         }
    392     },
    393 
    394     setupMarkers: function() {
    395         if (!this.segmentOverlays) {
    396             this.segmentOverlays = L.featureGroup().addTo(this._map);
    397         }
    398         if (!this.nodeMarkers) {
    399             this.nodeMarkers = L.featureGroup().addTo(this._map);
    400         }
    401         this.removeMarkers();
    402         var latlngs = this.getLatLngs(),
    403             startNode = 0,
    404             endNode = latlngs.length - 1;
    405         if (this._drawingDirection === -1) {
    406             startNode += 1;
    407         }
    408         if (this._drawingDirection === 1) {
    409             endNode -= 1;
    410         }
    411         for (var i = startNode; i <= endNode; i++) {
    412             this.makeNodeMarker(i);
    413             if (i < endNode) {
    414                 this.makeSegmentOverlay(i);
    415             }
    416         }
    417         this._setupEndMarkers();
    418     },
    419 
    420     spliceLatLngs: function(...args) {
    421         const latlngs = this.getLatLngs();
    422         const res = latlngs.splice(...args);
    423         this.setLatLngs(latlngs);
    424         this.fire('nodeschanged');
    425         return res;
    426         // this._latlngs.splice(...args);
    427         // this.redraw();
    428     },
    429 
    430     getFixedLatLngs: function() {
    431         const start = this._drawingDirection === -1 ? 1 : 0;
    432         let end = this._latlngs.length;
    433         if (this._drawingDirection === 1) {
    434             end -= 1;
    435         }
    436         return this._latlngs.slice(start, end);
    437     },
    438 
    439     disableEditOnLeftClick: function(disable) {
    440         this._disableEditOnLeftClick = disable;
    441     },
    442 
    443     highlighNodesForDeletion: function(startNodeIndex, endNodeIndex) {
    444         if (!this._editing) {
    445             return;
    446         }
    447         const nodes = this.getLatLngs();
    448         for (let i = 0; i < nodes.length; i++) {
    449             const node = nodes[i];
    450             const icon = node._nodeMarker._icon;
    451             L.DomUtil[i >= startNodeIndex && i <= endNodeIndex ? 'addClass' : 'removeClass'](icon, 'highlight-delete');
    452         }
    453     }
    454 };