# Wax 3.x

Wax is a collection of extras and tools that make it easier to publish 
custom maps on any website. It's an extension of 
[different mapping APIs](#mapping-libraries) including Modest Maps, OpenLayers and
the Google Maps API client.

## Upgrading to 3.x+

*Wax 3.x contains important updates to the Wax API. Please see the
[CHANGELOG.md](https://github.com/mapbox/wax/blob/master/CHANGELOG.md) for more
information.*

## Intro to Web Maps

Assuming that you've been designing maps with [TileMill](http://tilemill.com/) or
another design tool, and  have gotten them up on a server for your usage,
what's next? It's actually  quite simple to get to the next step: your basic
ingredients are

* A map server, like [TileStream](https://github.com/mapbox/tilestream)
* A Javascript API, like [Modest Maps](https://github.com/stamen/modestmaps-js)
* Your website

The mapping server serves up **tiles** of rendered data - tiles being 256 pixel
square images covering some of the world. Here's a tile of Europe from the
[World Light tileset](http://mapbox.com/tileset/world-light).

![Europe](http://a.tile.mapbox.com/1.0.0/world-light/2/2/2.png)

## TileJSON

The Wax API makes use of [TileJSON](https://github.com/mapbox/tilejson).
TileJSON is a format that contains metadata and information necessary for using
a tileset.

To start you'll need to know the URL of the tileset you want to use. Most
tilesets follow the convention of ending in `/{z}/{x}/{y}.[image format]`
where `{z}` is the *zoom level*, `{x}` is the *x coordinate* and `{y}` is
the *y coordinate*. TileJSON represents tileset URLs using these placeholders
so that a tile at any coordinate can be requested.

The URL of the tile above is `http://a.tile.mapbox.com/1.0.0/world-light/2/2/2.png`. By inference we can write the TileJSON needed to use the World Light tileset:

{
  "version": "1.0.0",
  "scheme": "tms",
  "tiles" ["http://a.tile.mapbox.com/1.0.0/world-light/{z}/{x}/{y}.png"]
}
- The `version` key declares that we are implementing version `1.0.0` of the TileJSON spec. - The `scheme` key describes the coordinate system used for the tiles. MapBox tilesets currently use the scheme `tms`. - The `tiles` key contains an array of URLs from which tiles can be requested. There are quite a few mapping APIs, but at their core, they're doing the same sort of thing - adding these tiles to a page and managing them so that the map seems like a continuous world instead of little squares. We'll start off with **Modest Maps** because it's lightweight and fast. # Modest Maps The first step is to download and include the necessary Javascript code to make your map work. We'll also include a CSS file to start rolling with style: - `wax/ext/modestmaps.min.js` contains the Modest Maps library. - `wax/dist/wax.mm.js` contains the Wax controls and integration code for Modest Maps. - `wax/theme/controls.css` contains default styles for controls. You can always swap in your own later on.
<html>
<head>
  <script src='wax/ext/modestmaps.min.js' type='text/javascript'></script>
  <script src='wax/dist/wax.mm.js' type='text/javascript'></script>
  <link href='wax/theme/controls.css' rel='stylesheet' type='text/css' />
  ...
Wax has a custom Modest Maps provider that can display tilesets described by the TileJSON format at `wax.mm.connector`.
World Light
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/world-light/{z}/{x}/{y}.png']
};
// Alias com.modestmaps to mm. This isn't necessary -
// just nice for shorter code.
var mm = com.modestmaps;
// Set up a map in a div with the id 'modestmaps-setup'
var m = new mm.Map('modestmaps-setup',
  // Use Wax's connector to add a new custom layer
  new wax.mm.connector(tilejson),
  // And it'll be 240px by 120px
  new mm.Point(240,120));

// Center it on the United States, at zoom level 2.
m.setCenterZoom(new mm.Location(39, -98), 2);
## Controls ### Interaction The interaction control adds quite a bit of logic to the map, adding interactivity - mouse hovers and clicks - to layers that support it, like those made with [TileMill](http://tilemill.com/) and the interactive [UTFGrid section](https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md) of the [MBTiles spec](https://github.com/mapbox/mbtiles-spec). The interaction control takes a parameter, `callbacks`, that has the default value of `new wax.tooltip()` - the default tooltip library that comes with wax. Any other library that implements the same interface (see `tooltips.js`) can be passed into the callbacks parameter.
Geography Class
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  grids: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.grid.json'],
  formatter: function(options, data) { return data.NAME }
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-interaction',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.interaction(m, tilejson);
m.setCenterZoom(new mm.Location(39, -98), 1);
### Mobile TODO
World Glass
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  grids: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.grid.json'],
  formatter: function(options, data) { return data.NAME }
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-mobile',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120),
  [new mm.MouseHandler(), new mm.TouchHandler()]);
wax.mm.interaction(m, tilejson);
wax.mm.mobile(m, tilejson, {
  bodyDraw: function(body) { body.bgColor = '#000000' }
});
m.setCenterZoom(new mm.Location(39, -98), 2);
### Fullscreen The fullscreen control adds a link to the map that assigns a fullscreen class to the map, which makes it fill the page. You'll see that this control adds a fullscreen link to the map, and that it's a bit ugly right now. Until Wax's theming improves, keep in mind that its styling, which is contained in `theme/controls.css`, is completely optional and you can replace it with your own.
World Light
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/world-light/{z}/{x}/{y}.png']
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-fullscreen',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.fullscreen(m, tilejson).appendTo(m.parent);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Zoomer A simple zoom control offering zoom in & out buttons. It creates links and appends them to the map, adding classes like `zoomin`, `zoomout`, and `zoomdisabled` to help you style them.
World Glass
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/world-glass/{z}/{x}/{y}.png']
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-zoomer',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.zoomer(m, tilejson).appendTo(m.parent);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Zoombox Control that allows you to zoom with the shift-key and a draggable box.
World Glass
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/world-glass/{z}/{x}/{y}.png']
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-zoombox',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.zoombox(m, tilejson);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Boxselector A control that lets you highlight a region of the map with the shift-key and a draggable box, and calls a callback when you release the mouse. It's useful for tools that need the selection of certain areas of the world.
Blue Marble Topography & Bathymetry (July)
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/blue-marble-topo-bathy-jul/{z}/{x}/{y}.png']
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-boxselector',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.boxselector(m, tilejson, {
  callback: function(coords) {
    $('#boxselector-text').text(
      coords.map(function(c) {
        return c.lat + ',' + c.lon;
      }).join(' - '));
  }
});
m.setCenterZoom(new mm.Location(39, -98), 2);
Selection:
### Pointselector A control that enables users to add points to a map by clicking the map, and then clicking those points to remove them. Like the boxselector control, it calls a callback with the current map data, and also exposes an API, `addLocation(com.modestmaps.Location)`, if you wish to add points on pageload.
Blue Marble Topography & Bathymetry (July)
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/blue-marble-topo-bathy-jul/{z}/{x}/{y}.png']
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-pointselector',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120))
wax.mm.pointselector(m, tilejson, {
  callback: function(coords) {
    $('#pointselector-text').text(
      coords.join(' - '))
  }
});
m.setCenterZoom(new mm.Location(39, -98), 2);
Points:
### Legend Display legend information on the map. This internally creates the legend, and then you can add it to a map by chaining `.appendTo(map.parent)`.
Geography Class
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  legend: 'Geography Class by MapBox'
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-legend',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.legend(m, tilejson).appendTo(m.parent);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Hash Save the map position to the URL so that links hit the map in the same state as the initial user. By default, this control uses [pushState](https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history), a feature found in modern webbrowsers, to give you the history of the map without changing the page URL. You can use traditional hashes (`#/0/0/etc`) by specifying `manager: wax.mm.locationHash` in its options object.
Natural Earth II
var mm = com.modestmaps;
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/natural-earth-2/{z}/{x}/{y}.png']
};
var m = new mm.Map('modestmaps-hash',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.hash(m, tilejson, {
  defaultCenter: new mm.Location(39, -98),
  defaultZoom: 4,
  manager: wax.mm.pushState
});
### Attribution Adds a container capable of displaying arbitrary HTML to the map. Useful for citing data sources.
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  attribution: '© MapBox'
};
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-attribution',
  new wax.mm.connector(tilejson),
  new mm.Point(240,120));
wax.mm.attribution(m, tilejson).appendTo(m.parent);
m.setCenterZoom(new mm.Location(39, -98), 2);
## Layering Modest Maps natively supports a single map layer at a time, unlike OpenLayers, which has a flexible baselayer/overlay system. [TileStream Hosting](http://mapbox.com/#/tilestream) supports compositing of layers server-side, which is far more performant than layering client-side. # Leaflet [Leaflet](http://leaflet.cloudmade.com/index.html) is a new mapping library written by Vladimir Agafonkin at CloudMade that delivers much of the interface of OpenLayers, but with higher performance and a slimmer profile. - `wax/ext/leaflet.js` contains the core Leaflet library. - `wax/ext/leaflet.css` contains the CSS styling for Leaflet. - `wax/dist/wax.leaf.js` containsthe Wax controls and integration code for Leaflet.
<html>
<head>
  <script src='wax/ext/leaflet.js' type='text/javascript'></script>
  <script src='wax/dist/wax.leaf.js' type='text/javascript'></script>
  <link href='wax/ext/leaflet.css' rel='stylesheet' type='text/css' />
  ...
Wax has a custom Leaflet tile layer that can display tilesets described by the TileJSON format at `wax.leaf.connector`.
Geography Class
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  grids: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.grid.json'],
  formatter: function(options, data) { return data.NAME }
};
var map = new L.Map('leaflet-simple')
  .addLayer(new wax.leaf.connector(tilejson))
  .setView(new L.LatLng(51.505, -0.09), 1);
