# Wax

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.

## 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://b.tile.mapbox.com/1.0.0/world-light/2/2/2.png)

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 actually 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' />
  ...
The tilesets that TileStream serves and TileMill creates are supported by a custom Modest Maps provider supplied by Wax at `wax.mm.provider`.
World Light
// 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 to provider add a new custom layer
  new wax.mm.provider({
    // From the main MapBox server
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    // Called world-light
    layerName: 'world-light'}),
  // And it'll be 300px by 200px
  new mm.Point(300,200));

// 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).
Geography Class
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-interaction',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'geography-class'}),
  new mm.Point(300,200));
wax.mm.interaction(m, { callbacks:
  new wax.tooltip({ animationOut: 'wax-fade' })
});
m.setCenterZoom(new mm.Location(39, -98), 1);
### Mobile TODO
World Glass
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-mobile',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'geography-class'}),
  new mm.Point(300,200),
  [new mm.MouseHandler(), new mm.TouchHandler()]);
wax.mm.mobile(m, {
  bodyDraw: function(body) {
    body.bgColor = '#000000';
  }
});
wax.mm.interaction(m, { callbacks:
  new wax.tooltip({ animationOut: 'wax-fade' })
});
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 mm = com.modestmaps;
var m = new mm.Map('modestmaps-fullscreen',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'world-light'}),
  new mm.Point(300,200));
wax.mm.fullscreen(m);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Zoomer The Zoomer control is a stripped-down version of zoom controls, offering just zoom in & out buttons.
World Glass
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-zoomer',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'world-glass'}),
  new mm.Point(300,200));
wax.mm.zoomer(m);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Zoombox The Zoombox control is a control that lets you zoom using the shift-key and a box.
World Glass
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-zoombox',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'world-glass'}),
  new mm.Point(300,200));
wax.mm.zoombox(m);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Boxselector The boxselector control is a control that lets you highlight a region of the map with the shift-key and a box.
Blue Marble Topography & Bathymetry (July)
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-boxselector',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'blue-marble-topo-bathy-jul'}),
    new mm.Point(300,200));
wax.mm.boxselector(m, 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
Blue Marble Topography & Bathymetry (July)
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-pointselector',
    new wax.mm.provider({
      baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
      layerName: 'blue-marble-topo-bathy-jul'}),
    new mm.Point(300,200))
wax.mm.pointselector(m, function(coords) {
  $('#pointselector-text').text(
    coords.join(' - '))
  });
m.setCenterZoom(new mm.Location(39, -98), 2);
Points:
### Legend The legend control pulls legend information from an interactive layer and displays it on the map.
World Print
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-legend',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'world-print'}),
  new mm.Point(300,200));
wax.mm.legend(m);
m.setCenterZoom(new mm.Location(39, -98), 2);
### Hash The hash control saves the map position so that links hit the map in the same state as the user was.
Natural Earth II
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-hash',
  new wax.mm.provider({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'natural-earth-2'}),
  new mm.Point(300,200));
wax.mm.hash(m, {
  defaultCenter: new mm.Location(39, -98),
  defaultZoom: 4,
  manager: wax.mm.locationHash});
## Layering Modest Maps natively supports a single map layer at a time, unlike OpenLayers, which has a flexible baselayer/overlay system. Currently we're working on compositing layers server-side rather than supporting multiple layers in the browser, because this could give a much higher level of performance. # 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'
}));
m.addControl(new wax.ol.Interaction());
m.zoomTo(1);
# 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' />
  ...
The tilesets that TileStream serves and TileMill creates are supported by a custom `MapType` provided by Wax at `wax.g.MapType`.
Geography Class
var map = new google.maps.Map(
  document.getElementById('google-map'),
  { center: new google.maps.LatLng(0, 0),
    disableDefaultUI: true,
    zoom: 1,
    mapTypeId: google.maps.MapTypeId.ROADMAP });
map.mapTypes.set('mb', new wax.g.MapType({
    baseUrl: 'http://a.tiles.mapbox.com/mapbox/',
    layerName: 'geography-class',
    name: 'Geography Class'
}));
map.setMapTypeId('mb');
wax.g.interaction(map);
# 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 ## 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. And you can easily specify them in Modest Maps - just give the `WaxProvider` function an array of domain names instead of just one.
World Glass
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-cnames',
  new wax.mm.provider({
    baseUrl: [
      'http://a.tile.mapbox.com/',
      'http://b.tile.mapbox.com/',
      'http://c.tile.mapbox.com/'],
    layerName: 'world-glass'}),
  new mm.Point(300,200));
m.setCenterZoom(new mm.Location(39, -98), 2);
And, of course, there are other options you can set on the `wax.mm.provider` object, not just layerName and baseUrl. * **filetype**: default `.png`, it can be `.jpg` or anything else. * **zoomRange**: default `[0, 18]`, it can be any restricted range of zoom levels that you happen to have rendered.
Pakistan Grey
var mm = com.modestmaps;
var m = new mm.Map('modestmaps-options',
  new wax.mm.provider({
    baseUrl: 'http://a.tile.mapbox.com/',
    layerName: 'pakistan-grey',
    zoomRange: [0, 9],
    filetype: '.jpg'}),
  new mm.Point(300,200));
m.setCenterZoom(new mm.Location(30.5, 69.78), 4);
## 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.