nakarte

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

fixWorldCopyJump.js (5518B)


      1 import L from 'leaflet';
      2 
      3 function shiftLongitudeToTarget(lng, targetLng) {
      4     if (targetLng instanceof L.LatLngBounds) {
      5         if (!targetLng.isValid()) {
      6             return 0;
      7         }
      8         targetLng = targetLng.getCenter().lng;
      9     } else {
     10         targetLng = targetLng.lng ?? targetLng;
     11     }
     12     let shift = 0;
     13     if (Math.abs(lng + 360 - targetLng) < Math.abs(lng - targetLng)) {
     14         shift = 360;
     15     } else if (Math.abs(lng - 360 - targetLng) < Math.abs(lng - targetLng)) {
     16         shift = -360;
     17     }
     18     return shift;
     19 }
     20 
     21 function wrapLatLngToTarget(latLng, targetLng) {
     22     const shift = shiftLongitudeToTarget(latLng.lng, targetLng);
     23     return L.latLng(latLng.lat, latLng.lng + shift);
     24 }
     25 
     26 function wrapLatLngBoundsToTarget(latLngBounds, targetLng) {
     27     const shift = shiftLongitudeToTarget(latLngBounds.getCenter().lng, targetLng);
     28     const p1 = latLngBounds.getSouthEast();
     29     const p2 = latLngBounds.getNorthWest();
     30     return L.latLngBounds([[p1.lat, p1.lng + shift], [p2.lat, p2.lng + shift]]);
     31 }
     32 
     33 function fixVectorMarkerWorldJump() {
     34     L.Polyline.prototype.shiftProjectedFitMapView = function() {
     35         const polylineBounds = this.getBounds();
     36         let shift = null;
     37         if (this._map && polylineBounds.isValid()) {
     38             const worldWidth = this._map.getPixelWorldBounds().getSize().x;
     39             const polylineCenter = polylineBounds.getCenter();
     40             const mapCenter = this._map.getCenter();
     41 
     42             if (polylineCenter.lng < mapCenter.lng - 180) {
     43                 shift = worldWidth;
     44             } else if (polylineCenter.lng > mapCenter.lng + 180) {
     45                 shift = -worldWidth;
     46             } else {
     47                 shift = 0;
     48             }
     49         }
     50         return shift;
     51     };
     52 
     53     // Shift line points longitude by +360 or -360, to minimize distance between line center and map view center
     54     // Longitude is changed only for display, longitude of pints is not changed
     55     // Breaks dipslay of lines spanning more then one world copy
     56     L.Polyline.prototype._projectLatlngs = function(latlngs, result, projectedBounds) {
     57         var flat = latlngs[0] instanceof L.LatLng,
     58             len = latlngs.length,
     59             i, ring;
     60         let shift = null;
     61         if (this.options.projectedShift) {
     62             shift = this.options.projectedShift();
     63         }
     64         if (shift === null) {
     65             shift = this.shiftProjectedFitMapView();
     66         }
     67 
     68         if (flat) {
     69             ring = [];
     70             for (i = 0; i < len; i++) {
     71                 let p = this._map.latLngToLayerPoint(latlngs[i]);
     72                 p.x += shift;
     73                 ring[i] = p;
     74                 projectedBounds.extend(p);
     75             }
     76             result.push(ring);
     77         } else {
     78             for (i = 0; i < len; i++) {
     79                 this._projectLatlngs(latlngs[i], result, projectedBounds);
     80             }
     81         }
     82     };
     83 
     84     // Shift marker longitude by +360 or -360, which is closer to map view center
     85     // Longitude is changed only for positioning html-element, Marker._latlng is not changed
     86     // Breaks display of markers with huge longitudes like 750 (can be displayed only at zoom levels 0 or 1)
     87     L.Marker.prototype.update = function() {
     88         if (this._icon) {
     89             var pos = this._map.latLngToLayerPoint(this._latlng).round();
     90             let shift = null;
     91             if (this.options.projectedShift) {
     92                 shift = this.options.projectedShift();
     93             }
     94             if (shift === null) {
     95                 const mapCenter = this._map.getCenter();
     96                 const worldWidth = this._map.getPixelWorldBounds().getSize().x;
     97                 if (this._latlng.lng < mapCenter.lng - 180) {
     98                     shift = worldWidth;
     99                 } else if (this._latlng.lng > mapCenter.lng + 180) {
    100                     shift = -worldWidth;
    101                 } else {
    102                     shift = 0;
    103                 }
    104             }
    105             pos.x += shift;
    106             this._setPos(pos);
    107         }
    108 
    109         return this;
    110     };
    111 
    112     // Emit viewreset event when longitude of map view center changes more then 90 degrees from prevoius reset
    113     L.Map.addInitHook(function() {
    114         this._lastResetLongitude = null;
    115         this.on('viewreset', () => {
    116             this._lastResetLongitude = this.getCenter().lng;
    117         });
    118 
    119         this.on('move', () => {
    120             const lng = this.getCenter().lng;
    121             if (this._lastResetLongitude === null) {
    122                 this._lastResetLongitude = lng;
    123             } else if (Math.abs(lng - this._lastResetLongitude) > 90) {
    124                 this.fire('viewreset');
    125             }
    126         });
    127     });
    128 
    129     // Avoid marker longitude change from 180 to -180 while dragging.
    130     L.Handler.MarkerDrag.prototype._onDrag = function(e) {
    131         var marker = this._marker,
    132             shadow = marker._shadow,
    133             iconPos = L.DomUtil.getPosition(marker._icon),
    134             latlng = marker._map.layerPointToLatLng(iconPos);
    135         // update shadow position
    136         if (shadow) {
    137             L.DomUtil.setPosition(shadow, iconPos);
    138         }
    139 
    140         latlng = wrapLatLngToTarget(latlng, marker._latlng);
    141         marker._latlng = latlng;
    142         e.latlng = latlng;
    143         e.oldLatLng = this._oldLatLng;
    144 
    145         // @event drag: Event
    146         // Fired repeatedly while the user drags the marker.
    147         marker
    148             .fire('move', e)
    149             .fire('drag', e);
    150     };
    151 }
    152 
    153 export {wrapLatLngToTarget, fixVectorMarkerWorldJump, wrapLatLngBoundsToTarget};