简体   繁体   中英

How to track map zoom in react leaflet

On the page on the left side I have a map and on the right side I have a list of places. Markers for the map and a list of places comes to me from the database. I need to track the map zoom to filter the list of places and remove those places whose markers are not visible. How can i do this? How can I track the map zoom and implement such logic?

 const Map = ({ onSelect }) => { const [coordinates, setCoordinates] = useState([]); useEffect(() => { const q = query(collection(db, "map-markers")); onSnapshot(q, (querySnapshot) => { setCoordinates( querySnapshot.docs.map((doc) => ({ id: doc.id, data: doc.data(), })) ); }); }, []); return ( <div style={{ width: "100%" }}> <MapContainer center={center} zoom={13} scrollWheelZoom={false} style={{ height: "100vh" }} > <TileLayer attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> {coordinates.map((coord, index) => ( <Marker key={index} eventHandlers={{ click: () => { onSelect(index); }, }} position={[parseFloat(coord.data.lat), parseFloat(coord.data.lon)]} icon={defaultIcon} /> ))} </MapContainer> </div> ); };

 const List = ({ selectedHouse }) => { const [houseTitles, setHouseTitle] = useState([]); useEffect(() => { const q = query(collection(db, "map-markers")); onSnapshot(q, (querySnapshot) => { setHouseTitle( querySnapshot.docs.map((doc) => ({ id: doc.id, data: doc.data(), })) ); }); }, []); return ( <div style={{ width: "50%" }}> {houseTitles.map((title, index) => ( <ListItem key={index} title={title.data.title} /> ))} </div> ); };

Assuming your components are structured as follows:

<Parent>
  <List />
  <Map />
</Parent>

you could lift the state up into the Parent component (so Parent is responsible for fetching the data and storing it in React's useState ). You would need to define 2 states: allHouses (the complete list of houses) and visibleHouses (the houses in view based on the map bounds):

const [allHouses, setAllHouses] = useState([
  {
    id: 1,
    data: {
      title: 'House 1',
      lat: 52.074,
      lon: 5.217,
    },
  },
  {
    id: 2,
    data: {
      title: 'House 2',
      lat: 52.07222,
      lon: 5.221965,
    },
  },
  {
    id: 2,
    data: {
      title: 'House 3',
      lat: 52.07,
      lon: 5.215,
    },
  },
]);

const [visibleHouses, setVisibleHouses] = useState(allHouses);

For simplicity, I've hardcoded the data rather than fetching it from an API.

The state can then be passed down to the List and Map components:

<List visibleHouses={visibleHouses} />
<Map
  ...
  allHouses={allHouses}
  setVisibleHouses={setVisibleHouses}
/>

Only the visibleHouses need to be passed to the List component as we only want to display a list of the ones visible based on the map bounds. We'll need to pass allHouses along with the setVisibleHouses state setter to the Map component so that we can render all the houses on the map, and update the list of visible houses as the user moves or zooms the map.

You can use events to listen for either a map move ( dragend ) or a zoom event ( zoomend ) and then update the visibleHouses based on whether each house is in the current bounds of the map :

function MyComponent() {
  const map = useMapEvents({
    dragend: () => {
      console.log('moved');

      setVisibleHouses(
        allHouses.filter((c) =>
          map.getBounds().contains({ lat: c.data.lat, lng: c.data.lon })
        )
      );
    },
    zoomend: () => {
      console.log('zoomed');

      setVisibleHouses(
        allHouses.filter((c) =>
          map.getBounds().contains({ lat: c.data.lat, lng: c.data.lon })
        )
      );
    },
  });
  return null;
}

Because the List component renders the visibleHouses , whenever this state is updated as the result of a map move or zoom, it will cause the list to be updated accordingly.

This StackBlitz shows a working demo of this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM