⚡ GMapsBook.com is crafted by Jozef Sorocin (🟢 Book a consulting hour) and powered by:
- g-Xperts (Google Cloud & Business Profile Partner)
- Spatialized.io (Elasticsearch & Google Maps consulting).
- and Garages-Near-Me.com (Effortless parking across Germany)
Extracting CoordinatesGetting latitude & longitude of lines & polygonsPolylinesPolygonsMultipolygonsCoordinate conversionsWorking with BoundsBounding Box RecapArtifacts’ boundsExtending, merging, and fitting boundsExtending boundsMerging boundsFitting boundsBonus #1: Calculating projected bounds at zoom levelBonus #2: Calculating projected zoom level based on boundsIn this Chapter →
Extracting Coordinates
Obtaining coordinates from markers is quite straightforward — analogously to
map.getCenter()
, you’d call marker.
getPosition()
. Since that’d return a LatLng
object instance, you’d need to chain .toJSON()
to arrive at the familiar lat,lng
coordinate pair:const position = {lat: 40.7419, lng: -73.9921};
const marker = new google.maps.Marker({
map,
position,
});
const extractedPosition = marker.getPosition().getCenter();
// returns {lat: 40.7419, lng: -73.9921}
Equally straightforward is obtaining a
circle
's center — you’d need circle.getCenter().toJSON()
.But what about more complicated shapes like polylines and markers? How do you obtain their coordinates?
Getting latitude & longitude of lines & polygons
Polylines
- A polyline’s coordinates form a path.
- Calling
polygon.
getPath()
returns an MVCArray.
- Calling
polygon.getPath().
getArray()
returns an iterable list ofLatLng
objects.
- Finally, calling
.toJSON()
on each object individually produces a familiar list of coordinates.
const nycToLaFlightCoords = [
{ lat: 40.7419, lng: -73.9921 },
{ lat: 37.772, lng: -122.214 },
];
const flightPolyline = new google.maps.Polyline({
map,
path: nycToLaFlightCoords,
geodesic: true,
});
const coords = flightPolyline.getPath()
.getArray()
.map((latLng) => latLng.toJSON())
// returns [{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214}]
Polygons
A polygon’s coordinates form a closed loop. Similarly to polylines, you’ll need to call
.getPath()
and .getArray()
on the polygon object:const polygonCoords = [
{ lat: 40.7419, lng: -73.9921 },
{ lat: 37.772, lng: -122.214 },
{ lat: 32.321, lng: -64.757 },
{ lat: 40.7419, lng: -73.9921 }
];
const polygon = new google.maps.Polygon({
map,
paths: polygonCoords
});
const coords = polygon.getPath()
.getArray()
.map((latLng) => latLng.toJSON())
// returns [{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214},{"lat":32.321,"lng":-64.757},{"lat":40.7419,"lng":-73.9921}]
Multipolygons
A multipolygon’s coordinates wrap polygon loops within a “parent” array. In pseudo code:
multiPolyCoords = [
coordsOfPoly_1,
coordsOfPoly_2,
...
];
// concretely
const multiPolygonCoords = [
[
{ lat: 40.7419, lng: -73.9921 },
{ lat: 37.772, lng: -122.214 },
{ lat: 32.321, lng: -64.757 },
{ lat: 40.7419, lng: -73.9921 }
],
[
{ lat: 40.7419, lng: -73.9921 },
{ lat: 37.772, lng: -122.214 },
{ lat: 32.321, lng: -64.757 },
{ lat: 40.7419, lng: -73.9921 }
]
];
If you want to retain the individual polygon separation, use:
const multiPoly = new google.maps.Polygon({
map,
paths: multiPolygonCoords,
});
const coords = multiPoly.getPaths()
.getArray()
.map((arr) => arr.getArray().map((latLng) => latLng.toJSON()))
// returns [[{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214},{"lat":32.321,"lng":-64.757},{"lat":40.7419,"lng":-73.9921}],[{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214},{"lat":32.321,"lng":-64.757},{"lat":40.7419,"lng":-73.9921}]]
Alternatively, to flatten the coordinates, use:
const coords = triangle.getPaths()
.getArray()
.flatMap((arr) => arr.getArray())
.map((latLng) => latLng.toJSON())
// returns [{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214},{"lat":32.321,"lng":-64.757},{"lat":40.7419,"lng":-73.9921},{"lat":40.7419,"lng":-73.9921},{"lat":37.772,"lng":-122.214},{"lat":32.321,"lng":-64.757},{"lat":40.7419,"lng":-73.9921}]
Coordinate conversions
Speaking of coordinates, there is a multitude of geodetic coordinate reference systems out there, the most common of which is
WGS84
— used by GPS, Google Maps, and others. Virtually all these systems are standardized by an organization called EPSG and so each reference system has its own EPSG notation or code — WGS84
corresponds to EPSG:4326
and so on.When you encounter coordinates other than
EPSG:4326
, the data provider will likely include the EPSG code somewhere within the dataset (usually in the properties
field of a GeoJSON file, or in the metadata of other file types.) For instance, these coordinates in meters —
[360590, 555610]
— were specified as EPSG:27700
. So, if we now know the origin and the target coordinate system (:27700 → :4326), we can leverage the conversion utility proj4
to transform the meter coordinates into latitudes & longitudes.import proj4 from 'proj4';
// from https://epsg.io/27700
const EPSG_27700_DATUM = "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +no_defs";
// from https://epsg.io/4326
const WGS84_DATUM = "+proj=longlat +datum=WGS84 +no_defs";
// [x -> lon, y -> lat ]
const point = [360590, 555610];
// yielding [-2.61597, 54.89366] -> [lon, lat]
const converted_point = proj4(EPSG_27700_DATUM, WGS84_DATUM, point);
Working with Bounds
Bounding Box Recap
As a zoomable canvas, your map restricts the world to a rectangular viewport. This viewport is bounded on each side by its cardinal direction — west, south, east, north:
North (+90)
|
|
(-180) West ---+--- East (+180)
|
|
South (-90)
Now, to describe the viewport with the smallest number of points, we'll need the rectangle's opposing corners — typically the south west and the north east:
- South West → Bottom Left → [ min(x), min(y) ]