Skip to content

Overview

Module 00 โ€” GIS Primer: What You Need to Know Before You Map

This module contains no Leaflet, no Phlex, and no Rails. It is a short course in the concepts that underpin everything else in this series. You could skip it and come back when something confuses you โ€” but the ideas here are dense enough that encountering them mid-tutorial, while also learning a new library, makes both harder. Twenty minutes now will save you an afternoon of debugging later.


Coordinates: What lat/lng Actually Means

You almost certainly know that a location on Earth can be described by two numbers โ€” latitude and longitude. But knowing the words and knowing the meaning are different things, and the difference matters when things go wrong.

Latitude measures how far north or south you are from the equator. It runs from โˆ’90ยฐ at the South Pole to +90ยฐ at the North Pole. The equator is 0ยฐ. Australia sits between roughly โˆ’10ยฐ (Cape York) and โˆ’44ยฐ (southern Tasmania) โ€” always negative, because it is entirely in the southern hemisphere.

Longitude measures how far east or west you are from the Prime Meridian, an arbitrary line that runs through Greenwich, London. It runs from โˆ’180ยฐ to +180ยฐ. Australia sits between roughly +113ยฐ (western WA) and +154ยฐ (eastern Queensland) โ€” always positive, because it is entirely east of Greenwich.

So Sydney is approximately โˆ’33.87, +151.21. The negative latitude puts it south of the equator. The positive longitude puts it east of Greenwich. Both numbers are degrees of arc on a sphere.

In Ruby, you will write this as a pair of floats:

1
sydney = { lat: -33.8688, lng: 151.2093 }

The degree of precision matters. One degree of latitude is approximately 111 km. One decimal place gets you to ~11 km โ€” useful for identifying a city. Four decimal places gets you to ~11 metres โ€” useful for placing a marker on a building. Six decimal places gets you to ~11 centimetres โ€” more than enough for any mapping application.


WGS84: The Coordinate System Everything Uses

Latitude and longitude are not self-contained โ€” they are measurements within a coordinate reference system (CRS). A CRS defines what “latitude” and “longitude” actually mean: what shape the Earth is modelled as, where the origin is, and how distances are calculated.

The CRS you will use for everything in this series is WGS84, formally EPSG:4326. It is the coordinate system used by GPS, by Google Maps, by OpenStreetMap, by GeoJSON, and by Leaflet. When someone says “latitude and longitude” without qualification, they almost certainly mean WGS84.

๐Ÿ“Œ What does WGS84 stand for?

World Geodetic System 1984. It is a standard published in 1984 (and updated since) that defines a precise model of the Earth’s shape, size, and orientation. The “84” is the year of the original publication. It is maintained by the United States National Geospatial-Intelligence Agency and is the coordinate system used by GPS satellites. When your phone tells you where you are, it is giving you a WGS84 coordinate.

You do not need to think about WGS84 directly. You just need to know it exists, so that when you encounter the code EPSG:4326 in PostGIS documentation or GeoJSON specs, you recognise it as “the normal one.” There are hundreds of other coordinate systems โ€” national survey grids, regional projections, historical systems โ€” and PostGIS can work with all of them. This series stays in WGS84 throughout.

๐Ÿ“Œ What does EPSG stand for?

European Petroleum Survey Group. The EPSG was an organisation of oil and gas producers that, starting in the 1980s, maintained a registry of coordinate reference systems to ensure that survey data could be shared reliably between companies and countries. They needed a common language for “where is this oil well, exactly.” The registry they created โ€” a numbered list of coordinate systems โ€” became the global standard. The EPSG organisation itself was absorbed into the International Association of Oil and Gas Producers (IOGP) in 2005, but the numbering system kept the EPSG name. Today, EPSG:4326 means WGS84, EPSG:3857 means Web Mercator, and there are thousands of other codes for national and regional systems. You will only ever need 4326 and occasionally 3857 in this series.


Web Mercator: Why the Map Looks the Way It Does

If WGS84 is the coordinate system, Web Mercator (EPSG:3857) is the projection used to display maps on a flat screen.

A projection is a mathematical transformation from a sphere to a flat surface. No projection is perfect โ€” you cannot flatten a sphere without distorting something. Web Mercator makes a specific trade-off: it preserves shape locally (so roads and buildings look correct) but distorts area dramatically at high latitudes.

This is why Greenland appears roughly the same size as Africa on a standard web map, despite being about fourteen times smaller in reality. Near the equator, Web Mercator is accurate. Near the poles, it is severely distorted.

For Australia, which sits between 10ยฐS and 44ยฐS, Web Mercator distortion is modest and generally not worth worrying about. It becomes relevant if you ever need to calculate areas from map coordinates โ€” in that case, use PostGIS functions rather than trying to compute area from degrees.