wax.leaf.interaction(map, tilejson);
# Google Maps The Google Maps API V3 is supported by Wax. - Include the Google Maps API V3 according to the [API documentation](http://code.google.com/apis/maps/documentation/javascript/tutorial.html#Loading_the_Maps_API). - `wax/dist/wax.g.js` contains the Wax controls and integration code for Google Maps. - `wax/theme/controls.css` contains default styles for controls. You can always swap in your own later on.
<html>
<head>
  <script src='http://maps.google.com/maps/api/js?sensor=false' type='text/javascript'></script>
  <script src='wax/dist/wax.g.js' type='text/javascript'></script>
  <link href='wax/theme/controls.css' rel='stylesheet' type='text/css' />
  ...
Wax has a custom Google map type that can display tilesets described by the TileJSON format at `wax.g.connector`.
Geography Class
var tilejson = {
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  grids: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.grid.json'],
  formatter: function(options, data) { return data.NAME }
};

var m = new google.maps.Map(
  document.getElementById('google-map'), {
    center: new google.maps.LatLng(0, 0),
    disableDefaultUI: true,
    zoom: 1,
    mapTypeId: google.maps.MapTypeId.ROADMAP });
m.mapTypes.set('mb', new wax.g.connector(tilejson));
m.setMapTypeId('mb');
wax.g.interaction(m, tilejson);
# OpenLayers The Wax toolkit also supports [OpenLayers](http://openlayers.org), though it is **not recommended for new projects**, because it has become extremely bulky and difficult to use correctly. - `wax/ext/OpenLayers.js` contains the core OpenLayers library. **Do not use the hosted version** unless absolutely necessary - the openlayers.org server is not very fast or reliable, and the version that's hosted includes all dependencies, making it extremely large. - `wax/dist/wax.ol.js` contains the Wax controls and integration code for OpenLayers. - `wax/theme/controls.css` contains default styles for controls. You can always swap in your own later on.
<html>
<head>
  <script src='wax/ext/OpenLayers.js' type='text/javascript'></script>
  <script src='wax/dist/wax.ol.js' type='text/javascript'></script>
  <link href='wax/theme/controls.css' rel='stylesheet' type='text/css' />
  ...
