MapMath

CHAPTER 17

GeoJSON — the universal format

Every GeoJSON geometry type, winding order rules, the lon/lat ordering trap, and the validation rules that every developer trips over.

3 min read

GeoJSON (RFC 7946) is the de facto interchange format for geographic data. It's what every mapping library reads and writes, and it has several sharp edges that trip up developers.

optional — skip if familiarrefresher

GeoJSON is plain JSON. There's nothing special about it beyond a specific schema. You can create, read, and edit it with any text editor or JSON.parse. The full spec is RFC 7946 — 20 pages, worth reading once.

Geometry types

GeoJSON has nine types:

TypeDescriptionExample
PointSingle coordinateA shop location
LineStringOrdered list of pointsA road segment
PolygonClosed ring(s)A country boundary
MultiPointCollection of pointsBus stops
MultiLineStringCollection of linesA split route
MultiPolygonCollection of polygonsCountries with islands
GeometryCollectionMix of any geometries
FeatureGeometry + propertiesA labelled location
FeatureCollectionArray of FeaturesA layer

Feature and FeatureCollection are the wrapper types you'll use most. Raw geometry types (Point, Polygon, etc.) carry no attributes; wrapping them in a Feature lets you attach a properties object with metadata like names, IDs, and display values.

GeoJSON geometry types

{
  ype] "Feature",
  "geometry": {
    ype] "Point",
    "coordinates": [
      74.3587,
      31.5204
    ]
  },
  "properties": {
    "name": "Lahore",
    "population": 13000000
  }
}

Geometry + arbitrary properties.

The lon/lat trap

GeoJSON coordinates are [longitude, latitude] — the opposite of most mapping APIs.

{ "type": "Point", "coordinates": [74.3587, 31.5204] }
//                                  ^ lon first   ^ lat second

Google Maps, Apple Maps, Leaflet — they all use (lat, lon). GeoJSON follows the (x, y) = (easting, northing) convention from cartography. This trips up every developer at least once.

// ❌ Wrong — swapped
const point = { type: "Point", coordinates: [31.5204, 74.3587] };

// ✅ Correct
const point = { type: "Point", coordinates: [74.3587, 31.5204] };

Winding order (right-hand rule)

RFC 7946 requires counter-clockwise exterior rings and clockwise interior rings (holes). This is the right-hand rule: if you walk the boundary with your right hand pointing outward, the interior is to your left.

Counter-clockwise exterior (correct):       Clockwise interior/hole (correct):
  [0,1] → [1,1] → [1,0] → [0,0] → [0,1]     [0.2,0.8] → [0.2,0.2] → [0.8,0.2] → [0.8,0.8]

Winding order matters because GeoJSON needs a convention to distinguish the "inside" from the "outside" of a polygon, especially for global-spanning polygons where either side could be the interior. Some consumers (Mapbox, PostGIS) auto-correct winding order. Others reject invalid GeoJSON silently. Always validate.

import { rewind } from "@turf/rewind";
const corrected = rewind(myGeoJSON, { reverse: false });
Chapter 17 · Paid content

Continue reading "GeoJSON — the universal format"

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 including Wise, PayPal, and bank transfer.