The practical point: when you look at a Leaflet map, the tiles are rendered in Web Mercator. When you place a marker using lat/lng coordinates, Leaflet converts them to Web Mercator internally. You never have to do this conversion yourself, but knowing it happens explains why your coordinates (WGS84) and the tile URLs (Web Mercator) use different numbers.


Tile Layers: How a Slippy Map Works

A “slippy map” โ€” one you can pan and zoom โ€” is not a single image. It is a grid of small square images called tiles, fetched on demand from a tile server as you move around.

Each tile is 256ร—256 pixels. Tiles are organised by three parameters: zoom level, column (x), and row (y). A tile server URL looks like this:

https://tile.openstreetmap.org/{z}/{x}/{y}.png

At zoom level 0, the entire world fits in a single tile. At zoom level 1, it is a 2ร—2 grid (4 tiles). At zoom level 2, a 4ร—4 grid. Each additional zoom level doubles the number of tiles in each direction, so zoom level z has 2แถป ร— 2แถป tiles covering the world.

At zoom level 10 โ€” a typical city view โ€” there are over a million tiles covering the planet. Leaflet requests only the tiles it needs to fill the current viewport, and caches them in the browser.

When you specify a tile layer in Ruby:

1
2
3
4
5
Map::Options.new(
  centre: [-33.8688, 151.2093],
  zoom: 12,
  tile_layer: :cartodb_positron
)

…the tile_layer: value resolves to a URL template. Leaflet substitutes {z}, {x}, and {y} at runtime to fetch exactly the tiles it needs.

Attribution matters. Tile providers โ€” OpenStreetMap, CartoDB, Stadia โ€” supply their tiles for free, but they require attribution in return. Leaflet’s attribution control (the small text in the corner of the map) handles this. Do not remove it. It is a licence condition, not a design suggestion.


GeoJSON: The Format for Geographic Data

GeoJSON is the standard format for representing geographic features โ€” points, lines, polygons โ€” as JSON. It is what PostGIS emits, what Leaflet consumes, and what APIs return. Understanding its structure will save you significant confusion.

A GeoJSON Feature represents a single geographic thing with a geometry and optional properties:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# What a GeoJSON Feature looks like as a Ruby hash
# (before serialising to JSON)
{
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [151.2093, -33.8688]   # [longitude, latitude] โ€” note the order
  },
  properties: {
    name: "Sydney",
    population: 5_300_000
  }
}

A GeoJSON FeatureCollection is a container for multiple features:

1
2
3
4
5
6
7
{
  type: "FeatureCollection",
  features: [
    { type: "Feature", geometry: { ... }, properties: { ... } },
    { type: "Feature", geometry: { ... }, properties: { ... } },
  ]
}

GeoJSON supports several geometry types: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, and GeometryCollection. For this series, you will mostly work with Point (markers) and Polygon/ MultiPolygon (regions and boundaries).


โš ๏ธ The Coordinate Order Gotcha

GeoJSON specifies coordinates as [longitude, latitude] โ€” longitude first.

Leaflet specifies coordinates as [latitude, longitude] โ€” latitude first.

These are opposite. They are both widely used. There is no warning when you get it wrong โ€” your marker will simply appear somewhere in the Atlantic Ocean instead of Australia.

The rule in this series: Ruby DSL objects always use [lat, lng] order, consistent with Leaflet. When the DSL serialises data to GeoJSON, it swaps the order for you. You write lat: and lng: as named keyword arguments and never worry about array order.

If you ever construct GeoJSON by hand โ€” for PostGIS, for an API, for a fixture file โ€” remember: longitude first.


Projections and Area: A Practical Warning

Web Mercator makes areas look wrong at high latitudes. For Australia, this is not a significant problem for display purposes. But it becomes a real problem if you try to calculate areas or distances from screen coordinates or from raw WGS84 degrees.

Do not do geometry arithmetic on coordinates. Use PostGIS instead.

PostGIS functions like ST_Area, ST_Distance, and ST_DWithin work correctly with geographic coordinates because they account for the curvature of the Earth. A calculation like “find all schools within 5 km of this point” is one PostGIS function call. The equivalent calculation in Ruby, working with raw lat/lng values, would require implementing the Haversine formula and would still be less accurate for large distances.

The practical rule: use coordinates for display, use PostGIS for calculation.


Zoom Levels and Scale

Zoom levels are not just a visual convenience โ€” they carry meaning.

Zoom Typical view Approximate map width
1โ€“3 World / continent 10,000โ€“40,000 km
4โ€“6 Country 1,000โ€“5,000 km
7โ€“9 State / region 100โ€“500 km
10โ€“12 City 10โ€“100 km
13โ€“15 Suburb / neighbourhood 1โ€“10 km
16โ€“18 Street / building 100 m โ€“ 1 km
19+ Individual structures < 100 m

