Leaflet.Sync icon indicating copy to clipboard operation
Leaflet.Sync copied to clipboard

Offset zoom

Open moravcik opened this issue 7 years ago • 6 comments

What about to support also zoom offset in offsetFn ?

The offsetFn(center, zoom, refMap, tgtMap) could return:

{
  center: L.LatLng,
  zoom: number
}

instead of just L.LatLng, in order to use both center and zoom in the setView() call of synced map.

moravcik avatar May 26 '17 14:05 moravcik

Interesting thought, can you show how much change is required?

jieter avatar May 30 '17 06:05 jieter

I did the modification locally for a project I'm working on. There are just a few lines to change (the goolge layer modif is not finished thought). For retro-compatibility & old browser compatibility, the modifications should be adapted.

49c49
<                     return center;
---
>                     return { center, zoom };
59a60
>                 const { center, zoom } = options.offsetFn(this.getCenter(), this.getZoom(), this, map);
61,62c62,63
<                     options.offsetFn(this.getCenter(), this.getZoom(), this, map),
<                     this.getZoom(), NO_ANIMATION);
---
>                     center,
>                     zoom, NO_ANIMATION);
214,216c215,216
<                                 return toSync.setView(
<                                     originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync),
<                                     zoom, options, true);
---
>                                 const offsetData = originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync);
>                                 return toSync.setView(offsetData.center, offsetData.zoom, options, true);
260c260
<                             var center = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync);
---
>                             const {center, zoom} = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync);

nmoreaud avatar Jul 28 '20 15:07 nmoreaud

Well, I didn't check everything : when I pan the map it should move according to the zoom difference. There is also the offsetHelper function to update.

nmoreaud avatar Jul 28 '20 15:07 nmoreaud

Ok, so here is a version that handles :

  • pan with keyboard arrows
  • pan with mouse
  • offsetHelper with both offset and zoom (added zoomDiff argument, ex : -2 : the synced map will have zoom 3 when the original map has zoom 5)

There is a very little modification to make google layer work. Do you want to integrate this ?

Regards

21c21
<     L.Sync.offsetHelper = function (ratioRef, ratioTarget) {
---
>     L.Sync.offsetHelper = function (ratioRef, ratioTarget, zoomDiff) {
23a24
>         var zoomFactor = Math.pow((zoomDiff > 0) ? .5 : 2, Math.abs(zoomDiff));
24a26,27
>             var targetZoom = zoom + zoomDiff;
>             var ot2 = zoomFactor == 1 ? ot : ot.map(val => ((val-.5) * zoomFactor)+.5);
29,30c32,33
<                            .add([(0.5 - ot[0]) * ts.x, (0.5 - ot[1]) * ts.y]);
<             return refMap.unproject(pt, zoom);
---
>                            .add([(0.5 - ot2[0]) * ts.x, (0.5 - ot2[1]) * ts.y]);
>             return { center: refMap.unproject(pt, zoom), zoom: targetZoom };
49c52
<                     return center;
---
>                     return { center, zoom };
59a63
>                 const { center, zoom } = options.offsetFn(this.getCenter(), this.getZoom(), this, map);
61,62c65,66
<                     options.offsetFn(this.getCenter(), this.getZoom(), this, map),
<                     this.getZoom(), NO_ANIMATION);
---
>                     center,
>                     zoom, NO_ANIMATION);
152a157,167
>         _zoomFactorTo: function(syncedMap) {
>             const zoom = this.getZoom();
>             const toSyncZoom = syncedMap.getZoom();
>             if (zoom == toSyncZoom) {
>                 return 1;
>             }
>             const zoomDiff = zoom - toSyncZoom;
>             const zoomFactor = Math.pow((zoomDiff > 0) ? .5 : 2, Math.abs(zoomDiff));
>             return zoomFactor;
>         },
> 
214,216c229,230
<                                 return toSync.setView(
<                                     originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync),
<                                     zoom, options, true);
---
>                                 const offsetData = originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync);
>                                 return toSync.setView(offsetData.center, offsetData.zoom, options, true);
227c241,243
<                             toSync.panBy(offset, options, true);
---
>                             const zoomFactor = originalMap._zoomFactorTo(toSync);
>                             const newOffset = (zoomFactor == 1 || ! Array.isArray(offset)) ? offset : offset.map(o => o*zoomFactor);
>                             toSync.panBy(newOffset, options, true);
255,256c271,278
<                 originalMap._syncMaps.forEach(function (toSync) {
<                     L.DomUtil.setPosition(toSync.dragging._draggable._element, self._newPos);
---
>                 originalMap._syncMaps.forEach(function (toSync) 
>                 {
>                     let newPos = self._newPos;
>                     const zoomFactor = originalMap._zoomFactorTo(toSync);
>                     if (zoomFactor != 1) {
>                         newPos = newPos.multiplyBy(zoomFactor);
>                     }
>                     L.DomUtil.setPosition(toSync.dragging._draggable._element, newPos);
260c282
<                             var center = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync);
---
>                             const {center, zoom} = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync);

nmoreaud avatar Jul 29 '20 08:07 nmoreaud

Few comments:

  • In those changes you are using syntax from ES6, like const. That means the you need a transpilation to ES5. As the rest of the plugin (and Leaflet I guess) is already in ES5, you should use that syntax instead.
  • those changes will break API compatibility. This means a change in the mayor version?
  • I guess (I have never tried it) Leaflet supports non integer zooms. Are you supporting it?

jjimenezshaw avatar Jul 29 '20 09:07 jjimenezshaw

It is possible to keep compatibility, however offsetFn returning a value center or an object {center, zoom} might be counter-intuitive. I didn't try to write something compatible with ES5 (I just share the code I use), but is can be easily fixed.

I just saw that leaflet supports fractional zoom, I didn't try to support it. There are glitches on basic maps with fractional zoom tests (white lines visible between tiles) without the sync plugin, I wont't test it further

nmoreaud avatar Jul 29 '20 12:07 nmoreaud