The tilesets that TileStream serves and TileMill creates are valid in the [TMS specification](http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification), for which OpenLayers has the `OpenLayers.Layer.TMS` layer type.
Geography Class
// Use the mapbox openlayers zoom/pan control images.
OpenLayers.ImgPath = 'http://js.mapbox.com/theme/dark/';
// Set up a map in a div with the id 'openlayers-simple'
var m = new OpenLayers.Map('openlayers-simple', {
  units: 'm',
  projection: new OpenLayers.Projection('EPSG:900913'),
  maxExtent: new OpenLayers.Bounds(-20037508.34,
    -20037508.34,
    20037508.34,
    20037508.34)
});
m.addLayer(new OpenLayers.Layer.TMS('geography-class',
  'http://a.tiles.mapbox.com/mapbox/', {
  maxResolution: 156543.0339,
  type: 'png',
  layername: 'geography-class'
}));
// The Wax OL interaction control can accept TileJSON.
m.addControl(new wax.ol.Interaction({
  tilejson: '1.0.0',
  scheme: 'tms',
  tiles: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.png'],
  grids: ['http://a.tiles.mapbox.com/mapbox/1.0.0/geography-class/{z}/{x}/{y}.grid.json'],
  formatter: function(options, data) { return data.NAME }
}));
m.zoomTo(1);
# Comparison of Mapping Libraries Wax supports [Modest Maps] [1], [OpenLayers] [2], and [Google Maps] [3] APIs with custom map controls - the ability to interact with tooltips and links, a legend to illustrate map data, and other various utilities. Modest Maps is the recommended library for use with Wax. Being more compact than OpenLayers, faster on older browsers than Polymaps, and more flexible than the Google Maps makes it a good choice for custom mapping applications. The library was originally developed by Tom Carden and Mike Migurski of [Stamen](http://stamen.com/) as a port of [ActionScript and Python code](http://modestmaps.com/). The main reason that [Polymaps](http://polymaps.org/) is not recommended for mainstream usage is its lack of support for Internet Explorer. Modest Maps, OpenLayers, and Google Maps all have solid support for Internet Explorer 7 and higher. [1]: https://github.com/stamen/modestmaps-js [2]: http://www.openlayers.org/ [3]: http://code.google.com/apis/maps/documentation/javascript/ # Protips ## TileJSON URLs Servers like [TileStream](http://github.com/mapbox/tilestream) offer TileJSON for their tilesets at public URLs. Wax provides a basic JSONP loader for grabbing TileJSON from a server and using it to generate your map.
World Light
var url = 'http://tiles.mapbox.com/mapbox/api/Tileset/dc-nightvision';
wax.tilejson(url, function(tilejson) {
  var mm = com.modestmaps;
  var m = new mm.Map('tilejson-url',
    new wax.mm.connector(tilejson),
    new mm.Point(240,120));
  m.setCenterZoom(new mm.Location(
    tilejson.center[1],  // lon
    tilejson.center[0]), // lat
    tilejson.center[2]); // zoom
});
## Multiple servers [Most browsers have a limit](https://encrypted.google.com/search?hl=en&q=browser+domain+connection+limit&aq=f&aqi=&aql=&oq=) for how many things they can ask a single server for at one time - for instance, Modest Maps will aim to download 18 tiles as soon as you load a map, but Internet Explorer decides that the server shouldn't handle more than two requests at a time. Thus, only two tiles are downloaded at a time, despite the fact that modern servers can handle many more. For this problem, we use multiple servers, or more often, multiple domain names. So, you can use * `a.tile.mapbox.com` * `b.tile.mapbox.com` and * `c.tile.mapbox.com` For tile requests. Specify additional servers in your TileJSON `tiles` key instead of just one:
var tilejson = {
  scheme: 'tms',
  tiles: [
    'http://a.tile.mapbox.com/mapbox/1.0.0/world-glass/{z}/{x}/{y}.png',
    'http://b.tile.mapbox.com/mapbox/1.0.0/world-glass/{z}/{x}/{y}.png',
    'http://c.tile.mapbox.com/mapbox/1.0.0/world-glass/{z}/{x}/{y}.png'
  ]
};
## Records Records are a feature of Wax aimed to simplify the configuration of sites that host many maps. They translate the configuration of any mapping API into logic-free [JSON](http://json.org/), where it can be stored in a database and easily modified by other code.
new google.maps.Map(document.getElementById('gmap'), {
  center: new google.maps.LatLng(0, 0),
  zoom: 2,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

// The above code is equivalent to

wax.Record({ 'wax':
  ['@new google.maps.Map',
    ['@call document.getElementById', 'gmap'],
    {
      center: ['@new google.maps.LatLng', 0, 0],
      zoom: 2,
      mapTypeId: ['@literal google.maps.MapTypeId.ROADMAP']
    }
  ]
});
Records aim to be a very close translation from the actual Javascript. You'll notice that the Javascript keyword `new` is represented by `@new`, and the same with calling functions, using literal functions, etc. * Records are not written for variable-heavy code. A great chaining interface, with `@group`, `@inject`, and `@chain` is available for libraries that are written in a chainable fashion, like Modest Maps and Polymaps. * Records are mainly written for code that will be 'done' when the Record stops spinning. Although `wax.Record` returns the last object it was playing around with (most often the map object), this is more a convenience than a core API guarantee.