CHAPTER 18
Coordinate transforms: converting between CRS
EPSG:4326 ↔ 3857 by hand, using proj4js, and the practical situations where you need to transform coordinates.
A coordinate reference system (CRS) defines how coordinates map to a location on Earth. Most data you encounter is in one of two CRS, and converting between them is a daily task.
A coordinate reference system (CRS) defines the relationship between coordinates and locations on Earth. Every dataset has one. If two datasets use different CRS, their coordinates are incomparable, like comparing heights in metres and feet without converting. EPSG codes are the standard shorthand for identifying them.
The two you'll use 95% of the time
| EPSG | Name | Units | Used by |
|---|---|---|---|
4326 | WGS84 geographic | Degrees (lat, lon) | GPS, GeoJSON, most APIs |
3857 | Web Mercator | Metres (x, y) | Google Maps, OSM, Mapbox tiles |
The distinction matters in practice because operations that assume planar geometry (computing buffer distances, calculating area, overlaying rasters) work correctly in metres but give wrong results in degrees. A degree of longitude at the equator is ~111 km; a degree of longitude at 60°N is ~56 km. Treating them as equal without projection introduces systematic distortion.
EPSG:4326 → EPSG:3857 (degrees → metres)
This is the Mercator projection formula you saw in Chapter 4, applied to the Web Mercator sphere:
where m (WGS84 equatorial radius), and φ, λ are in radians.
const R = 6_378_137; // metres
function toWebMercator(lat, lon) {
const x = (lon * Math.PI / 180) * R;
const y = Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI / 180) / 2)) * R;
return { x, y };
}
EPSG:3857 → EPSG:4326 (metres → degrees)
The inverse:
function fromWebMercator(x, y) {
const lon = (x / R) * (180 / Math.PI);
const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * (180 / Math.PI);
return { lat, lon };
}
CRS converter: EPSG:4326 ↔ EPSG:3857
Valid range for Web Mercator
Web Mercator cannot represent the poles. The practical limits are:
- Longitude: −180° to +180°
- Latitude: −85.051129° to +85.051129°
At exactly ±90°, the formula produces ±∞ in the y direction. Google Maps and friends clip to ±85.051129° to produce a square world tile.
Using proj4js
For anything beyond 4326 ↔ 3857, use proj4:
npm install proj4
import proj4 from "proj4";
// Define your custom CRS (find definitions at epsg.io)
proj4.defs("EPSG:32618", "+proj=utm +zone=18 +datum=WGS84 +units=m +no_defs");
// Convert New York from WGS84 to UTM Zone 18N
const [easting, northing] = proj4("EPSG:4326", "EPSG:32618", [-74.0060, 40.7128]);
// → [583959, 4507351] (metres from zone origin)
Continue reading "Coordinate transforms: converting between CRS"
You've reached the end of the free preview. Unlock all 22 paid chapters, including distance math, bearings, polygons, spatial indexing, and 3D map rendering, plus a downloadable PDF and the companion code repo.
- All 22 paid chapters with worked examples
- Downloadable PDF for offline reading
- Companion GitHub repo (JavaScript + Python)
- Free updates for life
Multiple payment options: card, Wise, and bank transfer.
Related chapters
- Coordinate systems: latitude and longitude, the input lat/lon system
- Map projections: flattening the globe, what you're transforming between
- ECEF and 3D coordinate systems, the 3D Cartesian system at the centre of transforms
