Skip to content

Demo: one map, a dozen projections — and the API decision it forces #4

Description

@mark-brannan

The pitch

One map. A dozen projections. Pick one and watch the world redraw.

Almost every mapping library ships with Web Mercator and stops there. That is
fine for a street map and wrong for a boat. Mercator cannot draw a pole, and it
cannot put you in the middle of your own map. Sailors who go north or cross the
date line find this out the hard way.

This library's claim is that it has no projection of its own at all. You hand it
two small pieces of math and it draws whatever map you asked for. That is a
strange thing to claim and nobody believes it from a paragraph in a README.

So: a page with a menu. Pick Mercator and get the map everybody grew up with.
Pick Mollweide and the world goes oval. Pick orthographic and you are looking at
a globe from space. The coastline data never changes, the drawing code never
changes, and the page shows you the handful of lines of arithmetic that did
change, right next to the map.

There is a second control: a boat you can drag. The map recenters on it as it
moves, and keeps drawing correctly when it crosses the date line or passes over
the top of the world. That is the exact failure this library was written to fix,
and it has never been shown to anyone.

How we know it is done

  • A public web page (GitHub Pages, this repo) draws one coastline through a menu of projections.
  • At least twelve projections in the menu.
  • At least three of them are not cylindrical — for example Mollweide, orthographic, and azimuthal equidistant. This one matters more than the count; see the notes below.
  • Switching projections redraws immediately, with no page reload and no reloading of the map data.
  • The page shows the actual math for the chosen projection next to the map, so a reader can see how little of it there is.
  • A draggable boat marker. The map recenters on it, and the coastline still draws correctly when the boat crosses the date line and when it passes over a pole.
  • Every projection in the menu is drawn by the published limn function. None of them get special-case drawing code.
  • Readable on a phone.
  • The README leads with a picture of the page that links to it, and portolani and coastlines link across to it.
  • The page has been shown publicly, and at least one piece of feedback is written into this issue.

Not in this issue

  • Zooming, or map data at any detail level other than the one we ship.
  • Land fill, labels, graticules, or anything else that is not coastline.
  • Making this a general purpose projection library. The projections here are demo material; if any of them deserve to be published, that is a separate decision.
Notes for whoever picks this up — this demo forces an API decision

The current signature only supports about a third of the projections people
want to look at.
limn(ctx, rings, x, y, options) calls x(lon) and
y(lat) (lib/limn.js:41). Longitude and latitude are projected
independently. That works for the cylindrical family and only that family:
Plate Carrée, Mercator, Miller, Gall–Peters, Lambert cylindrical equal-area,
Behrmann, Braun. Seven or eight projections, no code change needed.

Everything visually interesting is not separable — Mollweide, Robinson,
Winkel Tripel, sinusoidal, orthographic, and azimuthal equidistant all need
both coordinates to compute either output.

Two changes are implied, and they are not the same size:

  1. Widen the signature to x(lon, lat) and y(lon, lat). This is
    backward compatible for free: existing callers that take one argument
    simply ignore the second. Effectively a one-line change.

  2. The seam rule needs generalising, and this is the real design work.
    limn decides where to lift the pen by testing each segment against
    lonCenter, which assumes the map wraps around like a cylinder.
    Orthographic does not wrap — half the world is behind the globe and must
    not be drawn at all. Interrupted projections break in several places at
    once. A visible(lon, lat) predicate passed alongside x and y is the
    obvious candidate, but it should be chosen by writing the three hard
    projections, not by guessing in advance.

This is why the non-cylindrical projections are an acceptance criterion rather
than a nice-to-have. A gallery of eight cylindrical projections would look
finished and would prove nothing, because they all share the one code path
that already works. The format and this API are still alpha; this is the right
moment to find out what the drawing interface actually needs to be, and a demo
is a cheaper way to find out than a bug report from someone at sea.

Sibling demos: portolani#3 (the 8 KB size slider, shipping), wire-wright#4
(browser wire sizing), signalk-noaa-space-weather#199 (space weather map).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions