forked from OpenDroneMap/UAVArena
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1e6b2e8
commit 90bf96c
Showing
3 changed files
with
409 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
// from https://github.com/jieter/Leaflet.Sync | ||
// retrieved on 2023-04-07 | ||
|
||
/* | ||
* Extends L.Map to synchronize the interaction on one map to one or more other maps. | ||
*/ | ||
|
||
(function () { | ||
var NO_ANIMATION = { | ||
animate: false, | ||
reset: true, | ||
disableViewprereset: true | ||
}; | ||
|
||
L.Sync = function () {}; | ||
/* | ||
* Helper function to compute the offset easily. | ||
* | ||
* The arguments are relative positions with respect to reference and target maps of | ||
* the point to sync. If you provide ratioRef=[0, 1], ratioTarget=[1, 0] will sync the | ||
* bottom left corner of the reference map with the top right corner of the target map. | ||
* The values can be less than 0 or greater than 1. It will sync points out of the map. | ||
*/ | ||
L.Sync.offsetHelper = function (ratioRef, ratioTarget) { | ||
var or = L.Util.isArray(ratioRef) ? ratioRef : [0.5, 0.5]; | ||
var ot = L.Util.isArray(ratioTarget) ? ratioTarget : [0.5, 0.5]; | ||
return function (center, zoom, refMap, targetMap) { | ||
var rs = refMap.getSize(); | ||
var ts = targetMap.getSize(); | ||
var pt = refMap.project(center, zoom) | ||
.subtract([(0.5 - or[0]) * rs.x, (0.5 - or[1]) * rs.y]) | ||
.add([(0.5 - ot[0]) * ts.x, (0.5 - ot[1]) * ts.y]); | ||
return refMap.unproject(pt, zoom); | ||
}; | ||
}; | ||
|
||
|
||
L.Map.include({ | ||
sync: function (map, options) { | ||
this._initSync(); | ||
options = L.extend({ | ||
noInitialSync: false, | ||
syncCursor: false, | ||
syncCursorMarkerOptions: { | ||
radius: 10, | ||
fillOpacity: 0.3, | ||
color: '#da291c', | ||
fillColor: '#fff' | ||
}, | ||
offsetFn: function (center, zoom, refMap, targetMap) { | ||
// no transformation at all | ||
return center; | ||
} | ||
}, options); | ||
|
||
// prevent double-syncing the map: | ||
if (this._syncMaps.indexOf(map) === -1) { | ||
this._syncMaps.push(map); | ||
this._syncOffsetFns[L.Util.stamp(map)] = options.offsetFn; | ||
} | ||
|
||
if (!options.noInitialSync) { | ||
map.setView( | ||
options.offsetFn(this.getCenter(), this.getZoom(), this, map), | ||
this.getZoom(), NO_ANIMATION); | ||
} | ||
if (options.syncCursor) { | ||
if (typeof map.cursor === 'undefined') { | ||
map.cursor = L.circleMarker([0, 0], options.syncCursorMarkerOptions).addTo(map); | ||
} | ||
|
||
this._cursors.push(map.cursor); | ||
|
||
this.on('mousemove', this._cursorSyncMove, this); | ||
this.on('mouseout', this._cursorSyncOut, this); | ||
} | ||
|
||
// on these events, we should reset the view on every synced map | ||
// dragstart is due to inertia | ||
this.on('resize zoomend', this._selfSetView); | ||
this.on('moveend', this._syncOnMoveend); | ||
this.on('dragend', this._syncOnDragend); | ||
return this; | ||
}, | ||
|
||
|
||
// unsync maps from each other | ||
unsync: function (map) { | ||
var self = this; | ||
|
||
if (this._cursors) { | ||
this._cursors.forEach(function (cursor, indx, _cursors) { | ||
if (cursor === map.cursor) { | ||
_cursors.splice(indx, 1); | ||
} | ||
}); | ||
} | ||
|
||
// TODO: hide cursor in stead of moving to 0, 0 | ||
if (map.cursor) { | ||
map.cursor.setLatLng([0, 0]); | ||
} | ||
|
||
if (this._syncMaps) { | ||
this._syncMaps.forEach(function (synced, id) { | ||
if (map === synced) { | ||
delete self._syncOffsetFns[L.Util.stamp(map)]; | ||
self._syncMaps.splice(id, 1); | ||
} | ||
}); | ||
} | ||
|
||
if (!this._syncMaps || this._syncMaps.length == 0) { | ||
// no more synced maps, so these events are not needed. | ||
this.off('resize zoomend', this._selfSetView); | ||
this.off('moveend', this._syncOnMoveend); | ||
this.off('dragend', this._syncOnDragend); | ||
} | ||
|
||
return this; | ||
}, | ||
|
||
// Checks if the map is synced with anything or a specifyc map | ||
isSynced: function (otherMap) { | ||
var has = (this.hasOwnProperty('_syncMaps') && Object.keys(this._syncMaps).length > 0); | ||
if (has && otherMap) { | ||
// Look for this specific map | ||
has = false; | ||
this._syncMaps.forEach(function (synced) { | ||
if (otherMap == synced) { has = true; } | ||
}); | ||
} | ||
return has; | ||
}, | ||
|
||
|
||
// Callbacks for events... | ||
_cursorSyncMove: function (e) { | ||
this._cursors.forEach(function (cursor) { | ||
cursor.setLatLng(e.latlng); | ||
}); | ||
}, | ||
|
||
_cursorSyncOut: function (e) { | ||
this._cursors.forEach(function (cursor) { | ||
// TODO: hide cursor in stead of moving to 0, 0 | ||
cursor.setLatLng([0, 0]); | ||
}); | ||
}, | ||
|
||
_selfSetView: function (e) { | ||
// reset the map, and let setView synchronize the others. | ||
this.setView(this.getCenter(), this.getZoom(), NO_ANIMATION); | ||
}, | ||
|
||
_syncOnMoveend: function (e) { | ||
if (this._syncDragend) { | ||
// This is 'the moveend' after the dragend. | ||
// Without inertia, it will be right after, | ||
// but when inertia is on, we need this to detect that. | ||
this._syncDragend = false; // before calling setView! | ||
this._selfSetView(e); | ||
this._syncMaps.forEach(function (toSync) { | ||
toSync.fire('moveend'); | ||
}); | ||
} | ||
}, | ||
|
||
_syncOnDragend: function (e) { | ||
// It is ugly to have state, but we need it in case of inertia. | ||
this._syncDragend = true; | ||
}, | ||
|
||
|
||
// overload methods on originalMap to replay interactions on _syncMaps; | ||
_initSync: function () { | ||
if (this._syncMaps) { | ||
return; | ||
} | ||
var originalMap = this; | ||
|
||
this._syncMaps = []; | ||
this._cursors = []; | ||
this._syncOffsetFns = {}; | ||
|
||
L.extend(originalMap, { | ||
setView: function (center, zoom, options, sync) { | ||
// Use this sandwich to disable and enable viewprereset | ||
// around setView call | ||
function sandwich (obj, fn) { | ||
var viewpreresets = []; | ||
var doit = options && options.disableViewprereset && obj && obj._events; | ||
if (doit) { | ||
// The event viewpreresets does an invalidateAll, | ||
// that reloads all the tiles. | ||
// That causes an annoying flicker. | ||
viewpreresets = obj._events.viewprereset; | ||
obj._events.viewprereset = []; | ||
} | ||
var ret = fn(obj); | ||
if (doit) { | ||
// restore viewpreresets event to its previous values | ||
obj._events.viewprereset = viewpreresets; | ||
} | ||
return ret; | ||
} | ||
|
||
// Looks better if the other maps 'follow' the active one, | ||
// so call this before _syncMaps | ||
var ret = sandwich(this, function (obj) { | ||
return L.Map.prototype.setView.call(obj, center, zoom, options); | ||
}); | ||
|
||
if (!sync) { | ||
originalMap._syncMaps.forEach(function (toSync) { | ||
sandwich(toSync, function (obj) { | ||
return toSync.setView( | ||
originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync), | ||
zoom, options, true); | ||
}); | ||
}); | ||
} | ||
|
||
return ret; | ||
}, | ||
|
||
panBy: function (offset, options, sync) { | ||
if (!sync) { | ||
originalMap._syncMaps.forEach(function (toSync) { | ||
toSync.panBy(offset, options, true); | ||
}); | ||
} | ||
return L.Map.prototype.panBy.call(this, offset, options); | ||
}, | ||
|
||
_onResize: function (event, sync) { | ||
if (!sync) { | ||
originalMap._syncMaps.forEach(function (toSync) { | ||
toSync._onResize(event, true); | ||
}); | ||
} | ||
return L.Map.prototype._onResize.call(this, event); | ||
}, | ||
|
||
_stop: function (sync) { | ||
L.Map.prototype._stop.call(this); | ||
if (!sync) { | ||
originalMap._syncMaps.forEach(function (toSync) { | ||
toSync._stop(true); | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
originalMap.dragging._draggable._updatePosition = function () { | ||
L.Draggable.prototype._updatePosition.call(this); | ||
var self = this; | ||
originalMap._syncMaps.forEach(function (toSync) { | ||
L.DomUtil.setPosition(toSync.dragging._draggable._element, self._newPos); | ||
toSync.eachLayer(function (layer) { | ||
if (layer._google !== undefined) { | ||
var offsetFn = originalMap._syncOffsetFns[L.Util.stamp(toSync)]; | ||
var center = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync); | ||
layer._google.setCenter(center); | ||
} | ||
}); | ||
toSync.fire('move'); | ||
}); | ||
}; | ||
} | ||
}); | ||
})(); |
Oops, something went wrong.