Skip to content

Instantly share code, notes, and snippets.

@nclarkjudd
Created January 21, 2013 23:51
Show Gist options
  • Save nclarkjudd/4590681 to your computer and use it in GitHub Desktop.
Save nclarkjudd/4590681 to your computer and use it in GitHub Desktop.
Basic leaflet + tilemill + wax howto
<!DOCTYPE html>
<html>
<head>
<title>HOW TO PUBLISH A SLIPPY MAP</title>
</head>
<body>
This tutorial assumes:
<ul>
<li>You know how to use TileMill</li>
<li>You know how to wrangle your web server</li>
<li>What you want to do is publish your map to the web</li>
</ul>
You will need:
<ul>
<li>git</li>
<li>mbutils</li>
<li>TileMill</li>
<li>Wax</li>
<li>Leaflet</li>
</ul>
This tutorial is essentially a fork of <a href="http://build-failed.blogspot.com/2012/03/custom-map-tiles-part-2-tilemill.html">this tutorial right here</a>.
The instructions above are fine right up until the author starts talking about using MBUtils. That library, which converts what you export from TileMill into something ready for use on the web, has changed since the author wrote his tutorial.
In fact, a lot has changed. So much so that I was frustrated into figuring out the below myself, cobbling together from some other sources &mdash; <a href="http://www.minnpost.com/data/2012/03/how-we-built-same-day-registration-map">chiefly this one</a> &mdash; the procedure I've outlined below:
<ol>
<li>Once your map is ready for export, in TileMill go to Export --> "Upload" and Export --> MBTiles</li>
<li>Save your MBTiles after export is complete.</li>
<li>With MBUtils, convert your tiles file to images and json stored in the filesystem.
<pre>
mb-util --scheme=xyz yourfile.mbtiles yourtiledir
</pre>
</li>
<li>While that's running, it's time to grab what you need to build a tilejson file. This is the file that Wax will use to figure out what to pass to Leaflet to render your map. Wax specs say the file has to be a special json file with the extension "jsonp," but that's balderdash. Any appropriately constructed json seems to do the trick.
Head over to MapBox Hosting, where a hosted version of your map awaits. MapBox's API specs tell you where to look for various files, but the construction will look something like this:
<pre>http://a.tiles.mapbox.com/v3/yourmap.id.jsonp</pre>
You should also be able to build the file from scratch yourself, inferring what you need from other sources -- like the metadata file that comes with your converted tiles. I was having trouble going down that road, so I cribbed.
</li>
<li>Copy/paste the file into a text editor and tweak it so that it points to the right spots. Feel free to add line breaks, etc., to make it easier to read. You can also remove things you're not sure about. For example, the "description" field was blank, "filesize" doesn't make a lot of sense for something that actually comprises lots of different files, and "id" seems to be something useful only to MapBox Hosting, so I deleted all of those.
The MapBox-generated jsonp file reveals that your tiles are hosted on multiple servers (nice!) but we're going to be pointing people to just one location on our single measly server, so delete out the redundant addresses for "tiles" and "grids." Make sure to preserve the syntax of this file, with tile and grid locations ["in brackets and quotes"] and commas after each attribute. Otherwise, things break.
MAKE SURE YOU INCLUDE THESE ATTRIBUTES: tilejson -- this is the version of the tilejson spec you're using, and as of now, it looks like it should be 2.0.0; tiles -- this is where your tiles are; grids -- this is also important; scheme -- Wax and Leaflet need this to figure out where to put each tile image on the map; template -- you built this in TileMill, Wax will use it to add interactivity, but if there's no interactivity, you won't need it.</li>
<li>By now your map tiles should be ready to rock. You'll see they're in a directory with the name you specified. In the root directory will be a "metadata.json" file. This is not the same as the tilejson file. They appear to be different. I save the tilejson files in this root directory because it seems like as good a place as any. I like the naming convention mapname-tilejson.json. Pretty descriptive, yeah?</li>
<li>Upload your map tiles wherever they're going to go. In my case, I'm copying them two places: a local directory that I'm going to use to compile a GitHub repo and my staging server, where I'm going to test everything out. When I have everything the way I want on my git repo, I will set up an AWS instance and clone my repo onto it.</li>
<li>To move to my staging server, where I am putting the map so some colleagues can give me feedback, I prefer to use SCP. At this point you should also have an idea of how you want your filesystem to look. I have my map tiles in a subdirectory of a dir called "tiles," and I'm putting the javascript in a directory called "wax." "tiles" and "wax" will both be subdirectories of the parent project directory. I'm calling my parent directory "beta."
So my command to upload tiles is:
<pre>scp -r yourtiledir username@host:path/to/beta/tiles</pre>
</li>
<li>Go get the latest copy of Wax, which has all the javascript libraries we'll need, and put it in the right spot. The libraries we're using are in two subdirectories of the binary: "ext" and "dist."</li>
<li>Build the HTML you'll use. The basic requirement is to include Wax and Leaflet scripts in your header files, CSS for the div where Leaflet will pop up in your page, and javascript in which you call Wax, Wax calls Leaflet to create the map, and then adds the interactivity layer on top (if you have one). That script could look like this:
<textarea rows="16" cols="200">
<div id="map-div">
<script>
// Invoke the map
wax.tilejson('tiles/yourtiledir/yourtilejsonfile.json',
function(tilejson) {
var map = new L.Map('map-div')
.addLayer(new wax.leaf.connector(tilejson))
.setView(new L.LatLng(40.1789, -101.7169), 4);
// Add interaction
wax.leaf.interaction()
.map(map)
.tilejson(tilejson)
.on(wax.tooltip().animate(true).parent(map._container).events());
});
</script>
</div>
</textarea>
You could also put the script in a file elsewhere, and invoke it in the HTML using window-onload.
At this point, I created and pushed the aforementioned Git repo so you can see the map that I made. This text doesn't include all the details that made the HTML work &mdash; for example, the CSS I used. That's in my repo, <a href="https://github.com/nclarkjudd/representator">which you can browse here.</a></li>
<li>Publish!</li>
</ol>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment