Search code examples
mapsleafletzooming

Leaflet zoom to a point with mouse wheel


I'm working on a project which uses a Leaflet map to add new spots. So the app has 2 modes:

  1. Regular, when the map should work as usual
  2. Add new point mode, when it has a dot overlay (not in the center of the map) which stays at the same point all the time (implemented).

In the second mode, I need to override scroll wheel zooming. It should zoom only to this "new" point on the map.

I found no specific options in Leaflet which allows to select zooming anchor point.

But I suppose it's possible to implement, but I haven't understood how yet :-)

Here is a simplified schema of the app view:

enter image description here


Solution

  • Since you stress out the fact that the point where you want to zoom in not in the center of the map container, you may already be aware of the map scrollWheelZoom option:

    Whether the map can be zoomed by using the mouse wheel. If passed 'center', it will zoom to the center of the view regardless of where the mouse was.

    So the 'center' value would not exactly fit your case.

    But you should be able to easily customize how Leaflet implements the scroll wheel zoom:

    L.Map.ScrollWheelZoom.include({
      _performZoom: function() {
        var map = this._map,
          zoom = map.getZoom(),
          snap = this._map.options.zoomSnap || 0;
    
        map._stop(); // stop panning and fly animations if any
    
        // map the delta with a sigmoid function to -4..4 range leaning on -1..1
        var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
          d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
          d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
          delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
    
        this._delta = 0;
        this._startTime = null;
    
        if (!delta) {
          return;
        }
    
        if (map.options.scrollWheelZoom === 'center') {
          console.log(zoom + delta);
          map.setZoom(zoom + delta);
    
        ////////////////////////////////////////////////////////////////////////
        // Add a case where scrollWheelZoom option is an app specific point.
        } else if (map.options.scrollWheelZoom instanceof L.Point) {
          map.setZoomAround(map.options.scrollWheelZoom, zoom + delta);
        ////////////////////////////////////////////////////////////////////////
    
        } else {
          map.setZoomAround(this._lastMousePos, zoom + delta);
        }
      }
    });
    
    
    var map = L.map('map', {
      scrollWheelZoom: L.point(150, 100) // x, y
    }).setView([48.85, 2.35], 12);
    
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    #mapWrapper {
      position: relative;
    }
    
    #map {
      height: 500px;
    }
    
    #pointer {
      z-index: 2000;
      position: absolute;
      top: 100px; /* y */
      left: 150px; /* x */
      width: 5px;
      height: 5px;
      background-color: red;
    }
    <link href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css" rel="stylesheet"/>
    <script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet-src.js"></script>
    
    <div id="mapWrapper">
      <div id="map"></div>
      <div id="pointer"></div>
    </div>

    Note: I guess you have also modified the Zoom Control buttons behaviour.