September 9, 2024
To center the map with a lot of markers and zoom in on the area with markers,
we need to use the center
and bounds
properties for the map. But how can you find the center of
the markers?
Here is a simple example of how to do it:
import React, { useMemo } from "react";
import Link from "next/link";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
const Map = ({ locations }) => {
const { defaultCenter, bounds } = useMemo(() => {
if (locations.length === 0) return { defaultCenter: [0, 0], bounds: null };
let minLat = Infinity,
maxLat = -Infinity,
minLng = Infinity,
maxLng = -Infinity;
locations.forEach((loc) => {
minLat = Math.min(minLat, loc.lat);
maxLat = Math.max(maxLat, loc.lat);
minLng = Math.min(minLng, loc.lng);
maxLng = Math.max(maxLng, loc.lng);
});
const defaultCenter = [(minLat + maxLat) / 2, (minLng + maxLng) / 2];
const bounds = [
[minLat, minLng],
[maxLat, maxLng],
];
return { defaultCenter, bounds };
}, [locations]);
return (
<MapContainer
center={defaultCenter}
bounds={bounds}
style={{ height: "400px", width: "100%", borderRadius: "10px" }}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution={null}
/>
{locations.map((location, index) => (
<Marker key={index} position={[location.lat, location.lng]} color="red">
<Popup>
<Link
href={`https://maps.google.com/?q=${location.lat},${location.lng}`}
>
Click here!
</Link>
</Popup>
</Marker>
))}
</MapContainer>
);
};
export default Map;
Let’s break down the algorithm used to calculate the defaultCenter
and bounds
:
const { defaultCenter, bounds } = useMemo(() => {
if (locations.length === 0) return { defaultCenter: [0, 0], bounds: null };
let minLat = Infinity,
maxLat = -Infinity,
minLng = Infinity,
maxLng = -Infinity;
locations.forEach((loc) => {
minLat = Math.min(minLat, loc.lat);
maxLat = Math.max(maxLat, loc.lat);
minLng = Math.min(minLng, loc.lng);
maxLng = Math.max(maxLng, loc.lng);
});
const defaultCenter = [(minLat + maxLat) / 2, (minLng + maxLng) / 2];
const bounds = [
[minLat, minLng],
[maxLat, maxLng],
];
return { defaultCenter, bounds };
}, [locations]);
First, we loop through all our location markers. As we go, we’re keeping track of four key values:
It’s like drawing an imaginary box around all our markers, and we’re finding the edges of that box.
Once we’ve found these extremes, we use them to calculate two important things:
a) The center point: We find this by taking the average of our latitude extremes and the average of our longitude extremes. It’s like finding the middle of our imaginary box.
b) The bounds: This is essentially our imaginary box defined as coordinates. It’s represented by two points: the southwest corner (min lat, min lng) and the northeast corner (max lat, max lng).
We then pass these calculated values back to our Map component:
defaultCenter
is used to initially position the map view.bounds
are used to ensure that all our markers fit within the visible area of the map.This approach works well because it automatically adjusts the map view based on the spread of our markers. Whether they’re all clustered in one city or spread across a continent, the map will always show them all!