Skip to main content

Routes

Routes draw curved A→B lines that follow the great circle — the shortest path on a sphere. Use them for trade flows, supply chains, migration corridors, or any map that needs to show a connection between two places. Endpoints can be ISO country codes (resolved to centroids) or explicit lat,lon coordinates.

Examples

Three routes with mixed styles:

https://api.maproll.io/map.svg?scope=world&theme=dark&routes=DE%3EBR:%2360a5fa:2:dashed:arrow%3BRO%3EAU:%23ec4899:2%3BJP%3EIN
Three routes with mixed styles

Hub-and-spoke: six routes radiating from the US:

https://api.maproll.io/map.svg?scope=world&theme=light&routes=US%3EGB:arrow%3BUS%3EFR:arrow%3BUS%3EDE:arrow%3BUS%3EJP:arrow%3BUS%3EAU:arrow%3BUS%3EBR:arrow
Hub-and-spoke routes from the US

Literal lat/lon endpoints — useful when the destination is a city, not a country centroid:

https://api.maproll.io/map.svg?scope=world&theme=dark&routes=44.43,26.10%3E52.52,13.40:%23ff8c00:3:arrow
Route between two lat/lon coordinates

Routes with marker icons at each endpoint:

https://api.maproll.io/map.svg?scope=world&theme=dark&routes=DE%3EBR:arrow%3BUS%3ECN:dashed:arrow&markers=52.52,13.40:airport:Berlin%3B-23.55,-46.63:pin:S%C3%A3o+Paulo:bottom%3B38.90,-77.04:flag:Washington%3B39.90,116.40:star:Beijing:right
Routes with markers at endpoints

Parameters

ParamTypeDefaultAllowedNotes
routesstringSee URL syntaxSemicolon-separated route definitions
colorstringtheme text color6-digit hex #rrggbbMust start with #
widthnumber21–20 (px)Integer stroke width
stylestringsolidsolid, dashed
arrowflagoffarrow (presence)Terminal arrowhead at the destination
seaflagoffsea (presence)Thread sea lanes instead of a great circle. See Sea routes

URL syntax

routes=from>to[:options];from>to[:options];...

Options after the >to endpoint are type-distinguished — specify them in any order:

OptionDetected byExample
ColorStarts with ##ff0000
WidthAll digits, 1–203
StyleLiteral solid or dasheddashed
ArrowLiteral arrowarrow
Sea modeLiteral seasea

Endpoints are either:

  • ISO codes — case-insensitive, resolved to the country's geographic centroid. Example: DE, US, RO-B (subnational).
  • lat,lon literals — a comma in the token signals a coordinate. Example: 44.43,26.10. Mix ISO and coordinates freely: DE>44.43,26.10.

The > separator was chosen over - so subnational ISO codes like RO-AG or US-CA remain unambiguous.

URL-encode > as %3E, # as %23, and ; as %3B in query strings.

# Simple ISO pair
routes=RO%3EDE

# With color and width
routes=RO%3EDE:%23ff0000:3

# Dashed with arrow
routes=RO%3EDE:dashed:arrow

# Lat/lon literal endpoints
routes=44.43,26.10%3E52.52,13.40

# Multiple routes
routes=DE%3EBR:dashed%3BUS%3ECN:arrow

JSON body syntax

Use POST /render/map with routes: RouteInput[]. The fromLatLon/toLatLon fields accept [lat, lon] and override the ISO lookup:

{
"scope": "world",
"theme": "dark",
"routes": [
{ "from": "RO", "to": "DE", "color": "#ff0000", "width": 3, "arrow": true },
{ "from": "US", "to": "CN", "style": "dashed" },
{ "from": "XX", "to": "YY", "fromLatLon": [44.43, 26.10], "toLatLon": [52.52, 13.40] }
]
}

Sea routes

Great circles draw the shortest path on a sphere, which is correct for flow visualization and ~accurate for flight paths. For ships it's wrong: a great circle from Shanghai to Rotterdam draws over Siberia. Adding the sea token threads the Eurostat marnet — through Suez, Panama, Malacca, etc.

