I’m currently developing an application based on maps. In that application I want to represent a set of markers. In order to do so, the map library I’m using it has a fitBounds method. However, you need to compute the bounds of the map that allow all the markers to be visible. I describe in this article the implemented algorithm.

## Abstraction of latitude longitude

First of all, we need to do a nasty approximation. We can represent the earth globe, as a 2-D cartesian axis. In order to do that, we can consider latitude as the y axis and longitude as the x axis.

Longitude will be in range [-180,180] and latitude in the range [-90,90]. We can define the cardinal points in the chart:

• North -> Point in (0,90)
• East -> Point in (180,0)
• South -> Point in (0,-90)
• West -> Point in (-180,0)

We can define the bounds of a set of points using two points only: North-East point and South

• North-East -> Point in (180,90)
• South-West -> Point in (-180,-90)

We can see a visual representation of those points in the following chart:

Taking this into account we can set up some algorithm to calculate the bounds.

## Algorithm to compute the bounds

The first basic algorithm is to iterate over all points and compare the longitude (x) and latitude (y) and obtain the point with higher x and y and the point with lower x and y.

const SW: LatLngTuple = [-90, -180]
const NE: LatLngTuple = [90, 180]
export const ALL_WORLD_BOUNDS: LatLngBoundsExpression = [NE, SW]
export const getBoundsFromPoints = (points: Point[]): LatLngBoundsExpression => {

if (points.length === 0)
return ALL_WORLD_BOUNDS

let nex = 0, swx = 0, ney = 0, swy = 0
points.forEach((point) => {
if (nex === 0 && swx === 0 && ney === 0 && swy === 0) {
nex = swx = point.longitude
ney = swy = point.latitude
} else {
if (point.longitude > nex) nex = point.longitude;
if (point.longitude < swx) swx = point.longitude;
if (point.latitude > ney) ney = point.latitude;
if (point.latitude < swy) swy = point.latitude;
}
})
return [[ney, nex], [swy, swx]]
}


Bear in mind that the map library expects and array of [lat,lng], that’s why we are switching the natural order of x,y and we’re using y,x that corresponds to [lat,lng].

## Unit test

These are the unit tests that check this algorithm behaves correctly:

import {ALL_WORLD_BOUNDS, getBoundsFromPoints} from "./BoundCalculator";
import {Point} from "../../types/Point";

test("should compute bounds of an empty list", () => {
const bounds = getBoundsFromPoints([])
expect(bounds).toEqual(ALL_WORLD_BOUNDS)
})

test("should compute bounds of one point", () => {
const lat = 1, lng = 1
const point = new Point(lat, lng)
const bounds = getBoundsFromPoints([point])
expect(bounds).toEqual([[lat, lng], [lat, lng]])
})

test("should compute bounds a list of points, each point per quadrant", () => {
const lat1 = 30, lng1 = 90
const lat2 = 30, lng2 = -90
const lat3 = -30, lng3 = -90
const lat4 = -30, lng4 = 90
const point1 = new Point(lat1, lng1)
const point2 = new Point(lat2, lng2)
const point3 = new Point(lat3, lng3)
const point4 = new Point(lat4, lng4)
const bounds = getBoundsFromPoints([point1, point2, point3, point4])
expect(bounds).toEqual([[lat1, lng1], [lat3, lng3]])
})