Tangram is a great open-source map renderer designed by Mapzen and meant to work primarily with their OpenStreetMap vector tiles. It is the way we styled and render the maps for our Conflict Urbanism: Colombia and Locations of Justice projects. However, Mapzen's APIs will shut down on February 1st, 2018, and with them we will loose the ability to style and render their OSM data.
Mapzen has fortunately outlined multiple alternatives to their APIs, including running your own version of their tile server and getting basemaps and tiles from other providers such as Mapbox, OpenMapTiles, or Thunderforest. Here at C4SR, we have been actively experimenting with these alternatives and will probably implement a couple of different ones in the projects that currently rely on Mapzen's tiles.
This post describes one of our alternatives, probably the easiest we have found, which combines Mapbox tiles with Tangram's styling and rendering. This way you don't have to recreate your style within Mapbox or use other rendering libraries in your code. You just have to hook up your Mapbox tiles to your Tangram's scene.yaml
file and adjust your style parameters to suit Mapbox's tiles schema.
The first thing you need to do is to get your API key (or access token) from Mapbox. Once you have your key you should go to the top of your scene.yaml
file and change your sources. Change your URL to Mapbox's tile server (https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/{z}/{x}/{y}.mvt
) and add your access token to the end of the URL (?access_token=xxx.xxx.xxx
). Your tile source should look something like this:
sources:
mapbox:
type: MVT
url: https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/{z}/{x}/{y}.mvt?access_token=xxx.xxx.xxx
max_zoom: 16
tile_size: 512
Once this is done, you will be rendering Mapbox's tiles instead of Mapzen's. However, even though Mapbox's tiles are mostly based on OSM data they have a different schema than Mapzen's, which means that you should adjust the code in your scene.yaml
accordingly.
The most useful resources we found to understand Mapbox's schema were this page and this one. They both contain more or less the same information, just organized a little differently. For example, we see here that the layer containing roads is called road
as opposed to roads
(with an 's') or that there is no layer containing the earth
. In addition, one important difference between the two tilesets is the fact that in Mapbox's tiles, labels are their own independent layers, not included in the respective feature layers.
To add a background layer (the equivalent of an earth
layer in Mapzen) you can add a background color in your .html
file. In the line where you create your map
div, just add a style line with the background color. Ours looks like this:
<div id="map" style="width: 1024px; height: 576px; background-color: white;">
The rest of the styling is fairly straight forward. Here's an example of a style for primary and secondary roads. The first one is the original using Mapzen tiles:
roads:
data: {source: mapzen}
major-roads:
filter:
kind: [major_road]
$zoom: {min: 12, max: 20}
draw:
lines:
order: 4
color: '#F2F2F2'
width: [[12, 1px], [13, 2.5px], [14, 4.5px], [15, 5.5px], [16, 7.0px], [19, 14m]]
outline:
color: '#D9D9D9'
width: [[12, 0px], [14, 1.25px], [16, 1px], [18, 2px]]
This one is the new one using Mapbox tiles:
road:
data: {source: mapbox}
major-roads:
filter:
class: [trunk, primary, secondary]
$zoom: {min: 12, max: 20}
draw:
lines:
order: 4
color: '#F2F2F2'
width: [[12, 1px], [13, 2.5px], [14, 4.5px], [15, 5.5px], [16, 7.0px], [19, 14m]]
outline:
color: '#D9D9D9'
width: [[12, 0px], [14, 1.25px], [16, 1px], [18, 2px]]
The two main differences are that in Mapzen the layer is called roads
(with and 's' at the end) and in Mapbox it is called road
, and that in Mapzen, you can filter the layer using the kind
attribute, while in Mapbox, you use primarily the class
attribute to filter features.
Finally, as I said before, in Mapbox you need to add separate layers for the labels. These work similarly than other features but just need to be fully independent. Here is an example of a label layer for cities in Mapbox:
place_label:
data: {source: mapbox}
otherCities:
filter:
type: [city]
draw:
text:
move_into_tile: false
order: 7
font:
family: 'Neue Haas Unica W01 Regular'
weight: 300
size: [[12,8px],[13,9px],[14,10px],[15,11px],[16,12px]]
fill: '#A6A6A6'
One important thing to note here is the move_into_tile: false
condition. If you don't add this condition, you will probably notice how multiple labels appear for the same feature. This is because Mapbox's tiles are buffered while Mapzen's are not. The move_into_tile: false
statement prevents this repetition from happening.
That's about it. With this you should be able to use Mapbox tiles while still styling and rendering them with Mapzen's Tangram. Some small things might be a little different but from the alternatives we've experimented with, this has been the easiest one.
In addition, if your map also uses Mapzen's terrain tiles you can easily just link it directly to the AWS's URL, bypassing Mapzen's APIs. In the sources
section of your scene.yaml
file, just change your terrain URL. Here's how mine looks:
sources:
normals:
type: Raster
url: https://s3.amazonaws.com/elevation-tiles-prod/normal/{z}/{x}/{y}.png
max_zoom: 15
Thanks to Ruatara Paapu and to Nathaniel Kelso for their help. And of course, thanks to Mapzen for creating these great tools in the first place.