https://api.maproll.io/map.svg?scope=world&theme=dark&width=1400&routes=31.23,121.47%3E51.92,4.48:sea:%230066cc:3:arrow
Shanghai to Rotterdam via Suez

Transpacific routes split cleanly at the antimeridian, same as great circles:

https://api.maproll.io/map.svg?scope=world&theme=dark&width=1400&routes=35.44,139.64%3E33.77,-118.20:sea:%23f5b25c:3
Yokohama to Long Beach across the Pacific

You can mix sea and great-circle routes on the same map — the sea routes get their polyline, the rest stay great circles:

https://api.maproll.io/map.svg?scope=world&theme=dark&width=1400&routes=CN%3ENL:sea:%230066cc:3:arrow%3BUS%3ECN:%23f59e0b:2:arrow
Mixed sea and great-circle routes

In JSON body, set mode: "sea" on the route object:

{
"scope": "world",
"theme": "dark",
"routes": [
{
"from": "Shanghai",
"to": "Rotterdam",
"fromLatLon": [31.23, 121.47],
"toLatLon": [51.92, 4.48],
"mode": "sea",
"color": "#0066cc"
}
]
}

Sea route notes

  • This is network path-finding, not navigational routing. The route is a shortest path across the Eurostat marnet graph — a real lane network through Suez, Panama, Malacca and the rest, not a great circle. It is equally not a voyage plan: the network is coarse (~100 km between vertices), so the line approximates the corridor rather than a sailed track, and nothing accounts for weather, traffic separation, or territorial waters.
  • Snap to the nearest lane vertex — not to a port. Endpoints snap to the closest vertex of the marnet graph. There is no port database behind this, so the snapped vertex is simply the nearest bit of network, which may not be the intended port. For a specific port, pass lat,lon literals.
  • No land leg from the true origin. The drawn polyline begins and ends at the snapped vertices, not at the coordinates you passed. An inland endpoint's line starts out at sea, with no connecting leg from the original point — draw that yourself as a separate route if you need it.
  • Snap radius is 500 km. Endpoints further from any sea lane than that are rejected — the route lands in X-Geo-Warnings: unknown-routes:sea:A>B and the render returns 200 with no line drawn. This catches truly landlocked pairs (Mongolia, Kazakhstan, Bolivia interior) rather than silently snapping to a faraway coast.
  • First-call latency. The maritime graph builds on the first sea-route request in a given server process (~100–500 ms). Subsequent calls reuse it. Cache-warm renders are fast.
  • Cache key includes mode. Sea and great-circle versions of the same endpoints are independent cache entries.
  • Restrictions, vessel draft, ETA — not exposed. The underlying library supports forcing routes to avoid specific canals (e.g. Suez disruption), gating canals by ship draft, an arctic toggle, and computing voyage duration. None of these are reachable through the API today, so a sea route cannot be made to avoid a canal or reflect a vessel's draft. These will land later when there is demand.

Notes

  • Great-circle curves. Routes are interpolated with 64 samples via d3.geoInterpolate, giving a smooth arc at world scale.
  • Antimeridian split. When a great circle crosses the ±180° meridian (the date line), the renderer automatically splits it into two segments meeting at the map edges. No client-side handling needed.
  • Routes draw below markers. Marker icons sit on top of route endpoints, so the line tip doesn't poke through the icon.
  • Unknown ISO codes. If an endpoint can't be resolved to a feature in the current scope, the route is skipped and the pair is reported in the X-Geo-Warnings: unknown-routes:A>B response header. The render still returns 200.
  • Centroid vs. city position. from=DE resolves to Germany's geographic centroid (central Germany), not Berlin. For routes that must connect city markers, pass explicit lat,lon literals matching the marker's coordinates.
  • Limit: 500 routes per render. Exceeding it returns 400 too_many_routes. The separate invalid_routes code covers malformed route syntax in the URL, not the count cap.
  • No multi-stop routes. Workaround: pass A>B and B>C as separate routes.
  • Arrow markers are deduped by (color, width). Twenty routes sharing a color and width share one SVG <marker> definition.