Skip to main content

Exploring the MapBox stack: MBTiles, TileJSON, UTFGrids and Wax

In my last blog post, we created a population density map of New Zealand using QGIS, SQLite and TileMill. Today, we’re going to publish this map to the web using various MapBox inventions. I'll also show you how to publish an interactive TileMill map on your own web server using some PHP and JavaScript wizardry. 

I love MapBox. The team behind this platform has created a series of new specifications, allowing us to create fast, good looking and interactive maps. The downside is the limited support for other map projections than Web Mercator.

TileMill allows you to add legends and tooltips to your maps. I’ve added a legend to my population density map with a HTML snippet describing the map and the color scale.



The tooltip shows when the user hovers over or clicks on the map. It allows us to show dynamic content - additional data, images, charts - for each map feature. I want to show the name, total population, area and population density for each feature:

The data fields for the layer are wrapped in curly Mustache tags. These tags will be replaced by data when you interact with the map. You can use the full Mustache template language.


The easy way to publish this map is to upload it to MapBox Hosting, and use the embed code provided. If you want to publish your map on your own web server, this is an alternative route:

To export an interactive map from TileMill, you need to use the MBTiles format. This is an innovative SQLite-based format specification capable of storing millions of map tiles in a single file. The format is also supported by various 3rd-party applications, and I'm sure we'll see a greater adoption in the future.

Within the MBTiles file, the map legend, the tooltip template and information about map extent, zoom levels etc. is stored in a format named TileJSON. This is also an open specification, providing a consistent way of describing a map, making it easier to load and display a map the way it’s meant to be seen.  The TileJSON for my map looks like this:

If you add interactivity to your map (tooltips), your MBTiles file will also include the most impressing part of the MapBox specifications: UTFgrids. This JSON-format allows us to add thousands of interactive points or polygons through interactivity data grids, and it will even work in older browsers with limited support for vector data. 

So how do we turn our MBTiles file into an interactive map? Previously, I've used MBUtil to extract the contents from MBTiles into a directory structure. But by doing this, we loose the benefits of the MBTiles format, like storing a map in a single file and dealing with redundant images. What we need is a script on our web server that will extract content from our MBTiles file on demand. I decided to try a PHP script from infostreams (this is probably not the most scaleable solution). The script supports the full MBTiles specification, including TileJSON and UTFGrids. Installation is simple: just put the .php file and the .htaccess file in the same directory as your .mbtiles files. The .htaccess file includes a rule that rewrites requested URLs on the fly, so the map data is available un URLs like:
So when we have our backend sorted, how can we recreate our interactive map with Leaflet or other JavaScript mapping libraries? This is way the MapBox team created Wax, which is a client implementation of the MBTiles interaction specification. You just include the wax script together with your mapping library of choice, and then you can add interactivity with a few lines of code:

I've also done some extra JavaScript coding to allow switching between various interactive map layers. I'll save that for a later blog post.

The Leaflet map looks like this (there seems to be an issue with the latest Wax distribution and Google Chrome):

Fullscreen map

Comments

Unknown said…
Nice article, thank you for sharing your experience!
cristen said…
Thank you! I had played with TileMill and Leaflet before, but was unsure how I was supposed to use them (and other parts of the MapBox family) together. This is the first time I've seen someone describe how to do this!
Ben said…
Hi there, thx for the post. There is an issue with the wax.leaf.interaction, if you position NZ to the right side of the map, then hover over NZ you will see that it does not render the teaser, but if you hover in the center of the map the teaser is rendered, it's as if the map had never move. I wanted to make a map with similar components and also wanted to use leaflet, but using wax and modestmaps instead solves the issue.
Bjørn Sandvik said…
Hi Ben,

It's probably this bug: https://github.com/mapbox/wax/issues/242

If you use the latest Wax distribution, it should solve the issue.

Bjørn
Unknown said…
Hello Bjorn,
Thank you for sharing. I have a question for you regarding the legend. If you would like to move your legend to the top left corner of your map, how would you do this?
I am new to MapBox and can't find any comments on this topic, so your answer would very appreciated.
Dorothy
Fons said…
Thanks for sharing this. I'm trying to get my own .mbtiles online for a project. Implementing Wax is going wrong I think.

