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};