For this series, you will most often work in the country-to-city range (zoom 4โ€“12). The showcase application opens Australia-wide at zoom 4 and lets the user drill down.


Spatial Queries: What PostGIS Makes Possible

Later modules introduce PostGIS โ€” a PostgreSQL extension that adds spatial data types and functions. The full introduction comes in Module 07. For now, it is enough to know what spatial queries are and why they are useful.

A spatial query is a database query that filters by geography. Examples:

  • Find all schools within 10 km of a given point
  • Find all SA2 regions that intersect a user-drawn polygon
  • Find the SA4 region that contains a clicked coordinate
  • Find all postcodes within the boundary of a local government area

These queries are expressed in SQL using PostGIS functions. They run in the database, return only the rows that match, and do not require loading all your data into Ruby first.

The three PostGIS functions you will use most often:

  • ST_Within(geometry_a, geometry_b) โ€” true if A is entirely inside B
  • ST_Intersects(geometry_a, geometry_b) โ€” true if A and B share any space
  • ST_DWithin(geometry_a, geometry_b, distance) โ€” true if A and B are within distance of each other (in metres, for geographic types)

You will see these explained in detail, with working Rails examples, in Module 07.

๐Ÿ“Œ What about SpatiaLite โ€” can I use SQLite instead of PostgreSQL?

SpatiaLite is a spatial extension for SQLite that provides many of the same functions as PostGIS. The core functions โ€” ST_Within, ST_Intersects, ST_Distance โ€” exist in both and work the same way in SQL queries. So the idea of using SpatiaLite for early development and graduating to PostGIS for production is appealing.

In practice, the transition is harder than it looks. The two databases are incompatible at the file level โ€” moving from SpatiaLite to PostGIS means exporting and reimporting all your data, not running a migration. SpatiaLite also lacks ST_DWithin, which is the correct way to do distance-bounded queries with spatial index support in PostGIS. And the Rails adapter for SpatiaLite (activerecord-spatialite-adapter) has not been maintained for recent Rails versions, meaning spatial queries must be written as raw SQL without ActiveRecord’s spatial column awareness.

There is also a practical obstacle on macOS: the system-installed SQLite does not support loading extensions, so SpatiaLite requires installing a separate SQLite via Homebrew and configuring Rails to use it โ€” a setup step that is fiddlier than simply installing PostGIS.

This series uses PostGIS throughout. Modules 01โ€“06 require no spatial database at all โ€” data comes from static files and seeds. PostGIS is introduced in Module 07, with a dedicated setup appendix. By the time you need it, you will have a working application worth the ten-minute install.


What You Now Know

Before this module you knew that latitude and longitude existed. You now know:

  • What the numbers actually mean and how precise they need to be
  • That WGS84 (EPSG:4326) is the coordinate system everything uses
  • That Web Mercator (EPSG:3857) is how tiles are rendered, and why areas look distorted
  • How tile layers work โ€” zoom levels, tile URLs, attribution requirements
  • The structure of a GeoJSON Feature and FeatureCollection
  • That GeoJSON uses [lng, lat] order and Leaflet uses [lat, lng] order
  • Why you should use PostGIS for spatial calculations, not Ruby arithmetic
  • What zoom levels correspond to real-world scales

That is enough to make sense of everything that follows.


Reference: Terminology Cheat Sheet

Term Meaning
WGS84 World Geodetic System 1984. The standard coordinate system for lat/lng, maintained for GPS.
EPSG European Petroleum Survey Group. Their numbered registry of coordinate systems became the global standard. EPSG:4326 = WGS84. EPSG:3857 = Web Mercator.
Web Mercator / EPSG:3857 The projection used to render tiles on a flat screen. Distorts area near the poles.
GeoJSON The standard JSON format for geographic features. Coordinates are [lng, lat].
Feature A single geographic thing: a point, line, or polygon, plus properties.
FeatureCollection A container for multiple Features.
Tile layer The background map image, assembled from 256ร—256 PNG tiles fetched by zoom/x/y.
Zoom level An integer (0โ€“20+) controlling how much of the world is visible. Higher = more detail.
Projection A mathematical transformation from sphere to flat surface. All projections distort something.
PostGIS A PostgreSQL extension for spatial data storage and querying.
SpatiaLite A spatial extension for SQLite. Shares many functions with PostGIS but is not interchangeable.
ST_Within PostGIS/SpatiaLite function: true if geometry A is entirely inside geometry B.
ST_DWithin PostGIS function: true if two geometries are within a given distance of each other.
EPSG code A numeric identifier for a coordinate reference system. 4326 = WGS84. 3857 = Web Mercator.

Next: Module 01 โ€” Foundation: Your First Map