Fit map to feature layer bounds in react-leaflet

懵懂的女人 提交于 2019-12-06 06:15:27

Because the contents of the Map are unavailable at componentDidMount-time (https://github.com/PaulLeCam/react-leaflet/issues/106#issuecomment-161594328) you cannot get the bounds of the FeatureGroup at that point, and out of all the refs you assign, only the Map ref will be available in this.refs.

However, as per this GitHub comment: https://github.com/PaulLeCam/react-leaflet/issues/106#issuecomment-366263225 you can give a FeatureGroup an onAdd handler function:

<FeatureGroup ref="features" onAdd={this.onFeatureGroupAdd}>...

and you can then use the Map refs to access the leafletElement and call fitBounds with the bounds of the incoming event target, which will be the FeatureGroup:

  onFeatureGroupAdd = (e) => {
    this.refs.map.leafletElement.fitBounds(e.target.getBounds());
  }

This will then "zoom" the map into the bounds of your FeatureGroup, as desired.

Update

I modified my React component so that zoom and centre are controlled by query parameters. The problem with the above solution was that if you zoomed in on a MarkerClusterGroup by clicking on it, for example, it would update the zoom in the url, re-render the map and re-call onFeatureGroupAdd, thus undoing all the marker cluster goodness.

What I needed was to access the zoom level required to keep the newly drawn circle nicely in bounds, then update the url with the correct zoom level and center.

  onDrawCircle = (e) => {
    ...
    var targetZoom = this.refs.map.leafletElement.getBoundsZoom(e.layer.getBounds());
        // Call function to update url here:
        functionToUpdateUrl(targetZoom, e.layer.getBounds().getCenter());
    }
  }

In order to be able to control the whole map I also call functionToUpdateUrl in onZoomEnd and onDragEnd event handlers, like so:

  onChangeView = (e) => {
      functionToUpdateUrl(e.target._zoom, this.refs.map.leafletElement.getCenter());
  }

and one for handling cluster clicks:

  onClusterClick = (e) => {
     // This time we want the center of the layer, not the map?
     functionToUpdateUrl(e.target._zoom, (e.layer ? e.layer.getBounds().getCenter() : e.target.getBounds().getCenter()));
  }

Then, when rendering the Map element, pass these properties:

  <Map
    center={center}
    ref='map'
    zoom={zoom}
    maxZoom={18}
    onZoomEnd={this.onChangeView}
    onDragEnd={this.onChangeView}
  >
  ....
  </Map>

And remember to give any MarkerClusterGroups their onClusterClick callback:

<MarkerClusterGroup onAdd={this.onMarkerGroupAdd} onClusterClick={this.onClusterClick}>

Have you tried doing getBounds in the componentDidMount function instead of componentWillMount? If that doesn't work then I'd suggest extending the FeatureGroup component and adding an onLoaded function as as prop and call that function in the componentDidMount function of your extended component. And by extending the FeatureGroup component I actually mean copying/pasting it from here. (if you care about why you need to copy that whole file check this thread)

This isn't tested but your code will probably look something like

import { FeatureGroup } from 'leaflet';

import { withLeaflet, Path } from 'react-leaflet';

class CustomFeatureGroup extends Path {
  createLeafletElement(prop) {
    const el = new FeatureGroup(this.getOptions(props));
    this.contextValue = {
      ...props.leaflet,
      layerContainer: el,
      popupContainer: el,
    };
    return el;
  }

  componentDidMount() {
    super.componentDidMount();
    this.setStyle(this.props);
    /*
     Here you can do your centering logic with an onLoad callback or just
     by using this.leafletElement.map or whatever
    */
    this.props.onLoaded();
  }
}

export default withLeaflet(CustomFeatureGroup)

Note: If you are using react-leaflet V1 this is actually way easier and I can edit this answer with that code if needed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!