In the same folder:
- tileserver.php
- .mbtiles
- index.html (with the script you've written and the sources for leaflet)

I've downloaded Wax, but this folder is full of stuff, so I don't know what to use.
In the script you've written, you're calling for a 'wax.tilejson('URL', function)....etc. I don't know what URL to put there and where is the tilejson file that I need to get from the .php script you told about?

Hope you can help me, I would really appreciate it!

Thanks in advance, Fons.
Anonymous said…
How can I make a PDF or image out of http://a.tiles.mapbox.com/v3/slate.truenames.html ? The PDF/image should be zoomable to the detail level of the link. Thanks a lot in advance!
Bjørn Sandvik said…
Dorothy: You can change the position by changing the CSS rules for .wax-legend.

Fons: Yes, it's the URL to your PHP script. TileJSON is part of your mbtiles file, and the PHP script will return it.
mac said…
I'm trying to get my own mbtiles project up but I cant seem to make it work, when i try to do it, only a blank map appears at
http://mandala2006.info/testleaf.html


My tilejson is here http://mandala2006.info/mbtiles/ph-comp.tilejson

and my code is like this

var url = 'mbtiles/ph-comp.tilejson'
wax.tilejson(url,
function(tilejson) {
var map = new L.Map('map-div')
.addLayer(new wax.leaf.connector(tilejson))
.setView(new L.LatLng(11, 123), 8);

// Add map interaction (tooltips)
wax.leaf.interaction()
.map(map)
.tilejson(tilejson)
.on(wax.tooltip().animate(true).parent(map._container).events());
});

What am i doing wrong?
mac said…
This comment has been removed by the author.
Unknown said…
There is now a ready to use PHP server for MBTiles + UTFGrid hosting: https://github.com/klokantech/tileserver-php/ with a live demo at http://tileserver.maptiler.com/
Thomas Barucchi said…
Hi Bjørn,

awesome work !

do you know how I can do the exact same thing (switch or remove legend when baselayer is on/off), but with the overlay layers instead.

I've tried moving your "population" tilelayer from the base layers to the overlay layers, the "population" legend appears when the layer is checked, but does not disapear when the layer is unchecked...

Thanks again for all these tutorials, very helpful for beginers!
David Bierman said…
Would it be possible to create a map similar to this one on a local coordinate systems so that others wouldn't know where it was located?

Popular posts from this blog

Creating a WebGL Earth with three.js

This blog post will show you how to create a WebGL Earth with three.js , a great JavaScript library which helps you to go 3D in the browser. I was surprised how easy it seemed when reading a blog post  by Jerome Etienne . So I decided to give it a try using earth textures  from one of my favourite cartographers, Tom Patterson . WebGL is a JavaScript API for rendering interactive 3D graphics in modern web browsers without the use of plug-ins. Three.js is built on top of WebGL, and allows you to create complex 3D scenes with a few lines of JavaScript. If your browser supports WebGL you should see a rotating Earth below: [ Fullscreen ] To be able to display something with three.js, you need three things: a scene, a camera and a renderer. var width  = window.innerWidth,     height = window.innerHeight; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000); camera.position.z = 1.5; var rende...

Thematic Mapping Engine

It's time to introduce the Thematic Mapping Engine (TME). In my previous blog posts, I've shown various techniques of how geobrowsers can be used for thematic mapping. The goal has been to explore the possibilites and to make these techniques available to a wider audience. The Tematic Mapping Engine provides an easy-to-use web interface where you can create visually appealing maps on-the-fly. So far only prism maps are supported, but other thematic mapping techniques will be added in the upcoming weeks. The engine returns a KMZ file that you can open in Google Earth or download to your computer. My primary data source is UNdata . The above visualisation is generated by TME ( download KMZ ) and shows child mortaility in the world ( UNdata ). The Thematic Mapping Engine is also an example of what you can achieve with open source tools and datasets in the public domain: A world border dataset is loaded into a MySQL database . The same database contains tables with statistics ...

Creating 3D terrains with Cesium

Previously, I’ve used three.js to create 3D terrain maps in the browser ( 1 , 2 , 3 , 4 , 5 , 6 ). It worked great for smaller areas, but three.js doesn’t have built-in support for tiling and advanced LOD algorithms needed to render large terrains. So I decided to take Cesium for a spin. Cesium is a JavaScript library for creating 3D globes and 2D maps in the browser without a plugin. Like three.js, it uses WebGL for hardware-accelerated graphics. Cesium allows you to add your own terrain data, and this blog post will show you how. Impressed by the terrain rendering in @CesiumJS - with a 10m elevation model for Norway! Farewell Google Earth. pic.twitter.com/RQKvfu2hBb — Bjørn Sandvik (@thematicmapping) October 4, 2014 Compared to  the dying Google Earth plugin , it's quite complicated to get started with Cesium. The source code is well documented and the live coding Sandcastle is great, but there is a lack of tutorials  and my development slows down when ...