Skip to content
Advertisement

How to Set Leaflet Map’s Zoom to Show All Markers in React Leaflet?

I have a React Leaflet map that needs to change its center and zoom when given a set of markers. The zoom should be changed such that all the markers are visible.

This change of view is currently being attempted using the function ChangeView.

Using my code below, I am able to move the map view, but not able to let the map fit to the bounds. Running the code gives the error:

Error: Bounds are not valid.

on the line

map.fitBounds(markerBounds)

What can we do? Thanks!

import L, { LatLng, latLngBounds, FeatureGroup } from 'leaflet';
import React from 'react';
import { MapContainer, TileLayer, Marker, Popup, useMap } from 'react-leaflet';
import MarkerClusterGroup from 'react-leaflet-markercluster';

import { LatLon, MapMarker } from '../../common/types';
import { config } from '../../config';

interface IProps {
    markers: MapMarker[];
    searchCenter: LatLon;
}

interface IChangeView {
    center: LatLon;
    markers: MapMarker[];
}

function ChangeView({ center, markers }: IChangeView) {
    const map = useMap();
    map.setView({lng: center.lon, lat: center.lat}, DEFAULT_ZOOM);
    
    let markerBounds = latLngBounds([]);
    markers.forEach(marker => {
        markerBounds.extend([marker.lat, marker.lon])
    })
    map.fitBounds(markerBounds)   // <===== Error: Bounds are not valid.
    return null;
}


export function MapView({markers, searchCenter}: IProps): JSX.Element {
    
    return (
        <MapContainer
            center={[searchCenter.lat, searchCenter.lon]}
            zoom=14
            style={{ width:'100%', height:'100vh' }}
            className='markercluster-map'
        >
            <ChangeView center={searchCenter} markers={markers} />
            <TileLayer 
                url={`https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=${config.api.mapbox}`}
            />
            <MarkerClusterGroup>
                {
                    markers.map((marker, index) => (
                        <Marker 
                            position={[marker.lat, marker.lon]} 
                            key={index}
                        />
                    ))
                }
            </MarkerClusterGroup>
        </MapContainer>
    )
}

Also tried using FeatureGroup instead of latLngBounds, but it gave the exact same error

Error: Bounds are not valid

    let group = new FeatureGroup();
    markers.forEach(marker => {
        L.marker([marker.lat, marker.lon]).addTo(group);
    })
    map.fitBounds(group.getBounds());

Advertisement

Answer

If the markers array is empty, or null, the bounds you create will not have ._southWest and ._northEast properties, and that error will throw. Just make the fitBounds statement conditional on there being markers in the array:

if (markers.length && markers.length > 0){
  markers.forEach(marker => {
    markerBounds.extend([marker.lat, marker.lon])
  })
  map.fitBounds(markerBounds)
}

Or even just a quick one liner:

markerBounds.isValid() && map.fitBounds(markerBounds)
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement