How a map is drawn¶
About what roadstyle makes, what MapLibre draws, the two forms of road data, and why the page uses one tile zoom. This page is the same for the Python engine and the Rust engine.
roadstyle makes the map, MapLibre draws it¶
roadstyle does not draw pixels. It turns the road edges into a map for one drawing library, and that library draws. You
select the library with the keyword backend of render_edges:
backend |
The library that draws | What render_edges gives |
|---|---|---|
"web" (the default) |
MapLibre GL JS, in the browser | one HTML file |
"folium" |
Leaflet, in a notebook | a folium.Map |
"lonboard" |
deck.gl, in a notebook | a lonboard.Map |
The rest of this page is about "web", the backend of almost all maps. The Rust engine makes only this backend.
flowchart TB
roads["Road edges + look"]
rsty["roadstyle<br/>makes the style<br/>and the road data"]
ml["MapLibre GL JS<br/>draws the pixels"]
roads --> rsty
rsty -->|"style + GeoJSON<br/>or vector tiles"| ml
The "web" backend makes:
- A MapLibre style: the layers and their paint expressions (the widths for each zoom, the colors, the casing under the fill,
the drawing order of bridges and tunnels), and the
roadstyle:*metadata for the dashboard. - The road data, as GeoJSON or as vector tiles (the next section).
- With
render_edges: one HTML page that holds 1 and 2, MapLibre and the dashboard.
MapLibre reads the style and the data and draws them with WebGL. It draws a new frame each time that the view or a filter changes.
Three choices for the road data¶
MapLibre draws only from tiles: small squares of the map, one grid for each zoom. Three choices decide who makes these tiles and how they get to the browser. Each choice comes after the one before it.
Choice 1: GeoJSON or vector tiles¶
| GeoJSON (the default) | Vector tiles (MVT) | |
|---|---|---|
| Who cuts the roads into tiles | MapLibre, in the browser, for all roads when the page opens | roadstyle, before the browser |
| Calls | render_edges(edges), export_inline, makeStyle |
tiles=True, export_style, Tiler |
| Good for | up to about 10⁴ edges | about 10⁵ edges |
With GeoJSON, roadstyle makes no tiles. The page gives MapLibre all the roads, and MapLibre cuts them; data_maxzoom and
data_tolerance control that cut. Choices 2 and 3 do not apply.
After the cut, MapLibre does the same work with both forms: it turns each tile into shapes for the GPU and draws them. The map looks the same, and the dashboard works on both.
Choice 2: how the vector tiles get to the browser¶
| Way | Call | Where the tiles are | Server | What the browser loads |
|---|---|---|---|---|
| A. In one HTML file | render_edges(edges, tiles=True) |
one PMTiles archive inside the page | not necessary: the file opens from disk | the whole file at the start, with all tiles; MapLibre decodes only the tiles in view |
| B. On a server | export_style(...) |
files on a web server | necessary | style.json, then only the tiles in view, one request for each |
| C. Made in the browser | new Tiler(...) (WebAssembly) |
nowhere: the engine makes each tile when MapLibre asks for it | only for the page and the roads file | the roads file one time; the tiles exist only in memory |
- Way A is one file for everything. Send it to a person or open it from disk.
- Way B is for a large area, and for other map apps (GeoLibre, QGIS) that open
style.jsonby its URL. - Way C is for a page that makes its maps itself, as duckosm-rust's page does.
Choice 3: the tile files on the server (way B only)¶
XYZ folder (format="xyz") |
One PMTiles file (format="pmtiles") |
|
|---|---|---|
| The files | one file for each tile: tiles/<z>/<x>/<y>.pbf |
one file, roads.pmtiles; an index at its start tells where each tile is |
| How the map gets one tile | one request for that tile's file | one request for a part of the file (an HTTP range request) |
In both forms the map downloads only the tiles of its view. The difference is the number of files on the server. Make tiles and PMTiles shows the calls.
One tile zoom or several¶
When the map is flat, all tiles on the screen have the same zoom. When the map is tilted, MapLibre loads the near tiles at a higher zoom than the far tiles, because the near part of the view is larger on the screen.
roadstyle bakes a road's width into each tile for the zoom of that tile. Where a near tile (zoom 15) meets a far tile (zoom 14), the same road gets two widths, and the map shows a line across all roads at that place.
To stop this, the page makes MapLibre use one tile zoom on the whole screen. The page template sets it for each source that is not a base map:
The cost:
- Up to 60° of tilt, MapLibre already uses one tile zoom, so the rule changes nothing.
- Above 60°, the page loads 2 to 3.6 times as many tiles (66° to 70°).
max_pitch=60keeps every view in the range where the rule costs nothing. The default is 70.
A page of your own that adds roadstyle's style to its own MapLibre map does not have this rule. Add the same line for each roads source, as the tile example of Use roadstyle in the browser does.
See also: Big networks · Make tiles and PMTiles · Architecture of the Rust version