Kyle Pennell
Kyle Pennell

Reputation: 6117

How to manually control react-leaflet popups (via props) within a geojson layer?

I'm using react-leaflet to render a geojson feature collection that has points and linestrings: enter image description here

I was able to get the click and hover events on the actual features themselves to work just fine. But I'd like to be able to hover on a list item (related to the items on the map) and have the popup open. I've been sorting through the docs, github, and trying different things out. But it seems there's no way to do this. Or that I'll have to render my linestrings and points manually vs. using the <GeoJSON data=

My map works well with the click events:

return (
        <Map
            style={{
                height: '100%',
                width: '100%',
                margin: '0 auto'
            }}
            ref={(el) => {
                this.leafletMap = el;
            }}
            center={position}
            zoom={10}>
            <TileLayer url='https://api.mapbox.com/v4/mapbox.outdoors/{z}/{x}/{y}@2x.png?access_token=pk.eyJ1IjoiYWJlbnMwefwefEiOiJjajJ1bDRtMzcwMDssmMzJydHdvcjF6ODA5In0.xdZi4pmkhj1zb9Krr64CXw' attribution='&copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a>' />
            <GeoJSON data={locations} onEachFeature={this.onEachFeature} />{' '}
        </Map>
    );

onEachFeature works as it should

onEachFeature = (feature, layer) => {
        console.log('onEachFeature fired: ');
        layer.on({
            mouseover: (e) => this.MouseOverFeature(e, feature),
            mouseout: (e) => this.MouseOutFeature(e, feature)

        });
    };

But I don't see how to call the layer.bindPopup without using onEachFeature. How does one change call these methods using prop values? I'd like to let people hover on a list item and have it toggle the popups.

Upvotes: 2

Views: 2405

Answers (1)

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59358

You could consider to extend GeoJSON component, for example:

const GeoJSONWithLayer = props => {
  const handleOnEachFeature = (feature, layer) => {
    let popupContent = "";
    if (props.popupContent.length) popupContent = props.popupContent;
    else if (feature.properties && feature.properties.popupContent) {
      popupContent = feature.properties.popupContent;
    }

    layer.bindPopup(popupContent);
    layer.on({
      mouseover: e => {
        layer.openPopup();
      },
      mouseout: e => {
        layer.closePopup();
      }
    });
  };
  return <GeoJSON {...props} onEachFeature={handleOnEachFeature} />;
}


GeoJSONWithLayer.defaultProps = {
  popupContent: '',
}

It supports passing extra props along with default properties and contains popup binding logic for a layer. Now it could be utilized like this:

const MapExample = props => {
  const style = () => ({
    color: "green",
    weight: 20
  });

  const freeBus = {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "LineString",
          coordinates: [
            [-105.00341892242432, 39.75383843460583],
            [-105.0008225440979, 39.751891803969535],
            [-104.99820470809937, 39.74979664004068],
            [-104.98689651489258, 39.741052354709055]
          ]
        },
        properties: {
          popupContent:
            "This is a free bus line that will take you across downtown.",
          underConstruction: false
        },
        id: 1
      }
    ]
  };

  return (
    <Map zoom={14} center={{ lat: 39.74739, lng: -105 }}>
      <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
      <GeoJSONWithLayer
        popupContent={"Some content goes here..."}
        data={freeBus}
        style={style}
      />
    </Map>
  );
};

Upvotes: 5

Related Questions