For my next web mapping project, we’ll use vector tiles. Great. And the data will come from OpenStreetMap. Excellent. Now you only have five more questions to answer.
For the front-end web application developer who wants to stick a map in their site, vector tiles open up lots of options and flexibility, but also lots of choices.
- Style: how will you tell the display engine what colour to draw each thing in the schema?
- Data schema: what kinds of data are contained in the tiles, what are the layers called, and what are the attributes available?
- Tile transport: how will the engine know where to get each tile from?
- File format: how is the data translated into bytes to store within a tile file?
We’re very lucky that in a couple of these areas, a single standard dominates:
Which leaves three decisions to make.
There are several viable options for displaying your vector tiles, depending on whether you also want to display raster tiles or need creative styling, if WebGL (IE11+ only) is ok, and what else you need to integrate with.
Mapbox Terrain, a style rendered with Mapbox-GL-JS.
- Mapbox-GL-JS: the industry leader, made by Mapbox, uses webGL, focused on the needs of mass-market maps for large web companies. It has excellent documentation, great examples and very active development.
- Tangram: made by Mapzen, also uses WebGL, has more experimental and creative features like custom shaders.
- OpenLayers: a fully-featured, truly open source mapping library primarily built for raster tiles, but with vector tile support. (Disclaimer: I’ve never used OpenLayers, I’m just reading docs here.)
There are other combinations as well, such as Leaflet.VectorGrid.
The style mechanism tends to be closely tied to the display engine. (That was also true of CartoCSS, which was a pre-processor for Mapnik. RIP).
- Mapbox Style Specification is a single JSON file which defines sources (vector tiles, GeoJSON files, raster tiles etc) and their display as layers (circles, fills, lines, text, icons etc), including properties that depend on zoom and/or data values. It also has some fiddly details for displaying custom fonts and symbols. Supported by Mapbox-GL-JS and Mapbox.js, but no third-party front-end libraries that I’m aware of. (Geoserver, a Java-based web application seems to have support.) Styles can be created with Mapbox Studio, Maputnik (free, open source) or by hand.
- Tangram scene file, a YAML format which covers a bit more than just styling data, such as cameras and lighting.
Finally, there are three distinct, well-defined schemas for packaging OpenStreetMap data into vector tiles. There doesn’t seem to be a formal specification for how you define a schema, so each is presented as documentation: a list of layers, each with a list of attributes (and their possible values), and at which zoom levels they appear.
- Mapbox Streets v7 (22 layers): a highly processed version of OpenStreetMap data optimised for simplicity and performance, geared towards general mapping applications. Layer and attribute names often reflect original OSM tag names (“waterway, class=stream”) but not slavishly (“road, class=link”, “road,
Dark Matter, a Mapbox Style for OpenMapTiles.
- OpenMapTiles (15 layers): an open schema developed by Klokan (a Swiss company) “in cooperation with the Wikimedia foundation”. It is a bit looser with layer names (“transportation, class=minor”) and occasionally quirky (“transportation, brunnel=tunnel”)
- Mapzen (9 layers): includes both simplified “kind=” and original OSM “kind_detail=” tags on almost every object, making them heavier than the alternatives. Somewhat confusingly, all waterway/water features are combined into a single layer and distinguished only by geometry (line or polygon). At lower zooms, data is sourced from Natural Earth, instead of OSM – I don’t know why. (A lot of work goes into these decisions!)
Matching schemas and styles
Now, the style needs to be designed for the schema: if the schema contains a layer called “roads”, your style can’t be expecting a layer called “transportation”. But it also needs to be expressed in the right format supported by the engine: don’t go feeding no YAML to Mapbox-GL-JS.
These styles kind of live within their company affiliations, however. How about styles rendered by one company’s engine, using data from a different schema:
- Tilezen uses Mapzen’s schema, but is rendered with Mapbox-GL-JS. Demo. (There are also Mapzen examples for OpenLayers and D3). This token effort by Mapbox achieves the same thing.
- This example uses OpenMapTiles, rendered using Tangram.
Mixing and matching
Which brings us to the point of this post. How do you mix schemas and styles? That is, how do you take a style you designed for Mapbox Streets, and make it work on OpenMapTiles? Or port one of Mapzen’s kooky open-licensed styles so it works with Mapbox Streets? Well, you can’t – yet.
(Adapting a style from one engine to another, like what ol-mapbox-style does, is a tough ask, because engines’ capabilities differ.)
But adapting a Mapbox Style file from one OpenStreetMap schema to another? That seems totally doable – even if there isn’t yet a tool to make that happen.
My quick little proof of concept in NodeJS converted OpenMapTiles’ “OSM Bright” style (left) to versions for Mapbox Streets (centre) and Mapzen (right).
Want to give me a hand? Get in touch!
really cool… could you do a full walkthrough of setting them up?
Pingback: weeklyOSM 371 | weekly – semanario – hebdo – săptămânal – haftalık – 週刊 – týdeník – edisi
Very decent. Is there any tutorial/setup to run this style in maputnik?
There is an onto mapping MA: OSM -> SchemaA/StyleA, and another onto mapping MB: OSM -> SchemaB/StyleB. (Not stricly onto, some elements map to NULL – they are dropped). So to go from B to A is just Inv(MB) * MA. Of course the function Inv(MB) may contain some ambiguities as MB is an onto function, And then some of the values in the image of Inv(MB) also map to NULL though MA. Nevertheless, as you showed in your example, it’s good enough. And you can make a speedy LUT for Inv(MB) * MA.
Where do you apply this transformation? On the fly on the server side as tiles are requested?
I’m also wondering if there is possible interference with this issue: https://github.com/osm2vectortiles/osm2vectortiles/issues/387.
I did the transformation as a one time conversion of a Mapbox style.json.