Light-map

a light-weight XYZ viewer

View the Project on GitHub nicoptere/light-map

foreword

the purpose of this lib is to provide a minimal engine to display a XYZ Tile Map like OSM, MapBox, MapQuest, Mapzen, Google Maps... there are already many APIs out there such as leaflet and they work fine, they are very comprehensive, well tested so I'd recommend them for a mainstream use.

I found it impractical to work with for "advanced" use cases though ; I needed to draw the view in a canvas (something leaflet wasn't designed for) and had to hack my way so much so that I ended up rebuilding an engine from scratch.

it's rough around the edges, not fully tested and has lots of room for improvement. in a word, it's not for the faint of the heart.

you can jump to the examples if you're not interested in the background.

basics

this is how you instantiate light map:

//import the script "light-map.min.js" somewhere in your page
//then:
var provider = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
var domains = "a,b,c".split( ',' );
var map = new Map( provider, domains, 512,512,0,18 );
document.body.appendChild( map.canvas );
map.setView(0,0,1);

which gives you this

the above is an actual map, loaded from the OpenStreetMap XYZ.

the Map constructor takes 6 arguments which are respectively:

the map holds a canvas DOM element, this is what you should add to the DOM. you can also replace it ( along with the map.ctx property of map ) with the canvas of your choice like so:

map.canvas = document.getElementById("myCanvas");
map.ctx = map.canvas.getContext("2d");
map.setSize(width,height);

now try to push this button (& allow geolocation)



the button calls this method;
function goHome()
{
    var geoSuccess = function(position) {

        map.latitude  = position.coords.latitude;
        map.longitude = position.coords.longitude;
        map.zoom = 17;
        map.setView();
    };
    navigator.geolocation.getCurrentPosition(geoSuccess);
}

here map.setView() is called without arguments, because map.latitude, map.longitude and map.zoom values are set before the call.
usually, you'll use setView( lat, lon, zoom) directly where lat / lon are expressed in degrees and zoom is a zoom value comprised between the bounds you specified in the constructor. the method will compute the tiles required to cover the view rect and load them if necessary.

XYZ?

one could say that XYZ is a "subset" of the TMS specification ; the XYZ refers to how the tiles are organized ( Z is for Zoom level ).

there are more and more XYZ providers made available, here's a list that gives an idea of the potential. if you have a shallow knowledge of what a XYZ is, don't worry, it's quite simple ; a map is decomposed into a pyramid of tiles and you're at the top of the pyramid.

each zoom level is a "slice" of that pyramid and each time you "zoom in" - when you go one level down in the pyramid - each tile is subdivided into 4 tiles with twice more detail.

so the amount of tiles grows quickly: at a zoom level 0 - the top of the pyramid - only one tile is necessary to represent the world, at level 16, you'll need 65.536 tiles to cover the same area which is the number of pixels of the top level tile.

if you go up to level 21, 2.097.152 tiles will be necessary to represent the original, unique, top of the pyramid tile.

that's quite a lot so usually, the XYZ are bound between levels 0 & 18. on the server, the tiles are stored in a specific way that allows for quick lookup. if you want to know more, there is this excellent article: Bing Maps Tile System

note that due to the large amount of tiles to process, some XYZ providers will not allow high zoom level.

usually, a provider url will look something like:

http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png

where

when requesting a tile, the X, Y & Z values are replaced by the tile's XY and the map's zoom level and the (sub)domain is picked randomly amongst the domains' list passed as an argument to the constructor.

switch providers

you can change the provider on the fly like so:


copyright

just make sure you call map.dispose() before assigning the new provider/domains

map_provider.dispose();
map_provider.provider = provider.getAttribute( "data-url" );
map_provider.domains = provider.getAttribute( "data-domains").split( "," );

examples

there are 2 examples in the repo:

warning: when you change the lat/lon values at high zoom levels, there will be MANY images queued for loading. use lon/lat with caution, at rather low zoom levels

otherwise, having a canvas as an output for the map is a strong feature of this API. I'll try to push the "post process" a bit in the upcoming days.

any feedback is welcome, you can hit me on on github or twitter (nicoptere)

that's it for now :)