commit 0dbeead3aff7b95c75728b650697734caaf3f4e1
parent 6a74ae81795db22b22d75848ff0d5a5ab7f35842
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Thu, 1 Nov 2018 22:25:53 +0100
Merge branch '140-fix-markers-paths-jump' into release-5
Diffstat:
5 files changed, 208 insertions(+), 17 deletions(-)
diff --git a/src/lib/leaflet.control.azimuth/index.js b/src/lib/leaflet.control.azimuth/index.js
@@ -65,20 +65,32 @@ L.Control.Azimuth = L.Control.extend({
const iconSingle = L.icon({iconUrl: iconPointer, iconSize: [30, 30]});
const iconStart = L.icon({iconUrl: iconPointerStart, iconSize: [30, 30]});
const iconEnd = L.icon({iconUrl: iconPointerEnd, iconSize: [30, 45]});
+ this.azimuthLine = L.polyline([], {interactive: false, weight: 1.5});
this.markers = {
single: L.marker([0, 0], {icon: iconSingle, draggable: true, which: 'start'})
.on('drag', this.onMarkerDrag, this)
.on('click', L.DomEvent.stopPropagation),
- start: L.marker([0, 0], {icon: iconStart, draggable: true, which: 'start', rotationOrigin: 'center center'})
+ start: L.marker([0, 0], {
+ icon: iconStart,
+ draggable: true,
+ which: 'start',
+ rotationOrigin: 'center center',
+ projectedShift: () => this.azimuthLine.shiftProjectedFitMapView()
+ })
.on('drag', this.onMarkerDrag, this)
.on('click', L.DomEvent.stopPropagation)
.on('dragend', this.onMarkerDragEnd, this),
- end: L.marker([0, 0], {icon: iconEnd, draggable: true, which: 'end', rotationOrigin: 'center center'})
+ end: L.marker([0, 0], {
+ icon: iconEnd,
+ draggable: true,
+ which: 'end',
+ rotationOrigin: 'center center',
+ projectedShift: () => this.azimuthLine.shiftProjectedFitMapView()
+ })
.on('drag', this.onMarkerDrag, this)
.on('click', L.DomEvent.stopPropagation)
.on('dragend', this.onMarkerDragEnd, this)
};
- this.azimuthLine = L.polyline([], {interactive: false, weight: 1.5});
},
onAdd: function(map) {
diff --git a/src/lib/leaflet.fixes/fixWorldCopyJump.js b/src/lib/leaflet.fixes/fixWorldCopyJump.js
@@ -0,0 +1,138 @@
+import L from 'leaflet';
+
+function wrapLongitudeToTarget(latLng, targetLatLng) {
+ const targetLng = targetLatLng.lng;
+ const lng = latLng.lng;
+ let newLng;
+ if (Math.abs(lng + 360 - targetLng) < Math.abs(lng - targetLng)) {
+ newLng = lng + 360;
+ } else if (Math.abs(lng - 360 - targetLng) < Math.abs(lng - targetLng)) {
+ newLng = lng - 360;
+ } else {
+ return latLng;
+ }
+ return L.latLng(latLng.lat, newLng);
+}
+
+function fixVectorMarkerWorldJump() {
+ L.Polyline.prototype.shiftProjectedFitMapView = function() {
+ const polylineBounds = this.getBounds();
+ let shift = null;
+ if (this._map && polylineBounds.isValid()) {
+ const worldWidth = this._map.getPixelWorldBounds().getSize().x;
+ const polylineCenter = polylineBounds.getCenter();
+ const mapCenter = this._map.getCenter();
+
+ if (polylineCenter.lng < mapCenter.lng - 180) {
+ shift = worldWidth
+ } else if (polylineCenter.lng > mapCenter.lng + 180) {
+ shift = -worldWidth;
+ } else {
+ shift = 0;
+ }
+ }
+ return shift;
+ };
+
+
+ // Shift line points longitude by +360 or -360, to minimize distance between line center and map view center
+ // Longitude is changed only for display, longitude of pints is not changed
+ // Breaks dipslay of lines spanning more then one world copy
+ L.Polyline.prototype._projectLatlngs = function(latlngs, result, projectedBounds) {
+ var flat = latlngs[0] instanceof L.LatLng,
+ len = latlngs.length,
+ i, ring;
+ let shift = null;
+ if (this.options.projectedShift) {
+ shift = this.options.projectedShift();
+ }
+ if (shift === null) {
+ shift = this.shiftProjectedFitMapView();
+ }
+
+ if (flat) {
+ ring = [];
+ for (i = 0; i < len; i++) {
+ let p = this._map.latLngToLayerPoint(latlngs[i]);
+ p.x += shift;
+ ring[i] = p;
+ projectedBounds.extend(p);
+ }
+ result.push(ring);
+ } else {
+ for (i = 0; i < len; i++) {
+ this._projectLatlngs(latlngs[i], result, projectedBounds);
+ }
+ }
+ };
+
+ // Shift marker longitude by +360 or -360, which is closer to map view center
+ // Longitude is changed only for positioning html-element, Marker._latlng is not changed
+ // Breaks display of markers with huge longitudes like 750 (can be displayed only at zoom levels 0 or 1)
+ L.Marker.prototype.update = function() {
+ if (this._icon) {
+ var pos = this._map.latLngToLayerPoint(this._latlng).round();
+ let shift = null;
+ if (this.options.projectedShift) {
+ shift = this.options.projectedShift();
+ }
+ if (shift === null) {
+ const mapCenter = this._map.getCenter();
+ const worldWidth = this._map.getPixelWorldBounds().getSize().x;
+ if (this._latlng.lng < mapCenter.lng - 180) {
+ shift = worldWidth;
+ } else if (this._latlng.lng > mapCenter.lng + 180) {
+ shift = -worldWidth;
+ } else {
+ shift = 0;
+ }
+ }
+ pos.x += shift;
+ this._setPos(pos);
+ }
+
+ return this;
+ };
+
+ // Emit viewreset event when longitude of map view center changes more then 90 degrees from prevoius reset
+ L.Map.addInitHook(function() {
+ this._lastResetLongitude = null;
+ this.on('viewreset', () => {
+ this._lastResetLongitude = this.getCenter().lng;
+ });
+
+ this.on('move', (e) => {
+ const lng = this.getCenter().lng;
+ if (this._lastResetLongitude === null) {
+ this._lastResetLongitude = lng;
+ } else if (Math.abs(lng - this._lastResetLongitude) > 90) {
+ this.fire('viewreset');
+ }
+ })
+ });
+
+ // Avoid marker longitude change from 180 to -180 while dragging.
+ L.Handler.MarkerDrag.prototype._onDrag = function(e) {
+ var marker = this._marker,
+ shadow = marker._shadow,
+ iconPos = L.DomUtil.getPosition(marker._icon),
+ latlng = marker._map.layerPointToLatLng(iconPos);
+ // update shadow position
+ if (shadow) {
+ L.DomUtil.setPosition(shadow, iconPos);
+ }
+
+ latlng = wrapLongitudeToTarget(latlng, marker._latlng);
+ marker._latlng = latlng;
+ e.latlng = latlng;
+ e.oldLatLng = this._oldLatLng;
+
+ // @event drag: Event
+ // Fired repeatedly while the user drags the marker.
+ marker
+ .fire('move', e)
+ .fire('drag', e);
+ }
+}
+
+export {wrapLongitudeToTarget, fixVectorMarkerWorldJump}
+\ No newline at end of file
diff --git a/src/lib/leaflet.fixes/index.js b/src/lib/leaflet.fixes/index.js
@@ -1,11 +1,13 @@
import L from 'leaflet';
import './style.css';
+import {fixVectorMarkerWorldJump} from './fixWorldCopyJump';
function fixAll() {
fixPanAnimationBug();
fixTouchDetection();
fixMapKeypressEvent();
fixVectorDrawWhileAnimation();
+ fixVectorMarkerWorldJump()
}
// https://github.com/Leaflet/Leaflet/issues/3575
@@ -78,4 +80,5 @@ function fixVectorDrawWhileAnimation() {
L.Renderer.__animationFixed = true;
}
+
export {fixAll}
diff --git a/src/lib/leaflet.polyline-edit/index.js b/src/lib/leaflet.polyline-edit/index.js
@@ -1,5 +1,6 @@
import L from 'leaflet';
import './edit_line.css';
+import {wrapLongitudeToTarget} from 'lib/leaflet.fixes/fixWorldCopyJump';
L.Polyline.EditMixinOptions = {
className: 'leaflet-editable-line'
@@ -85,8 +86,16 @@ L.Polyline.EditMixin = {
onMapClick: function(e) {
if (this._drawingDirection) {
- var newNodeIndex = this._drawingDirection === -1 ? 1 : this.getLatLngs().length - 1;
- this.addNode(newNodeIndex, e.latlng);
+ let newNodeIndex,
+ refNodeIndex;
+ if (this._drawingDirection === -1) {
+ newNodeIndex = 1;
+ refNodeIndex = 0;
+ } else {
+ newNodeIndex = this._latlngs.length - 1;
+ refNodeIndex = this._latlngs.length - 1;
+ }
+ this.addNode(newNodeIndex, wrapLongitudeToTarget(e.latlng, this._latlngs[refNodeIndex]));
} else {
if (!this.preventStopEdit) {
this.stopEdit(true);
@@ -177,18 +186,21 @@ L.Polyline.EditMixin = {
onMouseMoveFollowEndNode: function(e) {
var nodeIndex = this._drawingDirection === -1 ? 0 : this.getLatLngs().length - 1;
- this.spliceLatLngs(nodeIndex, 1, e.latlng);
+ let latlng = e.latlng;
+ if (this._latlngs.length > 0) {
+ latlng = wrapLongitudeToTarget(latlng, this._latlngs[nodeIndex]);
+ }
+ this.spliceLatLngs(nodeIndex, 1, latlng);
this.fire('nodeschanged');
},
makeNodeMarker: function(nodeIndex) {
var node = this.getLatLngs()[nodeIndex],
marker = L.marker(node.clone(), {
- icon: L.divIcon(
- {className: 'line-editor-node-marker-halo', 'html': '<div class="line-editor-node-marker"></div>'}
- ),
+ icon: L.divIcon({className: 'line-editor-node-marker-halo', 'html': '<div class="line-editor-node-marker"></div>'}),
draggable: true,
- zIndexOffset: this._nodeMarkersZOffset
+ zIndexOffset: this._nodeMarkersZOffset,
+ projectedShift: () => this.shiftProjectedFitMapView()
}
);
marker
@@ -235,7 +247,11 @@ L.Polyline.EditMixin = {
if (!p2) {
return;
}
- const segmentOverlay = L.polyline([p1, p2], {weight: 10, opacity: 0.0});
+ const segmentOverlay = L.polyline([p1, p2], {
+ weight: 10,
+ opacity: 0.0,
+ projectedShift: () => this.shiftProjectedFitMapView()
+ });
segmentOverlay.on('mousedown', this.onSegmentMouseDownAddNode, this);
segmentOverlay.on('contextmenu', function(e) {
this.stopDrawingLine();
@@ -259,7 +275,8 @@ L.Polyline.EditMixin = {
var segmentOverlay = e.target,
latlngs = this.getLatLngs(),
nodeIndex = latlngs.indexOf(segmentOverlay._lineNode) + 1;
- this.addNode(nodeIndex, e.latlng);
+ const midPoint = L.latLngBounds(latlngs[nodeIndex], latlngs[nodeIndex - 1]).getCenter();
+ this.addNode(nodeIndex, wrapLongitudeToTarget(e.latlng, midPoint));
if (L.Draggable._dragging) {
L.Draggable._dragging.finishDrag()
}
diff --git a/src/lib/leaflet.polyline-measure/index.js b/src/lib/leaflet.polyline-measure/index.js
@@ -32,7 +32,8 @@ L.MeasuredLine = L.Polyline.extend({
this._ticks = {};
this.updateTicks();
this._map.on('zoomend', this.updateTicks, this);
- this._map.on('dragend', this.updateTicks, this);
+ // markers are created only for visible part of map, need to update when it changes
+ this._map.on('moveend', this.updateTicks, this);
this.on('nodeschanged', this.updateTicksLater, this);
},
@@ -42,7 +43,7 @@ L.MeasuredLine = L.Polyline.extend({
onRemove: function(map) {
this._map.off('zoomend', this.updateTicks, this);
- this._map.off('dragend', this.updateTicks, this);
+ this._map.off('moveend', this.updateTicks, this);
this.off('nodeschanged', this.updateTicks, this);
this._clearTicks();
L.Polyline.prototype.onRemove.call(this, map);
@@ -69,7 +70,12 @@ L.MeasuredLine = L.Polyline.extend({
className: 'measure-tick-icon'
}
);
- marker = L.marker(tick.position, {icon: icon, interactive: false, keyboard: false});
+ marker = L.marker(tick.position, {
+ icon: icon,
+ interactive: false,
+ keyboard: false,
+ projectedShift: () => this.shiftProjectedFitMapView(),
+ });
marker.addTo(this._map);
}
this._ticks[tick.distanceValue.toString()] = marker;
@@ -84,10 +90,24 @@ L.MeasuredLine = L.Polyline.extend({
var steps = [500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000];
var ticks = [];
+ const self = this;
function addTick(position, segment, distanceValue) {
- if (bounds && (!bounds.contains(position))) {
- return;
+ if (bounds) {
+ // create markers only in visible part of map
+ const normalizedBounds = self._map.wrapLatLngBounds(bounds);
+ const normalizedPosition = position.wrap();
+ // account for worldCopyJump
+ const positionMinus360 = L.latLng(normalizedPosition.lat, normalizedPosition.lng - 360);
+ const positionPlus360 = L.latLng(normalizedPosition.lat, normalizedPosition.lng + 360);
+ if (
+ !normalizedBounds.contains(normalizedPosition) &&
+ !normalizedBounds.contains(positionMinus360) &&
+ !normalizedBounds.contains(positionPlus360)
+ ) {
+ return;
+ }
}
+
var sinCos = sinCosFromLatLonSegment(segment),
sin = sinCos[0], cos = sinCos[1],
transformMatrix;