mapbox / mapbox.js

Mapbox JavaScript API, a Leaflet Plugin
mapbox.com/mapbox.js/
Other
1.92k stars 385 forks source link

Set map container center on zoom #1266

Open facundopereztomasek opened 6 years ago

facundopereztomasek commented 6 years ago

I used different side windows on top of mapbox, like search results and item details. The mapbox container's width is 100% always, even when side windows are visible. I needed to change the zoom center, so when the user clicks zoom-in or zoom-out, the zoom center is the middle of the visible area of the background map.

Before side window showing up, the ZoomIn and ZoomOut controls should zoom with the white circle as center of zoom. 45502876-8ff67200-b75b-11e8-83d3-9adcb2c3c63c3

After side window showing up, the ZoomIn and ZoomOut controls should zoom with the white circle as center of zoom. 45502876-8ff67200-b75b-11e8-83d3-9adcb2c3c63c2

I solved it modifying the map object method setZoom:

  // @method setZoom(zoom: Number, options: Zoom/pan options): this
  // Sets the zoom of the map.
  setZoom: function (zoom, options) {
    if (!this._loaded) {
      this._zoom = zoom;
      return this;
    }
    var offsetX = this.options.mapOffset
    var centerPoint = this.getSize()
    var deltaX = this.getSize().x * (this._zoom < zoom
      // zoom in
      ? (1 + offsetX * 2) / 4
      // zoom out
      : (1 - offsetX)
    )
    var centerPointWithOffset = new L.Point(deltaX , centerPoint.y/2)
    var centerLayerPoint = this.containerPointToLayerPoint(centerPointWithOffset);
    var center = new L.Point(centerLayerPoint.x , centerLayerPoint.y)
    var centerLatLng = this.layerPointToLatLng(center);
    return this.setView(centerLatLng, zoom, {zoom: options});
  },

It worked, but it's seems a bit smelly to me.

Is there another way to achieve this? If not, it could be a necessary feature for single page apps with side menus, as it happened to me.

Thanks

raxod502 commented 4 years ago

I likewise hacked around the problem with some manual geometry corrections. Unfortunately this makes the animation a little wonky (the apparent center of the map doesn't move monotonically) but at least it zooms to the right place. Proper support for constraining geometry to a subset of the canvas would be a godsend!

            onClick={() => {
              let { lng, lat } = window.map.getCenter();
              let zoom = window.map.getZoom() + 1;
              // Correction for sidebar.
              if (this.props.showingSidebar) {
                if (this.props.sidebarVertical) {
                  lng -=
                    (sidebarWidthFraction / 4) *
                    (window.map.getBounds().getEast() -
                      window.map.getBounds().getWest());
                } else {
                  lat +=
                    (sidebarHeightFraction / 4) *
                    (window.map.getBounds().getNorth() -
                      window.map.getBounds().getSouth());
                }
              }
              window.map &&
                window.map.easeTo({
                  zoom: zoom,
                  center: { lng, lat },
                });
            }}