New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

modestmaps

Package Overview
Dependencies
Maintainers
2
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

modestmaps - npm Package Compare versions

Comparing version

to
1.0.0-alpha

_site/extending.html

7

_site/README.md

@@ -12,7 +12,2 @@ # Modest Maps

- About Datatypes
- Common recipes
- API
- Handlers
- Datatypes
- Providers
- The Map Object
- Common recipes

@@ -13,3 +13,3 @@ // namespacing!

{
this.coord = map.provider.locationCoordinate(location);
this.coord = map.locationCoordinate(location);

@@ -16,0 +16,0 @@ this.offset = new MM.Point(0, 0);

@@ -11,3 +11,3 @@ // namespacing!

{
this.coord = map.provider.locationCoordinate(location);
this.coord = map.locationCoordinate(location);

@@ -14,0 +14,0 @@ this.dimensions = new com.modestmaps.Point(20, 20);

// namespacing!
if (!com) {
var com = { };
if (!com.modestmaps) {
com.modestmaps = { };
}
if (!MM) {
var MM = { };
}
com.modestmaps.CloudMadeProvider = function(key, style) {
MM.CloudMadeProvider = function(key, style) {
this.key = key;
this.style = style;
this.tileWidth = 256;
this.tileHeight = 256;
}
com.modestmaps.CloudMadeProvider.prototype = {
MM.CloudMadeProvider.prototype = {
key: null,
style: null,
getTileUrl: function(coord) {
getTile: function(coord) {
coord = this.sourceCoordinate(coord);

@@ -26,2 +25,2 @@ var worldSize = Math.pow(2, coord.zoom);

com.modestmaps.extend(com.modestmaps.CloudMadeProvider, com.modestmaps.MapProvider);
MM.extend(MM.CloudMadeProvider, MM.MapProvider);

@@ -12,3 +12,3 @@ // namespacing!

{
this.coord = map.provider.locationCoordinate(location);
this.coord = map.locationCoordinate(location);

@@ -15,0 +15,0 @@ this.offset = new MM.Point(0, 0);

@@ -25,3 +25,3 @@ // namespacing!

for (var i = 0; i < locations.length; i++) {
this.coords.push(map.provider.locationCoordinate(locations[i]));
this.coords.push(map.locationCoordinate(locations[i]));
minLat = Math.min(minLat, locations[i].lat);

@@ -39,4 +39,4 @@ maxLat = Math.max(maxLat, locations[i].lat);

this.topLeftCoord = map.provider.locationCoordinate(topLeftLocation);
this.bottomRightCoord = map.provider.locationCoordinate(bottomRightLocation);
this.topLeftCoord = map.locationCoordinate(topLeftLocation);
this.bottomRightCoord = map.locationCoordinate(bottomRightLocation);

@@ -43,0 +43,0 @@ // console.log(this.topLeftCoord);

@@ -26,3 +26,3 @@ // namespacing!

for (var i = 0; i < locations.length; i++) {
this.coords.push(map.provider.locationCoordinate(locations[i]));
this.coords.push(map.locationCoordinate(locations[i]));
minLat = Math.min(minLat, locations[i].lat);

@@ -40,4 +40,4 @@ maxLat = Math.max(maxLat, locations[i].lat);

this.topLeftCoord = map.provider.locationCoordinate(topLeftLocation);
this.bottomRightCoord = map.provider.locationCoordinate(bottomRightLocation);
this.topLeftCoord = map.locationCoordinate(topLeftLocation);
this.bottomRightCoord = map.locationCoordinate(bottomRightLocation);

@@ -44,0 +44,0 @@ // console.log(this.topLeftCoord);

// namespacing!
if (!com) {
var com = { };
if (!com.modestmaps) {
com.modestmaps = { };
}
if (!MM) {
MM = { };
}
com.modestmaps.BingProvider = function(key, style, onready) {
MM.BingProvider = function(key, style, onready) {

@@ -27,8 +24,7 @@ this.key = key;

var quadKey = "";
for (var i = 1; i <= zoom; i++)
{
for (var i = 1; i <= zoom; i++) {
var rowBit = (row >> zoom-i) & 1;
var colBit = (column >> zoom-i) & 1;
quadKey += (rowBit << 1) + colBit;
}
}
return quadKey;

@@ -40,3 +36,2 @@ }

window.onBingComplete = function(data) {
var resourceSets = data.resourceSets;

@@ -49,3 +44,3 @@ for (var i = 0; i < resourceSets.length; i++) {

var serverSalt = Math.floor(Math.random() * 4);
provider.getTileUrl = function(coord) {
provider.getTile = function(coord) {
var quadKey = toMicrosoft(coord.column, coord.row, coord.zoom);

@@ -57,4 +52,3 @@ // this is so that requests will be consistent in this session, rather than totally random

.replace('{subdomain}', resource.imageUrlSubdomains[server]);
}
};
// TODO: use resource.imageWidth

@@ -67,10 +61,7 @@ // TODO: use resource.imageHeight

// TODO: display data.copyright
onready(provider);
}
};
};
}
com.modestmaps.BingProvider.prototype = {
MM.BingProvider.prototype = {
key: null,

@@ -80,4 +71,4 @@ style: null,

getTileUrl: null
}
};
com.modestmaps.extend(com.modestmaps.BingProvider, com.modestmaps.MapProvider);
MM.extend(MM.BingProvider, MM.MapProvider);

@@ -11,11 +11,17 @@ var MM = require('../../modestmaps.js'),

var canvas = new Canvas(dimensions.x, dimensions.y),
ctx = canvas.getContext('2d');
ctx = canvas.getContext('2d'),
// default to Google-y Mercator style maps
projection = new MM.MercatorProjection(0,
MM.deriveTransformation(-Math.PI, Math.PI, 0, 0,
Math.PI, Math.PI, 1, 0,
-Math.PI, -Math.PI, 0, 1)),
tileSize = new MM.Point(256, 256);
var centerCoordinate = projection.locationCoordinate(location).zoomTo(zoom);
var centerCoordinate = provider.locationCoordinate(location).zoomTo(zoom);
function pointCoordinate(point) {
// new point coordinate reflecting distance from map center, in tile widths
var coord = centerCoordinate.copy();
coord.column += (point.x - dimensions.x/2) / provider.tileWidth;
coord.row += (point.y - dimensions.y/2) / provider.tileHeight;
coord.column += (point.x - dimensions.x/2) / tileSize.x;
coord.row += (point.y - dimensions.y/2) / tileSize.y;
return coord;

@@ -30,4 +36,4 @@ };

var point = new MM.Point(dimensions.x/2, dimensions.y/2);
point.x += provider.tileWidth * (coord.column - centerCoordinate.column);
point.y += provider.tileHeight * (coord.row - centerCoordinate.row);
point.x += tileSize.x * (coord.column - centerCoordinate.column);
point.y += tileSize.y * (coord.row - centerCoordinate.row);
return point;

@@ -56,3 +62,3 @@ }

img.src = data;
ctx.drawImage(img, p.x, p.y, provider.tileWidth, provider.tileHeight);
ctx.drawImage(img, p.x, p.y, tileSize.x, tileSize.y);
completeRequests++;

@@ -59,0 +65,0 @@ checkDone();

@@ -11,3 +11,3 @@ // namespacing!

{
this.coord = map.provider.locationCoordinate(location);
this.coord = map.locationCoordinate(location);

@@ -14,0 +14,0 @@ this.offset = new com.modestmaps.Point(0, 0);

@@ -11,3 +11,3 @@ // namespacing!

{
this.coord = map.provider.locationCoordinate(location);
this.coord = map.locationCoordinate(location);

@@ -14,0 +14,0 @@ this.offset = new com.modestmaps.Point(0, 0);

@@ -1,5 +0,4 @@

com.modestmaps.TileCacheMapProvider = function(template, subdomains) {
MM.TileCacheMapProvider = function(template, subdomains) {
// utility functions...
function addZeros(i, zeros) {

@@ -16,13 +15,12 @@ if (zeros === undefined) {

}
function tilePad(i) {
return addZeros(parseInt(i / 1000000)) + '/' + addZeros(parseInt(i / 1000)) + '/' + addZeros(i % 1000);
return addZeros(parseInt(i / 1000000, 10)) + '/' +
addZeros(parseInt(i / 1000, 10)) + '/' + addZeros(i % 1000);
}
// this is like a call to 'super', kinda...
// we end up initializing a basic modestmaps.js MapProvider with
// this is like a call to 'super', kinda...
// we end up initializing a basic modestmaps.js MapProvider with
// a getTileURL function that knows about the above utility functions
com.modestmaps.MapProvider.call(this, function(coord) {
MM.MapProvider.call(this, function(coord) {
coord = this.sourceCoordinate(coord);

@@ -39,17 +37,13 @@ if (!coord) {

.replace('{Y}', tilePad(Math.pow(2, mod.zoom) - 1 - mod.row));
// replace the {S} portion of the url with the appropriate subdomain
if (url.indexOf('{S}') > -1)
{
var subdomain = (subdomains && subdomains.length > 0)
? subdomains[parseInt(mod.row + mod.column) % subdomains.length]
: '';
if (url.indexOf('{S}') > -1) {
var subdomain = (subdomains && subdomains.length > 0) ?
subdomains[parseInt(mod.row + mod.column, 10) % subdomains.length] : '';
url = url.replace('{S}', subdomain ? subdomain + '.' : '');
}
return url;
return url;
});
};
com.modestmaps.extend(com.modestmaps.TileCacheMapProvider, com.modestmaps.MapProvider);
MM.extend(MM.TileCacheMapProvider, MM.MapProvider);
/*
* Modest Maps JS v0.21.0
* Modest Maps JS v1.0.0-alpha
* http://modestmaps.com/

@@ -12,4 +12,4 @@ *

* See CHANGELOG and http://semver.org/ for more details.
*
*
*/
if(!com){var com={};if(!com.modestmaps){com.modestmaps={}}}(function(a){a.extend=function(d,b){for(var c in b.prototype){if(typeof d.prototype[c]=="undefined"){d.prototype[c]=b.prototype[c]}}return d};a.getFrame=function(){return function(b){(window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(c){window.setTimeout(function(){c(+new Date())},10)})(b)}}();a.transformProperty=(function(d){if(!this.document){return}var c=document.documentElement.style;for(var b=0;b<d.length;b++){if(d[b] in c){return d[b]}}return false})(["transformProperty","WebkitTransform","OTransform","MozTransform","msTransform"]);a.matrixString=function(b){if(b.scale*b.width%1){b.scale+=(1-b.scale*b.width%1)/b.width}if(a._browser.webkit3d){return"matrix3d("+[(b.scale||"1"),"0,0,0,0",(b.scale||"1"),"0,0","0,0,1,0",(b.x+(((b.width*b.scale)-b.width)/2)).toFixed(4),(b.y+(((b.height*b.scale)-b.height)/2)).toFixed(4),0,1].join(",")+")"}else{var c=(a.transformProperty=="MozTransform")?"px":"";return"matrix("+[(b.scale||"1"),0,0,(b.scale||"1"),(b.x+(((b.width*b.scale)-b.width)/2))+c,(b.y+(((b.height*b.scale)-b.height)/2))+c].join(",")+")"}};a._browser=(function(b){return{webkit:("WebKitCSSMatrix" in b),webkit3d:("WebKitCSSMatrix" in b)&&("m11" in new WebKitCSSMatrix())}})(this);a.moveElement=function(d,b){if(a.transformProperty){var c=a.matrixString(b);if(d[a.transformProperty]!==c){d.style[a.transformProperty]=d[a.transformProperty]=c}}else{d.style.left=b.x+"px";d.style.top=b.y+"px";d.style.width=Math.ceil(b.width*b.scale)+"px";d.style.height=Math.ceil(b.height*b.scale)+"px"}};a.cancelEvent=function(b){b.cancelBubble=true;b.cancel=true;b.returnValue=false;if(b.stopPropagation){b.stopPropagation()}if(b.preventDefault){b.preventDefault()}return false};a.addEvent=function(d,c,b){if(d.attachEvent){d["e"+c+b]=b;d[c+b]=function(){d["e"+c+b](window.event)};d.attachEvent("on"+c,d[c+b])}else{d.addEventListener(c,b,false);if(c=="mousewheel"){d.addEventListener("DOMMouseScroll",b,false)}}};a.bind=function(d,e){var f=Array.prototype.slice;var c=Function.prototype.bind;if(d.bind===c&&c){return c.apply(d,f.call(arguments,1))}var b=f.call(arguments,2);return function(){return d.apply(e,b.concat(f.call(arguments)))}};a.removeEvent=function(d,c,b){if(d.detachEvent){d.detachEvent("on"+c,d[c+b]);d[c+b]=null}else{d.removeEventListener(c,b,false);if(c=="mousewheel"){d.removeEventListener("DOMMouseScroll",b,false)}}};a.getStyle=function(c,b){if(c.currentStyle){return c.currentStyle[b]}else{if(window.getComputedStyle){return document.defaultView.getComputedStyle(c,null).getPropertyValue(b)}}};a.Point=function(b,c){this.x=parseFloat(b);this.y=parseFloat(c)};a.Point.prototype={x:0,y:0,toString:function(){return"("+this.x.toFixed(3)+", "+this.y.toFixed(3)+")"}};a.Point.distance=function(e,d){var c=(d.x-e.x);var b=(d.y-e.y);return Math.sqrt(c*c+b*b)};a.Point.interpolate=function(f,e,d){var c=f.x+(e.x-f.x)*d;var b=f.y+(e.y-f.y)*d;return new a.Point(c,b)};a.Coordinate=function(d,b,c){this.row=d;this.column=b;this.zoom=c};a.Coordinate.prototype={row:0,column:0,zoom:0,toString:function(){return"("+this.row.toFixed(3)+", "+this.column.toFixed(3)+" @"+this.zoom.toFixed(3)+")"},toKey:function(){return[this.zoom,this.row,this.column].join(",")},copy:function(){return new a.Coordinate(this.row,this.column,this.zoom)},container:function(){return new a.Coordinate(Math.floor(this.row),Math.floor(this.column),Math.floor(this.zoom))},zoomTo:function(b){var c=Math.pow(2,b-this.zoom);return new a.Coordinate(this.row*c,this.column*c,b)},zoomBy:function(c){var b=Math.pow(2,c);return new a.Coordinate(this.row*b,this.column*b,this.zoom+c)},up:function(b){if(b===undefined){b=1}return new a.Coordinate(this.row-b,this.column,this.zoom)},right:function(b){if(b===undefined){b=1}return new a.Coordinate(this.row,this.column+b,this.zoom)},down:function(b){if(b===undefined){b=1}return new a.Coordinate(this.row+b,this.column,this.zoom)},left:function(b){if(b===undefined){b=1}return new a.Coordinate(this.row,this.column-b,this.zoom)}};a.Location=function(b,c){this.lat=parseFloat(b);this.lon=parseFloat(c)};a.Location.prototype={lat:0,lon:0,toString:function(){return"("+this.lat.toFixed(3)+", "+this.lon.toFixed(3)+")"}};a.Location.distance=function(i,h,b){if(!b){b=6378000}var o=Math.PI/180,g=i.lat*o,n=i.lon*o,f=h.lat*o,m=h.lon*o,l=Math.cos(g)*Math.cos(n)*Math.cos(f)*Math.cos(m),k=Math.cos(g)*Math.sin(n)*Math.cos(f)*Math.sin(m),j=Math.sin(g)*Math.sin(f);return Math.acos(l+k+j)*b};a.Location.interpolate=function(i,g,m){if(i.lat===g.lat&&i.lon===g.lon){return new a.Location(i.lat,i.lon)}var s=Math.PI/180,k=i.lat*s,n=i.lon*s,j=g.lat*s,l=g.lon*s;var o=2*Math.asin(Math.sqrt(Math.pow(Math.sin((k-j)/2),2)+Math.cos(k)*Math.cos(j)*Math.pow(Math.sin((n-l)/2),2)));var t=Math.atan2(Math.sin(n-l)*Math.cos(j),Math.cos(k)*Math.sin(j)-Math.sin(k)*Math.cos(j)*Math.cos(n-l))/-(Math.PI/180);t=t<0?360+t:t;var e=Math.sin((1-m)*o)/Math.sin(o);var b=Math.sin(m*o)/Math.sin(o);var r=e*Math.cos(k)*Math.cos(n)+b*Math.cos(j)*Math.cos(l);var q=e*Math.cos(k)*Math.sin(n)+b*Math.cos(j)*Math.sin(l);var p=e*Math.sin(k)+b*Math.sin(j);var c=Math.atan2(p,Math.sqrt(Math.pow(r,2)+Math.pow(q,2)));var h=Math.atan2(q,r);return new a.Location(c/s,h/s)};a.Transformation=function(d,f,b,c,e,g){this.ax=d;this.bx=f;this.cx=b;this.ay=c;this.by=e;this.cy=g};a.Transformation.prototype={ax:0,bx:0,cx:0,ay:0,by:0,cy:0,transform:function(b){return new a.Point(this.ax*b.x+this.bx*b.y+this.cx,this.ay*b.x+this.by*b.y+this.cy)},untransform:function(b){return new a.Point((b.x*this.by-b.y*this.bx-this.cx*this.by+this.cy*this.bx)/(this.ax*this.by-this.ay*this.bx),(b.x*this.ay-b.y*this.ax-this.cx*this.ay+this.cy*this.ax)/(this.bx*this.ay-this.by*this.ax))}};a.deriveTransformation=function(l,k,f,e,b,o,h,g,d,c,n,m){var j=a.linearSolution(l,k,f,b,o,h,d,c,n);var i=a.linearSolution(l,k,e,b,o,g,d,c,m);return new a.Transformation(j[0],j[1],j[2],i[0],i[1],i[2])};a.linearSolution=function(f,o,i,e,n,h,d,m,g){f=parseFloat(f);o=parseFloat(o);i=parseFloat(i);e=parseFloat(e);n=parseFloat(n);h=parseFloat(h);d=parseFloat(d);m=parseFloat(m);g=parseFloat(g);var l=(((h-g)*(o-n))-((i-h)*(n-m)))/(((e-d)*(o-n))-((f-e)*(n-m)));var k=(((h-g)*(f-e))-((i-h)*(e-d)))/(((n-m)*(f-e))-((o-n)*(e-d)));var j=i-(f*l)-(o*k);return[l,k,j]};a.Projection=function(c,b){if(!b){b=new a.Transformation(1,0,0,0,1,0)}this.zoom=c;this.transformation=b};a.Projection.prototype={zoom:0,transformation:null,rawProject:function(b){throw"Abstract method not implemented by subclass."},rawUnproject:function(b){throw"Abstract method not implemented by subclass."},project:function(b){b=this.rawProject(b);if(this.transformation){b=this.transformation.transform(b)}return b},unproject:function(b){if(this.transformation){b=this.transformation.untransform(b)}b=this.rawUnproject(b);return b},locationCoordinate:function(c){var b=new a.Point(Math.PI*c.lon/180,Math.PI*c.lat/180);b=this.project(b);return new a.Coordinate(b.y,b.x,this.zoom)},coordinateLocation:function(c){c=c.zoomTo(this.zoom);var b=new a.Point(c.column,c.row);b=this.unproject(b);return new a.Location(180*b.y/Math.PI,180*b.x/Math.PI)}};a.LinearProjection=function(c,b){a.Projection.call(this,c,b)};a.LinearProjection.prototype={rawProject:function(b){return new a.Point(b.x,b.y)},rawUnproject:function(b){return new a.Point(b.x,b.y)}};a.extend(a.LinearProjection,a.Projection);a.MercatorProjection=function(c,b){a.Projection.call(this,c,b)};a.MercatorProjection.prototype={rawProject:function(b){return new a.Point(b.x,Math.log(Math.tan(0.25*Math.PI+0.5*b.y)))},rawUnproject:function(b){return new a.Point(b.x,2*Math.atan(Math.pow(Math.E,b.y))-0.5*Math.PI)}};a.extend(a.MercatorProjection,a.Projection);a.MapProvider=function(b){if(b){this.getTileUrl=b}};a.MapProvider.prototype={projection:new a.MercatorProjection(0,a.deriveTransformation(-Math.PI,Math.PI,0,0,Math.PI,Math.PI,1,0,-Math.PI,-Math.PI,0,1)),tileWidth:256,tileHeight:256,topLeftOuterLimit:new a.Coordinate(0,0,0),bottomRightInnerLimit:new a.Coordinate(1,1,0).zoomTo(18),getTileUrl:function(b){throw"Abstract method not implemented by subclass."},locationCoordinate:function(b){return this.projection.locationCoordinate(b)},coordinateLocation:function(b){return this.projection.coordinateLocation(b)},outerLimits:function(){return[this.topLeftOuterLimit.copy(),this.bottomRightInnerLimit.copy()]},setZoomRange:function(c,b){this.topLeftOuterLimit=this.topLeftOuterLimit.zoomTo(c);this.bottomRightInnerLimit=this.bottomRightInnerLimit.zoomTo(b)},sourceCoordinate:function(g){var b=this.topLeftOuterLimit.zoomTo(g.zoom);var d=this.bottomRightInnerLimit.zoomTo(g.zoom);var c=d.row-b.row;if(g.row<0|g.row>=c){return null}var f=d.column-b.column;var e=g.column%f;while(e<0){e+=f}return new a.Coordinate(g.row,e,g.zoom)}};a.TemplatedMapProvider=function(c,b){a.MapProvider.call(this,function(f){f=this.sourceCoordinate(f);if(!f){return null}var d=c;if(b&&b.length&&d.indexOf("{S}")>=0){var e=parseInt(f.zoom+f.row+f.column,10)%b.length;d=d.replace("{S}",b[e])}return d.replace("{Z}",f.zoom.toFixed(0)).replace("{X}",f.column.toFixed(0)).replace("{Y}",f.row.toFixed(0))})};a.extend(a.TemplatedMapProvider,a.MapProvider);a.getMousePoint=function(f,d){var b=new a.Point(f.clientX,f.clientY);b.x+=document.body.scrollLeft+document.documentElement.scrollLeft;b.y+=document.body.scrollTop+document.documentElement.scrollTop;for(var c=d.parent;c;c=c.offsetParent){b.x-=c.offsetLeft;b.y-=c.offsetTop}return b};a.MouseWheelHandler=function(b){if(b!==undefined){this.init(b)}};a.MouseWheelHandler.prototype={init:function(b){this.map=b;this._mouseWheel=a.bind(this.mouseWheel,this);a.addEvent(b.parent,"mousewheel",this._mouseWheel)},remove:function(){a.removeEvent(this.map.parent,"mousewheel",this._mouseWheel)},mouseWheel:function(d){var f=0;this.prevTime=this.prevTime||new Date().getTime();if(d.wheelDelta){f=d.wheelDelta}else{if(d.detail){f=-d.detail}}var c=new Date().getTime()-this.prevTime;if(Math.abs(f)>0&&(c>200)){var b=a.getMousePoint(d,this.map);this.map.zoomByAbout(f>0?1:-1,b);this.prevTime=new Date().getTime()}return a.cancelEvent(d)}};a.DoubleClickHandler=function(b){if(b!==undefined){this.init(b)}};a.DoubleClickHandler.prototype={init:function(b){this.map=b;this._doubleClick=a.bind(this.doubleClick,this);a.addEvent(b.parent,"dblclick",this._doubleClick)},remove:function(){a.removeEvent(this.map.parent,"dblclick",this._doubleClick)},doubleClick:function(c){var b=a.getMousePoint(c,this.map);this.map.zoomByAbout(c.shiftKey?-1:1,b);return a.cancelEvent(c)}};a.DragHandler=function(b){if(b!==undefined){this.init(b)}};a.DragHandler.prototype={init:function(b){this.map=b;this._mouseDown=a.bind(this.mouseDown,this);a.addEvent(b.parent,"mousedown",this._mouseDown)},remove:function(){a.removeEvent(this.map.parent,"mousedown",this._mouseDown)},mouseDown:function(b){a.addEvent(document,"mouseup",this._mouseUp=a.bind(this.mouseUp,this));a.addEvent(document,"mousemove",this._mouseMove=a.bind(this.mouseMove,this));this.prevMouse=new a.Point(b.clientX,b.clientY);this.map.parent.style.cursor="move";return a.cancelEvent(b)},mouseMove:function(b){if(this.prevMouse){this.map.panBy(b.clientX-this.prevMouse.x,b.clientY-this.prevMouse.y);this.prevMouse.x=b.clientX;this.prevMouse.y=b.clientY;this.prevMouse.t=+new Date()}return a.cancelEvent(b)},mouseUp:function(b){a.removeEvent(document,"mouseup",this._mouseUp);a.removeEvent(document,"mousemove",this._mouseMove);this.prevMouse=null;this.map.parent.style.cursor="";return a.cancelEvent(b)}};a.MouseHandler=function(b){if(b!==undefined){this.init(b)}};a.MouseHandler.prototype={init:function(b){this.map=b;this.handlers=[new a.DragHandler(b),new a.DoubleClickHandler(b),new a.MouseWheelHandler(b)]},remove:function(){for(var b=0;b<this.handlers.length;b++){this.handlers[b].remove()}}};a.TouchHandler=function(){};a.TouchHandler.prototype={maxTapTime:250,maxTapDistance:30,maxDoubleTapDelay:350,locations:{},taps:[],wasPinching:false,lastPinchCenter:null,init:function(c,b){this.map=c;b=b||{};this._touchStartMachine=a.bind(this.touchStartMachine,this);this._touchMoveMachine=a.bind(this.touchMoveMachine,this);this._touchEndMachine=a.bind(this.touchEndMachine,this);a.addEvent(c.parent,"touchstart",this._touchStartMachine);a.addEvent(c.parent,"touchmove",this._touchMoveMachine);a.addEvent(c.parent,"touchend",this._touchEndMachine);this.options={};this.options.snapToZoom=b.snapToZoom||true},remove:function(){a.removeEvent(this.map.parent,"touchstart",this._touchStartMachine);a.removeEvent(this.map.parent,"touchmove",this._touchMoveMachine);a.removeEvent(this.map.parent,"touchend",this._touchEndMachine)},updateTouches:function(f){for(var d=0;d<f.touches.length;d+=1){var c=f.touches[d];if(c.identifier in this.locations){var b=this.locations[c.identifier];b.x=c.screenX;b.y=c.screenY;b.scale=f.scale}else{this.locations[c.identifier]={scale:f.scale,startPos:{x:c.screenX,y:c.screenY},x:c.screenX,y:c.screenY,time:new Date().getTime()}}}},sameTouch:function(b,c){return(b&&b.touch)&&(c.identifier==b.touch.identifier)},touchStartMachine:function(b){this.updateTouches(b);return a.cancelEvent(b)},touchMoveMachine:function(b){switch(b.touches.length){case 1:this.onPanning(b.touches[0]);break;case 2:this.onPinching(b);break}this.updateTouches(b);return a.cancelEvent(b)},touchEndMachine:function(l){var c=new Date().getTime();if(l.touches.length===0&&this.wasPinching){this.onPinched(this.lastPinchCenter)}for(var h=0;h<l.changedTouches.length;h+=1){var o=l.changedTouches[h],k=this.locations[o.identifier];if(!k||k.wasPinch){continue}var n={x:o.screenX,y:o.screenY},f=c-k.time,d=a.Point.distance(n,k.startPos);if(d>this.maxTapDistance){}else{if(f>this.maxTapTime){n.end=c;n.duration=f;this.onHold(n)}else{n.time=c;this.onTap(n)}}}var m={};for(var g=0;g<l.touches.length;g++){m[l.touches[g].identifier]=true}for(var b in this.locations){if(!(b in m)){delete m[b]}}return a.cancelEvent(l)},onHold:function(b){},onTap:function(b){if(this.taps.length&&(b.time-this.taps[0].time)<this.maxDoubleTapDelay){this.onDoubleTap(b);this.taps=[];return}this.taps=[b]},onDoubleTap:function(c){var e=this.map.getZoom(),f=Math.round(e)+1,b=f-e;var d=new a.Point(c.x,c.y);this.map.zoomByAbout(b,d)},onPanning:function(d){var c={x:d.screenX,y:d.screenY},b=this.locations[d.identifier];this.map.panBy(c.x-b.x,c.y-b.y)},onPinching:function(i){var h=i.touches[0],g=i.touches[1],k=new a.Point(h.screenX,h.screenY),j=new a.Point(g.screenX,g.screenY),d=this.locations[h.identifier],c=this.locations[g.identifier];d.wasPinch=true;c.wasPinch=true;var b=a.Point.interpolate(k,j,0.5);this.map.zoomByAbout(Math.log(i.scale)/Math.LN2-Math.log(d.scale)/Math.LN2,b);var f=a.Point.interpolate(d,c,0.5);this.map.panBy(b.x-f.x,b.y-f.y);this.wasPinching=true;this.lastPinchCenter=b},onPinched:function(b){if(this.options.snapToZoom){var c=this.map.getZoom(),d=Math.round(c);this.map.zoomByAbout(d-c,b)}this.wasPinching=false}};a.CallbackManager=function(b,d){this.owner=b;this.callbacks={};for(var c=0;c<d.length;c++){this.callbacks[d[c]]=[]}};a.CallbackManager.prototype={owner:null,callbacks:null,addCallback:function(b,c){if(typeof(c)=="function"&&this.callbacks[b]){this.callbacks[b].push(c)}},removeCallback:function(e,f){if(typeof(f)=="function"&&this.callbacks[e]){var c=this.callbacks[e],b=c.length;for(var d=0;d<b;d++){if(c[d]===f){c.splice(d,1);break}}}},dispatchCallback:function(d,c){if(this.callbacks[d]){for(var b=0;b<this.callbacks[d].length;b+=1){try{this.callbacks[d][b](this.owner,c)}catch(f){}}}}};a.RequestManager=function(){this.loadingBay=document.createDocumentFragment();this.requestsById={};this.openRequestCount=0;this.maxOpenRequests=4;this.requestQueue=[];this.callbackManager=new a.CallbackManager(this,["requestcomplete"])};a.RequestManager.prototype={loadingBay:null,requestsById:null,requestQueue:null,openRequestCount:null,maxOpenRequests:null,callbackManager:null,addCallback:function(b,c){this.callbackManager.addCallback(b,c)},removeCallback:function(b,c){this.callbackManager.removeCallback(b,c)},dispatchCallback:function(c,b){this.callbackManager.dispatchCallback(c,b)},clear:function(){this.clearExcept({})},clearExcept:function(f){for(var e=0;e<this.requestQueue.length;e++){var g=this.requestQueue[e];if(g&&!(g.id in f)){this.requestQueue[e]=null}}var b=this.loadingBay.childNodes;for(var d=b.length-1;d>=0;d--){var c=b[d];if(!(c.id in f)){this.loadingBay.removeChild(c);this.openRequestCount--;c.src=c.coord=c.onload=c.onerror=null}}for(var k in this.requestsById){if(this.requestsById.hasOwnProperty(k)){if(!(k in f)){var h=this.requestsById[k];delete this.requestsById[k];if(h!==null){h=h.id=h.coord=h.url=null}}}}},hasRequest:function(b){return(b in this.requestsById)},requestTile:function(e,d,b){if(!(e in this.requestsById)){var c={id:e,coord:d.copy(),url:b};this.requestsById[e]=c;if(b){this.requestQueue.push(c)}}},getProcessQueue:function(){if(!this._processQueue){var b=this;this._processQueue=function(){b.processQueue()}}return this._processQueue},processQueue:function(d){if(d&&this.requestQueue.length>8){this.requestQueue.sort(d)}while(this.openRequestCount<this.maxOpenRequests&&this.requestQueue.length>0){var c=this.requestQueue.pop();if(c){this.openRequestCount++;var b=document.createElement("img");b.id=c.id;b.style.position="absolute";b.coord=c.coord;this.loadingBay.appendChild(b);b.onload=b.onerror=this.getLoadComplete();b.src=c.url;c=c.id=c.coord=c.url=null}}},_loadComplete:null,getLoadComplete:function(){if(!this._loadComplete){var b=this;this._loadComplete=function(d){d=d||window.event;var c=d.srcElement||d.target;c.onload=c.onerror=null;b.loadingBay.removeChild(c);b.openRequestCount--;delete b.requestsById[c.id];if(d.type==="load"&&(c.complete||(c.readyState&&c.readyState=="complete"))){b.dispatchCallback("requestcomplete",c)}else{c.src=null}setTimeout(b.getProcessQueue(),0)}}return this._loadComplete}};a.Map=function(e,h,f,g){if(typeof e=="string"){e=document.getElementById(e);if(!e){throw"The ID provided to modest maps could not be found."}}this.parent=e;this.parent.style.padding="0";this.parent.style.overflow="hidden";var b=a.getStyle(this.parent,"position");if(b!="relative"&&b!="absolute"){this.parent.style.position="relative"}if(!f){f=new a.Point(this.parent.offsetWidth,this.parent.offsetHeight);this.autoSize=true;var c=this;a.addEvent(window,"resize",this.windowResize())}else{this.autoSize=false;this.parent.style.width=Math.round(f.x)+"px";this.parent.style.height=Math.round(f.y)+"px"}this.dimensions=f;this.requestManager=new a.RequestManager(this.parent);this.requestManager.addCallback("requestcomplete",this.getTileComplete());this.layers={};this.layerParent=document.createElement("div");this.layerParent.id=this.parent.id+"-layers";this.layerParent.style.cssText="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; margin: 0; padding: 0; z-index: 0";this.parent.appendChild(this.layerParent);this.coordinate=new a.Coordinate(0.5,0.5,0);this.setProvider(h);this.enablePyramidLoading=false;this.callbackManager=new a.CallbackManager(this,["zoomed","panned","centered","extentset","resized","drawn"]);if(g===undefined){this.eventHandlers=[];this.eventHandlers.push(new a.MouseHandler(this))}else{this.eventHandlers=g;if(g instanceof Array){for(var d=0;d<g.length;d++){g[d].init(this)}}}};a.Map.prototype={parent:null,provider:null,dimensions:null,coordinate:null,tiles:null,layers:null,layerParent:null,requestManager:null,tileCacheSize:null,maxTileCacheSize:null,recentTiles:null,recentTilesById:null,recentTileSize:null,callbackManager:null,eventHandlers:null,autoSize:null,toString:function(){return"Map(#"+this.parent.id+")"},addCallback:function(b,c){this.callbackManager.addCallback(b,c);return this},removeCallback:function(b,c){this.callbackManager.removeCallback(b,c);return this},dispatchCallback:function(c,b){this.callbackManager.dispatchCallback(c,b);return this},windowResize:function(){if(!this._windowResize){var b=this;this._windowResize=function(c){b.dimensions=new a.Point(b.parent.offsetWidth,b.parent.offsetHeight);b.draw();b.dispatchCallback("resized",[b.dimensions])}}return this._windowResize},zoomBy:function(b){this.coordinate=this.enforceLimits(this.coordinate.zoomBy(b));a.getFrame(this.getRedraw());this.dispatchCallback("zoomed",b);return this},zoomIn:function(){return this.zoomBy(1)},zoomOut:function(){return this.zoomBy(-1)},setZoom:function(b){return this.zoomBy(b-this.coordinate.zoom)},zoomByAbout:function(c,b){var e=this.pointLocation(b);this.coordinate=this.enforceLimits(this.coordinate.zoomBy(c));var d=this.locationPoint(e);this.dispatchCallback("zoomed",c);return this.panBy(b.x-d.x,b.y-d.y)},panBy:function(c,b){this.coordinate.column-=c/this.provider.tileWidth;this.coordinate.row-=b/this.provider.tileHeight;this.coordinate=this.enforceLimits(this.coordinate);a.getFrame(this.getRedraw());this.dispatchCallback("panned",[c,b]);return this},panLeft:function(){return this.panBy(100,0)},panRight:function(){return this.panBy(-100,0)},panDown:function(){return this.panBy(0,-100)},panUp:function(){return this.panBy(0,100)},setCenter:function(b){return this.setCenterZoom(b,this.coordinate.zoom)},setCenterZoom:function(b,c){this.coordinate=this.provider.locationCoordinate(b).zoomTo(parseFloat(c)||0);this.draw();this.dispatchCallback("centered",[b,c]);return this},setExtent:function(q,g){var t,k;for(var l=0;l<q.length;l++){var m=this.provider.locationCoordinate(q[l]);if(t){t.row=Math.min(t.row,m.row);t.column=Math.min(t.column,m.column);t.zoom=Math.min(t.zoom,m.zoom);k.row=Math.max(k.row,m.row);k.column=Math.max(k.column,m.column);k.zoom=Math.max(k.zoom,m.zoom)}else{t=m.copy();k=m.copy()}}var j=this.dimensions.x+1;var h=this.dimensions.y+1;var n=(k.column-t.column)/(j/this.provider.tileWidth);var r=Math.log(n)/Math.log(2);var o=t.zoom-(g?r:Math.ceil(r));var p=(k.row-t.row)/(h/this.provider.tileHeight);var d=Math.log(p)/Math.log(2);var e=t.zoom-(g?d:Math.ceil(d));var b=Math.min(o,e);b=Math.min(b,this.provider.outerLimits()[1].zoom);b=Math.max(b,this.provider.outerLimits()[0].zoom);var c=(t.row+k.row)/2;var s=(t.column+k.column)/2;var f=t.zoom;this.coordinate=new a.Coordinate(c,s,f).zoomTo(b);this.draw();this.dispatchCallback("extentset",q);return this},setSize:function(c,b){if(c.hasOwnProperty("x")&&c.hasOwnProperty("y")){this.dimensions=c}else{if(b!==undefined&&!isNaN(b)){this.dimensions=new a.Point(c,b)}}this.parent.style.width=Math.round(this.dimensions.x)+"px";this.parent.style.height=Math.round(this.dimensions.y)+"px";this.draw();this.dispatchCallback("resized",[this.dimensions]);return this},coordinatePoint:function(c){if(c.zoom!=this.coordinate.zoom){c=c.zoomTo(this.coordinate.zoom)}var b=new a.Point(this.dimensions.x/2,this.dimensions.y/2);b.x+=this.provider.tileWidth*(c.column-this.coordinate.column);b.y+=this.provider.tileHeight*(c.row-this.coordinate.row);return b},pointCoordinate:function(b){var c=this.coordinate.copy();c.column+=(b.x-this.dimensions.x/2)/this.provider.tileWidth;c.row+=(b.y-this.dimensions.y/2)/this.provider.tileHeight;return c},locationPoint:function(b){return this.coordinatePoint(this.provider.locationCoordinate(b))},pointLocation:function(b){return this.provider.coordinateLocation(this.pointCoordinate(b))},getExtent:function(){var b=[];b.push(this.pointLocation(new a.Point(0,0)));b.push(this.pointLocation(this.dimensions));return b},getCenter:function(){return this.provider.coordinateLocation(this.coordinate)},getZoom:function(){return this.coordinate.zoom},setProvider:function(d){var e=false;if(this.provider===null){e=true}if(!e){this.requestManager.clear();for(var b in this.layers){if(this.layers.hasOwnProperty(b)){var c=this.layers[b];while(c.firstChild){c.removeChild(c.firstChild)}}}}this.tiles={};this.tileCacheSize=0;this.maxTileCacheSize=64;this.recentTiles=[];this.recentTilesById={};this.provider=d;if(!e){this.draw()}return this},enforceLimits:function(e){e=e.copy();var c=this.provider.outerLimits();if(c){var d=c[0].zoom;var b=c[1].zoom;if(e.zoom<d){e=e.zoomTo(d)}else{if(e.zoom>b){e=e.zoomTo(b)}}}return e},draw:function(){this.coordinate=this.enforceLimits(this.coordinate);var p=Math.round(this.coordinate.zoom);if(this.dimensions.x<=0||this.dimensions.y<=0){if(this.autoSize){var r=this.parent.offsetWidth,C=this.parent.offsetHeight;this.dimensions=new a.Point(r,C);if(r<=0||C<=0){return}}else{return}}var x=this.pointCoordinate(new a.Point(0,0)).zoomTo(p).container();var u=this.pointCoordinate(this.dimensions).zoomTo(p).container().right().down();var l=0;if(l){x=x.left(l).up(l);u=u.right(l).down(l)}var I={};var m=this.createOrGetLayer(x.zoom);var e=x.copy();for(e.column=x.column;e.column<=u.column;e.column+=1){for(e.row=x.row;e.row<=u.row;e.row+=1){var n=e.toKey();I[n]=true;if(n in this.tiles){var L=this.tiles[n];if(L.parentNode!=m){m.appendChild(L)}}else{if(!this.requestManager.hasRequest(n)){var o=this.provider.getTileUrl(e);this.requestManager.requestTile(n,e,o)}var s=false;var H=e.zoom;for(var t=1;t<=H;t++){var v=e.zoomBy(-t).container();var B=v.toKey();if(this.enablePyramidLoading){I[B]=true;var D=this.createOrGetLayer(v.zoom);if(B in this.tiles){var y=this.tiles[B];if(y.parentNode!=D){D.appendChild(y)}}else{if(!this.requestManager.hasRequest(B)){this.requestManager.requestTile(B,v,this.provider.getTileUrl(v))}}}else{if(B in this.tiles){I[B]=true;s=true;break}}}if(!s&&!this.enablePyramidLoading){var k=e.zoomBy(1);I[k.toKey()]=true;k.column+=1;I[k.toKey()]=true;k.row+=1;I[k.toKey()]=true;k.column-=1;I[k.toKey()]=true}}}}for(var M in this.layers){if(this.layers.hasOwnProperty(M)){var d=parseInt(M,10);if(d>=x.zoom-5&&d<x.zoom+2){continue}var K=this.layers[M];K.style.display="none";var G=K.getElementsByTagName("img");for(var z=G.length-1;z>=0;z--){K.removeChild(G[z])}}}var f=new Date().getTime();var E=x.zoom-5;var g=x.zoom+2;for(var A=E;A<g;A++){var K=this.layers[A];if(!K){continue}var J=1,c=this.coordinate.copy(),G=K.getElementsByTagName("img");if(G.length>0){K.style.display="block";J=Math.pow(2,this.coordinate.zoom-A);c=c.zoomTo(A)}else{K.style.display="none"}var b=this.provider.tileWidth*J,q=this.provider.tileHeight*J,F=new a.Point(this.dimensions.x/2,this.dimensions.y/2);for(var z=G.length-1;z>=0;z--){var L=G[z];if(!I[L.id]){K.removeChild(L)}else{a.moveElement(L,{x:Math.round(F.x+(L.coord.column-c.column)*b),y:Math.round(F.y+(L.coord.row-c.row)*q),scale:J,width:this.provider.tileWidth,height:this.provider.tileHeight});this.recentTilesById[L.id].lastTouchedTime=f}}}this.requestManager.clearExcept(I);this.requestManager.processQueue(this.getCenterDistanceCompare());this.checkCache();this.dispatchCallback("drawn")},_tileComplete:null,getTileComplete:function(){if(!this._tileComplete){var b=this;this._tileComplete=function(g,h){b.tiles[h.id]=h;b.tileCacheSize++;var e={id:h.id,lastTouchedTime:new Date().getTime()};b.recentTilesById[h.id]=e;b.recentTiles.push(e);var f=b.coordinate.zoomTo(h.coord.zoom);var j=Math.pow(2,b.coordinate.zoom-h.coord.zoom);var d=((b.dimensions.x/2)+(h.coord.column-f.column)*b.provider.tileWidth*j);var c=((b.dimensions.y/2)+(h.coord.row-f.row)*b.provider.tileHeight*j);a.moveElement(h,{x:Math.round(d),y:Math.round(c),scale:j,width:b.provider.tileWidth,height:b.provider.tileHeight});var i=b.layers[h.coord.zoom];i.appendChild(h);h.className="map-tile-loaded";if(Math.round(b.coordinate.zoom)===h.coord.zoom){i.style.display="block"}b.requestRedraw()}}return this._tileComplete},_redrawTimer:undefined,requestRedraw:function(){if(!this._redrawTimer){this._redrawTimer=setTimeout(this.getRedraw(),1000)}},_redraw:null,getRedraw:function(){if(!this._redraw){var b=this;this._redraw=function(){b.draw();b._redrawTimer=0}}return this._redraw},createOrGetLayer:function(c){if(c in this.layers){return this.layers[c]}var b=document.createElement("div");b.id=this.parent.id+"-zoom-"+c;b.style.cssText=this.layerParent.style.cssText;b.style.zIndex=c;this.layerParent.appendChild(b);this.layers[c]=b;return b},checkCache:function(){var f=this.parent.getElementsByTagName("img").length;var d=Math.max(f,this.maxTileCacheSize);if(this.tileCacheSize>d){this.recentTiles.sort(function(h,g){return g.lastTouchedTime<h.lastTouchedTime?-1:g.lastTouchedTime>h.lastTouchedTime?1:0})}while(this.tileCacheSize>d){var c=this.recentTiles.pop();var b=new Date().getTime();delete this.recentTilesById[c.id];var e=this.tiles[c.id];if(e.parentNode){alert("Gah: trying to removing cached tile even though it's still in the DOM")}else{delete this.tiles[c.id];this.tileCacheSize--}}},getCenterDistanceCompare:function(){var b=this.coordinate.zoomTo(Math.round(this.coordinate.zoom));return function(e,d){if(e&&d){var g=e.coord;var f=d.coord;if(g.zoom==f.zoom){var c=Math.abs(b.row-g.row-0.5)+Math.abs(b.column-g.column-0.5);var h=Math.abs(b.row-f.row-0.5)+Math.abs(b.column-f.column-0.5);return c<h?1:c>h?-1:0}else{return g.zoom<f.zoom?1:g.zoom>f.zoom?-1:0}}return e?1:d?-1:0}},destroy:function(){this.requestManager.clear();for(var b=0;b<this.eventHandlers.length;b++){this.eventHandlers[b].remove()}this.parent.removeChild(this.layerParent);a.removeEvent(window,"resize",this.windowResize());return this}};if(typeof module!=="undefined"&&module.exports){module.exports={Point:a.Point,Projection:a.Projection,MercatorProjection:a.MercatorProjection,LinearProjection:a.LinearProjection,Transformation:a.Transformation,Location:a.Location,MapProvider:a.MapProvider,TemplatedMapProvider:a.TemplatedMapProvider,Coordinate:a.Coordinate}}})(com.modestmaps);
var previousMM=MM;if(!com){var com={};if(!com.modestmaps){com.modestmaps={}}}var MM=com.modestmaps={noConflict:function(){MM=previousMM;return this}};(function(b){b.extend=function(e,c){for(var d in c.prototype){if(typeof e.prototype[d]=="undefined"){e.prototype[d]=c.prototype[d]}}return e};b.getFrame=function(){return function(c){(window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(d){window.setTimeout(function(){d(+new Date())},10)})(c)}}();b.transformProperty=(function(e){if(!this.document){return}var d=document.documentElement.style;for(var c=0;c<e.length;c++){if(e[c] in d){return e[c]}}return false})(["transformProperty","WebkitTransform","OTransform","MozTransform","msTransform"]);b.matrixString=function(c){if(c.scale*c.width%1){c.scale+=(1-c.scale*c.width%1)/c.width}if(b._browser.webkit3d){return"matrix3d("+[(c.scale||"1"),"0,0,0,0",(c.scale||"1"),"0,0","0,0,1,0",(c.x+(((c.width*c.scale)-c.width)/2)).toFixed(4),(c.y+(((c.height*c.scale)-c.height)/2)).toFixed(4),0,1].join(",")+")"}else{var d=(b.transformProperty=="MozTransform")?"px":"";return"matrix("+[(c.scale||"1"),0,0,(c.scale||"1"),(c.x+(((c.width*c.scale)-c.width)/2))+d,(c.y+(((c.height*c.scale)-c.height)/2))+d].join(",")+")"}};b._browser=(function(c){return{webkit:("WebKitCSSMatrix" in c),webkit3d:("WebKitCSSMatrix" in c)&&("m11" in new WebKitCSSMatrix())}})(this);b.moveElement=function(e,c){if(b.transformProperty){var d=b.matrixString(c);if(e[b.transformProperty]!==d){e.style[b.transformProperty]=e[b.transformProperty]=d}}else{e.style.left=c.x+"px";e.style.top=c.y+"px";e.style.width=Math.ceil(c.width*c.scale)+"px";e.style.height=Math.ceil(c.height*c.scale)+"px"}};b.cancelEvent=function(c){c.cancelBubble=true;c.cancel=true;c.returnValue=false;if(c.stopPropagation){c.stopPropagation()}if(c.preventDefault){c.preventDefault()}return false};b.bind=function(e,f){var g=Array.prototype.slice;var d=Function.prototype.bind;if(e.bind===d&&d){return d.apply(e,g.call(arguments,1))}var c=g.call(arguments,2);return function(){return e.apply(f,c.concat(g.call(arguments)))}};b.addEvent=function(e,d,c){if(e.addEventListener){e.addEventListener(d,c,false);if(d=="mousewheel"){e.addEventListener("DOMMouseScroll",c,false)}}else{if(e.attachEvent){e["e"+d+c]=c;e[d+c]=function(){e["e"+d+c](window.event)};e.attachEvent("on"+d,e[d+c])}}};b.removeEvent=function(e,d,c){if(e.removeEventListener){e.removeEventListener(d,c,false);if(d=="mousewheel"){e.removeEventListener("DOMMouseScroll",c,false)}}else{if(e.detachEvent){e.detachEvent("on"+d,e[d+c]);e[d+c]=null}}};b.getStyle=function(d,c){if(d.currentStyle){return d.currentStyle[c]}else{if(window.getComputedStyle){return document.defaultView.getComputedStyle(d,null).getPropertyValue(c)}}};b.Point=function(c,d){this.x=parseFloat(c);this.y=parseFloat(d)};b.Point.prototype={x:0,y:0,toString:function(){return"("+this.x.toFixed(3)+", "+this.y.toFixed(3)+")"},copy:function(){return new b.Point(this.x,this.y)}};b.Point.distance=function(f,e){var d=(e.x-f.x);var c=(e.y-f.y);return Math.sqrt(d*d+c*c)};b.Point.interpolate=function(g,f,e){var d=g.x+(f.x-g.x)*e;var c=g.y+(f.y-g.y)*e;return new b.Point(d,c)};b.Coordinate=function(e,c,d){this.row=e;this.column=c;this.zoom=d};b.Coordinate.prototype={row:0,column:0,zoom:0,toString:function(){return"("+this.row.toFixed(3)+", "+this.column.toFixed(3)+" @"+this.zoom.toFixed(3)+")"},toKey:function(){return[this.zoom,this.row,this.column].join(",")},copy:function(){return new b.Coordinate(this.row,this.column,this.zoom)},container:function(){return new b.Coordinate(Math.floor(this.row),Math.floor(this.column),Math.floor(this.zoom))},zoomTo:function(c){var d=Math.pow(2,c-this.zoom);return new b.Coordinate(this.row*d,this.column*d,c)},zoomBy:function(d){var c=Math.pow(2,d);return new b.Coordinate(this.row*c,this.column*c,this.zoom+d)},up:function(c){if(c===undefined){c=1}return new b.Coordinate(this.row-c,this.column,this.zoom)},right:function(c){if(c===undefined){c=1}return new b.Coordinate(this.row,this.column+c,this.zoom)},down:function(c){if(c===undefined){c=1}return new b.Coordinate(this.row+c,this.column,this.zoom)},left:function(c){if(c===undefined){c=1}return new b.Coordinate(this.row,this.column-c,this.zoom)}};b.Location=function(c,d){this.lat=parseFloat(c);this.lon=parseFloat(d)};b.Location.prototype={lat:0,lon:0,toString:function(){return"("+this.lat.toFixed(3)+", "+this.lon.toFixed(3)+")"},copy:function(){return new b.Location(this.lat,this.lon)}};b.Location.distance=function(j,i,f){if(!f){f=6378000}var p=Math.PI/180,h=j.lat*p,o=j.lon*p,g=i.lat*p,n=i.lon*p,m=Math.cos(h)*Math.cos(o)*Math.cos(g)*Math.cos(n),l=Math.cos(h)*Math.sin(o)*Math.cos(g)*Math.sin(n),k=Math.sin(h)*Math.sin(g);return Math.acos(m+l+k)*f};b.Location.interpolate=function(j,h,n){if(j.lat===h.lat&&j.lon===h.lon){return new b.Location(j.lat,j.lon)}var t=Math.PI/180,l=j.lat*t,o=j.lon*t,k=h.lat*t,m=h.lon*t;var p=2*Math.asin(Math.sqrt(Math.pow(Math.sin((l-k)/2),2)+Math.cos(l)*Math.cos(k)*Math.pow(Math.sin((o-m)/2),2)));var u=Math.atan2(Math.sin(o-m)*Math.cos(k),Math.cos(l)*Math.sin(k)-Math.sin(l)*Math.cos(k)*Math.cos(o-m))/-(Math.PI/180);u=u<0?360+u:u;var g=Math.sin((1-n)*p)/Math.sin(p);var c=Math.sin(n*p)/Math.sin(p);var s=g*Math.cos(l)*Math.cos(o)+c*Math.cos(k)*Math.cos(m);var r=g*Math.cos(l)*Math.sin(o)+c*Math.cos(k)*Math.sin(m);var q=g*Math.sin(l)+c*Math.sin(k);var e=Math.atan2(q,Math.sqrt(Math.pow(s,2)+Math.pow(r,2)));var i=Math.atan2(r,s);return new b.Location(e/t,i/t)};b.MapExtent=function(h,d,g,f){if(arguments[0] instanceof b.Location){var e=arguments[0];h=e.lat;d=e.lon}if(arguments[1] instanceof b.Location){var c=arguments[1];g=c.lat;f=c.lon}if(isNaN(g)){g=h}if(isNaN(f)){f=d}this.north=Math.max(h,g);this.south=Math.min(h,g);this.east=Math.max(f,d);this.west=Math.min(f,d)};b.MapExtent.prototype={north:0,south:0,east:0,west:0,copy:function(){return new b.MapExtent(this.north,this.west,this.south,this.east)},toString:function(c){if(isNaN(c)){c=3}return[this.north.toFixed(c),this.west.toFixed(c),this.south.toFixed(c),this.east.toFixed(c)].join(", ")},northWest:function(){return new b.Location(this.north,this.west)},southEast:function(){return new b.Location(this.south,this.east)},northEast:function(){return new b.Location(this.north,this.east)},southWest:function(){return new b.Location(this.south,this.west)},center:function(){return new b.Location(this.south+(this.north-this.south)/2,this.east+(this.west-this.east)/2)},encloseLocation:function(c){if(c.lat>this.north){this.north=c.lat}if(c.lat<this.south){this.south=c.lat}if(c.lon>this.east){this.east=c.lon}if(c.lon<this.west){this.west=c.lon}},encloseLocations:function(d){var c=d.length;for(var e=0;e<c;e++){this.encloseLocation(d[e])}},setFromLocations:function(d){var c=d.length,f=d[0];this.north=this.south=f.lat;this.east=this.west=f.lon;for(var e=1;e<c;e++){this.encloseLocation(d[e])}},encloseExtent:function(c){if(c.north>this.north){this.north=c.north}if(c.south<this.south){this.south=c.south}if(c.east>this.east){this.east=c.east}if(c.west<this.west){this.west=c.west}},containsLocation:function(c){return c.lat>=this.south&&c.lat<=this.north&&c.lon>=this.west&&c.lon<=this.east},toArray:function(){return[this.northWest(),this.southEast()]}};b.MapExtent.fromString=function(d){var c=d.split(/\s*,\s*/);if(c.length!=4){throw"Invalid extent string (expecting 4 comma-separated numbers)"}return new b.MapExtent(parseFloat(c[0]),parseFloat(c[1]),parseFloat(c[2]),parseFloat(c[3]))};b.MapExtent.fromArray=function(c){var d=new b.MapExtent();d.setFromLocations(c);return d};b.Transformation=function(e,g,c,d,f,h){this.ax=e;this.bx=g;this.cx=c;this.ay=d;this.by=f;this.cy=h};b.Transformation.prototype={ax:0,bx:0,cx:0,ay:0,by:0,cy:0,transform:function(c){return new b.Point(this.ax*c.x+this.bx*c.y+this.cx,this.ay*c.x+this.by*c.y+this.cy)},untransform:function(c){return new b.Point((c.x*this.by-c.y*this.bx-this.cx*this.by+this.cy*this.bx)/(this.ax*this.by-this.ay*this.bx),(c.x*this.ay-c.y*this.ax-this.cx*this.ay+this.cy*this.ax)/(this.bx*this.ay-this.by*this.ax))}};b.deriveTransformation=function(m,l,g,f,c,p,i,h,e,d,o,n){var k=b.linearSolution(m,l,g,c,p,i,e,d,o);var j=b.linearSolution(m,l,f,c,p,h,e,d,n);return new b.Transformation(k[0],k[1],k[2],j[0],j[1],j[2])};b.linearSolution=function(f,o,i,e,n,h,d,m,g){f=parseFloat(f);o=parseFloat(o);i=parseFloat(i);e=parseFloat(e);n=parseFloat(n);h=parseFloat(h);d=parseFloat(d);m=parseFloat(m);g=parseFloat(g);var l=(((h-g)*(o-n))-((i-h)*(n-m)))/(((e-d)*(o-n))-((f-e)*(n-m)));var k=(((h-g)*(f-e))-((i-h)*(e-d)))/(((n-m)*(f-e))-((o-n)*(e-d)));var j=i-(f*l)-(o*k);return[l,k,j]};b.Projection=function(d,c){if(!c){c=new b.Transformation(1,0,0,0,1,0)}this.zoom=d;this.transformation=c};b.Projection.prototype={zoom:0,transformation:null,rawProject:function(c){throw"Abstract method not implemented by subclass."},rawUnproject:function(c){throw"Abstract method not implemented by subclass."},project:function(c){c=this.rawProject(c);if(this.transformation){c=this.transformation.transform(c)}return c},unproject:function(c){if(this.transformation){c=this.transformation.untransform(c)}c=this.rawUnproject(c);return c},locationCoordinate:function(d){var c=new b.Point(Math.PI*d.lon/180,Math.PI*d.lat/180);c=this.project(c);return new b.Coordinate(c.y,c.x,this.zoom)},coordinateLocation:function(d){d=d.zoomTo(this.zoom);var c=new b.Point(d.column,d.row);c=this.unproject(c);return new b.Location(180*c.y/Math.PI,180*c.x/Math.PI)}};b.LinearProjection=function(d,c){b.Projection.call(this,d,c)};b.LinearProjection.prototype={rawProject:function(c){return new b.Point(c.x,c.y)},rawUnproject:function(c){return new b.Point(c.x,c.y)}};b.extend(b.LinearProjection,b.Projection);b.MercatorProjection=function(d,c){b.Projection.call(this,d,c)};b.MercatorProjection.prototype={rawProject:function(c){return new b.Point(c.x,Math.log(Math.tan(0.25*Math.PI+0.5*c.y)))},rawUnproject:function(c){return new b.Point(c.x,2*Math.atan(Math.pow(Math.E,c.y))-0.5*Math.PI)}};b.extend(b.MercatorProjection,b.Projection);b.MapProvider=function(c){if(c){this.getTile=c}};b.MapProvider.prototype={tileLimits:[new b.Coordinate(0,0,0),new b.Coordinate(1,1,0).zoomTo(18)],getTileUrl:function(c){throw"Abstract method not implemented by subclass."},getTile:function(c){throw"Abstract method not implemented by subclass."},releaseTile:function(c){},setZoomRange:function(d,c){this.tileLimits[0]=this.tileLimits[0].zoomTo(d);this.tileLimits[1]=this.tileLimits[1].zoomTo(c)},sourceCoordinate:function(h){var c=this.tileLimits[0].zoomTo(h.zoom);var e=this.tileLimits[1].zoomTo(h.zoom);var d=e.row-c.row;if(h.row<0|h.row>=d){return null}var g=e.column-c.column;var f=h.column%g;while(f<0){f+=g}return new b.Coordinate(h.row,f,h.zoom)}};b.TemplatedMapProvider=function(e,c){var f=false;if(e.match(/{(Q|quadkey)}/)){f=true;e=e.replace("{subdomains}","{S}").replace("{zoom}","{Z}").replace("{quadkey}","{Q}")}var d=(c&&c.length&&e.indexOf("{S}")>=0);var g=function(k){var j=this.sourceCoordinate(k);if(!j){return null}var i=e;if(d){var h=parseInt(j.zoom+j.row+j.column,10)%c.length;i=i.replace("{S}",c[h])}if(f){return i.replace("{Z}",j.zoom.toFixed(0)).replace("{Q}",this.quadKey(j.row,j.column,j.zoom))}else{return i.replace("{Z}",j.zoom.toFixed(0)).replace("{X}",j.column.toFixed(0)).replace("{Y}",j.row.toFixed(0))}};b.MapProvider.call(this,g)};b.TemplatedMapProvider.prototype={quadKey:function(g,e,f){var d="";for(var c=1;c<=f;c++){d+=(((g>>f-c)&1)<<1)|((e>>f-c)&1)}return d||"0"},getTile:function(c){return this.getTileUrl(c)},releaseTile:function(){}};b.extend(b.TemplatedMapProvider,b.MapProvider);b.getMousePoint=function(g,f){var c=new b.Point(g.clientX,g.clientY);c.x+=document.body.scrollLeft+document.documentElement.scrollLeft;c.y+=document.body.scrollTop+document.documentElement.scrollTop;for(var d=f.parent;d;d=d.offsetParent){c.x-=d.offsetLeft;c.y-=d.offsetTop}return c};b.MouseWheelHandler=function(d,c){if(d){this.init(d,c)}else{if(arguments.length>1){this.precise=c?true:false}}};b.MouseWheelHandler.prototype={precise:false,init:function(d){this.map=d;this._mouseWheel=b.bind(this.mouseWheel,this);this._zoomDiv=document.body.appendChild(document.createElement("div"));this._zoomDiv.style.cssText="visibility:hidden;top:0;height:0;width:0;overflow-y:scroll";var c=this._zoomDiv.appendChild(document.createElement("div"));c.style.height="2000px";b.addEvent(d.parent,"mousewheel",this._mouseWheel)},remove:function(){b.removeEvent(this.map.parent,"mousewheel",this._mouseWheel);this._zoomDiv.parentNode.removeChild(this._zoomDiv)},mouseWheel:function(g){var h=0;this.prevTime=this.prevTime||new Date().getTime();try{this._zoomDiv.scrollTop=1000;this._zoomDiv.dispatchEvent(g);h=1000-this._zoomDiv.scrollTop}catch(d){h=g.wheelDelta||(-g.detail*5)}var f=new Date().getTime()-this.prevTime;if(Math.abs(h)>0&&(f>200)&&!this.precise){var c=b.getMousePoint(g,this.map);this.map.zoomByAbout(h>0?1:-1,c);this.prevTime=new Date().getTime()}else{if(this.precise){var c=b.getMousePoint(g,this.map);this.map.zoomByAbout(h*0.001,c)}}return b.cancelEvent(g)}};b.DoubleClickHandler=function(c){if(c!==undefined){this.init(c)}};b.DoubleClickHandler.prototype={init:function(c){this.map=c;this._doubleClick=b.bind(this.doubleClick,this);b.addEvent(c.parent,"dblclick",this._doubleClick)},remove:function(){b.removeEvent(this.map.parent,"dblclick",this._doubleClick)},doubleClick:function(d){var c=b.getMousePoint(d,this.map);this.map.zoomByAbout(d.shiftKey?-1:1,c);return b.cancelEvent(d)}};b.DragHandler=function(c){if(c!==undefined){this.init(c)}};b.DragHandler.prototype={init:function(c){this.map=c;this._mouseDown=b.bind(this.mouseDown,this);b.addEvent(c.parent,"mousedown",this._mouseDown)},remove:function(){b.removeEvent(this.map.parent,"mousedown",this._mouseDown)},mouseDown:function(c){b.addEvent(document,"mouseup",this._mouseUp=b.bind(this.mouseUp,this));b.addEvent(document,"mousemove",this._mouseMove=b.bind(this.mouseMove,this));this.prevMouse=new b.Point(c.clientX,c.clientY);this.map.parent.style.cursor="move";return b.cancelEvent(c)},mouseMove:function(c){if(this.prevMouse){this.map.panBy(c.clientX-this.prevMouse.x,c.clientY-this.prevMouse.y);this.prevMouse.x=c.clientX;this.prevMouse.y=c.clientY;this.prevMouse.t=+new Date()}return b.cancelEvent(c)},mouseUp:function(c){b.removeEvent(document,"mouseup",this._mouseUp);b.removeEvent(document,"mousemove",this._mouseMove);this.prevMouse=null;this.map.parent.style.cursor="";return b.cancelEvent(c)}};b.MouseHandler=function(c){if(c!==undefined){this.init(c)}};b.MouseHandler.prototype={init:function(c){this.map=c;this.handlers=[new b.DragHandler(c),new b.DoubleClickHandler(c),new b.MouseWheelHandler(c)]},remove:function(){for(var c=0;c<this.handlers.length;c++){this.handlers[c].remove()}}};var a=(function(){var c=window.documentMode;return("onhashchange" in window)&&(c===undefined||c>7)})();b.Hash=function(c){this.onMapMove=b.bind(this.onMapMove,this);this.onHashChange=b.bind(this.onHashChange,this);if(c){this.init(c)}};b.Hash.prototype={map:null,lastHash:null,parseHash:function(f){var c=f.split("/");if(c.length==3){var d=parseInt(c[0],10),e=parseFloat(c[1]),g=parseFloat(c[2]);if(isNaN(d)||isNaN(e)||isNaN(g)){return false}else{return{center:new b.Location(e,g),zoom:d}}}else{return false}},formatHash:function(f){var c=f.getCenter(),e=f.getZoom(),d=Math.max(0,Math.ceil(Math.log(e)/Math.LN2));return"#"+[e,c.lat.toFixed(d),c.lon.toFixed(d)].join("/")},init:function(c){this.map=c;this.map.addCallback("drawn",this.onMapMove);this.lastHash=null;this.onHashChange();if(!this.isListening){this.startListening()}},remove:function(){this.map=null;if(this.isListening){this.stopListening()}},onMapMove:function(d){if(this.movingMap||this.map.zoom===0){return false}var c=this.formatHash(d);if(this.lastHash!=c){location.replace(c);this.lastHash=c}},movingMap:false,update:function(){var e=location.hash;if(e===this.lastHash){return}var d=e.substr(1),c=this.parseHash(d);if(c){this.movingMap=true;this.map.setCenterZoom(c.center,c.zoom);this.movingMap=false}else{this.onMapMove(this.map)}},changeDefer:100,changeTimeout:null,onHashChange:function(){if(!this.changeTimeout){var c=this;this.changeTimeout=setTimeout(function(){c.update();c.changeTimeout=null},this.changeDefer)}},isListening:false,hashChangeInterval:null,startListening:function(){if(a){window.addEventListener("hashchange",this.onHashChange,false)}else{clearInterval(this.hashChangeInterval);this.hashChangeInterval=setInterval(this.onHashChange,50)}this.isListening=true},stopListening:function(){if(a){window.removeEventListener("hashchange",this.onHashChange)}else{clearInterval(this.hashChangeInterval)}this.isListening=false}};b.TouchHandler=function(d,c){if(d){this.init(d,c)}};b.TouchHandler.prototype={maxTapTime:250,maxTapDistance:30,maxDoubleTapDelay:350,locations:{},taps:[],wasPinching:false,lastPinchCenter:null,init:function(d,c){this.map=d;c=c||{};if(!this.isTouchable()){return false}this._touchStartMachine=b.bind(this.touchStartMachine,this);this._touchMoveMachine=b.bind(this.touchMoveMachine,this);this._touchEndMachine=b.bind(this.touchEndMachine,this);b.addEvent(d.parent,"touchstart",this._touchStartMachine);b.addEvent(d.parent,"touchmove",this._touchMoveMachine);b.addEvent(d.parent,"touchend",this._touchEndMachine);this.options={};this.options.snapToZoom=c.snapToZoom||true},isTouchable:function(){var c=document.createElement("div");c.setAttribute("ongesturestart","return;");return(typeof c.ongesturestart==="function")},remove:function(){if(!this.isTouchable()){return false}b.removeEvent(this.map.parent,"touchstart",this._touchStartMachine);b.removeEvent(this.map.parent,"touchmove",this._touchMoveMachine);b.removeEvent(this.map.parent,"touchend",this._touchEndMachine)},updateTouches:function(g){for(var f=0;f<g.touches.length;f+=1){var d=g.touches[f];if(d.identifier in this.locations){var c=this.locations[d.identifier];c.x=d.screenX;c.y=d.screenY;c.scale=g.scale}else{this.locations[d.identifier]={scale:g.scale,startPos:{x:d.screenX,y:d.screenY},x:d.screenX,y:d.screenY,time:new Date().getTime()}}}},sameTouch:function(c,d){return(c&&c.touch)&&(d.identifier==c.touch.identifier)},touchStartMachine:function(c){this.updateTouches(c);return b.cancelEvent(c)},touchMoveMachine:function(c){switch(c.touches.length){case 1:this.onPanning(c.touches[0]);break;case 2:this.onPinching(c);break}this.updateTouches(c);return b.cancelEvent(c)},touchEndMachine:function(m){var d=new Date().getTime();if(m.touches.length===0&&this.wasPinching){this.onPinched(this.lastPinchCenter)}for(var k=0;k<m.changedTouches.length;k+=1){var p=m.changedTouches[k],l=this.locations[p.identifier];if(!l||l.wasPinch){continue}var o={x:p.screenX,y:p.screenY},g=d-l.time,f=b.Point.distance(o,l.startPos);if(f>this.maxTapDistance){}else{if(g>this.maxTapTime){o.end=d;o.duration=g;this.onHold(o)}else{o.time=d;this.onTap(o)}}}var n={};for(var h=0;h<m.touches.length;h++){n[m.touches[h].identifier]=true}for(var c in this.locations){if(!(c in n)){delete n[c]}}return b.cancelEvent(m)},onHold:function(c){},onTap:function(c){if(this.taps.length&&(c.time-this.taps[0].time)<this.maxDoubleTapDelay){this.onDoubleTap(c);this.taps=[];return}this.taps=[c]},onDoubleTap:function(d){var f=this.map.getZoom(),g=Math.round(f)+1,c=g-f;var e=new b.Point(d.x,d.y);this.map.zoomByAbout(c,e)},onPanning:function(e){var d={x:e.screenX,y:e.screenY},c=this.locations[e.identifier];this.map.panBy(d.x-c.x,d.y-c.y)},onPinching:function(j){var i=j.touches[0],h=j.touches[1],l=new b.Point(i.screenX,i.screenY),k=new b.Point(h.screenX,h.screenY),f=this.locations[i.identifier],d=this.locations[h.identifier];f.wasPinch=true;d.wasPinch=true;var c=b.Point.interpolate(l,k,0.5);this.map.zoomByAbout(Math.log(j.scale)/Math.LN2-Math.log(f.scale)/Math.LN2,c);var g=b.Point.interpolate(f,d,0.5);this.map.panBy(c.x-g.x,c.y-g.y);this.wasPinching=true;this.lastPinchCenter=c},onPinched:function(c){if(this.options.snapToZoom){var d=this.map.getZoom(),e=Math.round(d);this.map.zoomByAbout(e-d,c)}this.wasPinching=false}};b.CallbackManager=function(c,e){this.owner=c;this.callbacks={};for(var d=0;d<e.length;d++){this.callbacks[e[d]]=[]}};b.CallbackManager.prototype={owner:null,callbacks:null,addCallback:function(c,d){if(typeof(d)=="function"&&this.callbacks[c]){this.callbacks[c].push(d)}},removeCallback:function(f,g){if(typeof(g)=="function"&&this.callbacks[f]){var d=this.callbacks[f],c=d.length;for(var e=0;e<c;e++){if(d[e]===g){d.splice(e,1);break}}}},dispatchCallback:function(f,d){if(this.callbacks[f]){for(var c=0;c<this.callbacks[f].length;c+=1){try{this.callbacks[f][c](this.owner,d)}catch(g){}}}}};b.RequestManager=function(){this.loadingBay=document.createDocumentFragment();this.requestsById={};this.openRequestCount=0;this.maxOpenRequests=4;this.requestQueue=[];this.callbackManager=new b.CallbackManager(this,["requestcomplete","requesterror"])};b.RequestManager.prototype={loadingBay:null,requestsById:null,requestQueue:null,openRequestCount:null,maxOpenRequests:null,callbackManager:null,addCallback:function(c,d){this.callbackManager.addCallback(c,d)},removeCallback:function(c,d){this.callbackManager.removeCallback(c,d)},dispatchCallback:function(d,c){this.callbackManager.dispatchCallback(d,c)},clear:function(){this.clearExcept({})},clearRequest:function(e){if(e in this.requestsById){delete this.requestsById[e]}for(var c=0;c<this.requestQueue.length;c++){var d=this.requestQueue[c];if(d&&d.id==e){this.requestQueue[c]=null}}},clearExcept:function(g){for(var f=0;f<this.requestQueue.length;f++){var h=this.requestQueue[f];if(h&&!(h.id in g)){this.requestQueue[f]=null}}var c=this.loadingBay.childNodes;for(var e=c.length-1;e>=0;e--){var d=c[e];if(!(d.id in g)){this.loadingBay.removeChild(d);this.openRequestCount--;d.src=d.coord=d.onload=d.onerror=null}}for(var l in this.requestsById){if(this.requestsById.hasOwnProperty(l)){if(!(l in g)){var k=this.requestsById[l];delete this.requestsById[l];if(k!==null){k=k.id=k.coord=k.url=null}}}}},hasRequest:function(c){return(c in this.requestsById)},requestTile:function(f,e,c){if(!(f in this.requestsById)){var d={id:f,coord:e.copy(),url:c};this.requestsById[f]=d;if(c){this.requestQueue.push(d)}}},getProcessQueue:function(){if(!this._processQueue){var c=this;this._processQueue=function(){c.processQueue()}}return this._processQueue},processQueue:function(e){if(e&&this.requestQueue.length>8){this.requestQueue.sort(e)}while(this.openRequestCount<this.maxOpenRequests&&this.requestQueue.length>0){var d=this.requestQueue.pop();if(d){this.openRequestCount++;var c=document.createElement("img");c.id=d.id;c.style.position="absolute";c.coord=d.coord;this.loadingBay.appendChild(c);c.onload=c.onerror=this.getLoadComplete();c.src=d.url;d=d.id=d.coord=d.url=null}}},_loadComplete:null,getLoadComplete:function(){if(!this._loadComplete){var c=this;this._loadComplete=function(f){f=f||window.event;var d=f.srcElement||f.target;d.onload=d.onerror=null;c.loadingBay.removeChild(d);c.openRequestCount--;delete c.requestsById[d.id];if(f.type==="load"&&(d.complete||(d.readyState&&d.readyState=="complete"))){c.dispatchCallback("requestcomplete",d)}else{c.dispatchCallback("requesterror",d.src);d.src=null}setTimeout(c.getProcessQueue(),0)}}return this._loadComplete}};b.Layer=function(d,c){this.parent=c||document.createElement("div");this.parent.style.cssText="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; margin: 0; padding: 0; z-index: 0";this.levels={};this.requestManager=new b.RequestManager();this.requestManager.addCallback("requestcomplete",this.getTileComplete());if(d){this.setProvider(d)}};b.Layer.prototype={map:null,parent:null,tiles:null,levels:null,requestManager:null,tileCacheSize:null,maxTileCacheSize:null,provider:null,recentTiles:null,recentTilesById:null,enablePyramidLoading:false,_tileComplete:null,getTileComplete:function(){if(!this._tileComplete){var c=this;this._tileComplete=function(e,f){c.tiles[f.id]=f;c.tileCacheSize++;var d={id:f.id,lastTouchedTime:new Date().getTime()};c.recentTilesById[f.id]=d;c.recentTiles.push(d);c.positionTile(f)}}return this._tileComplete},draw:function(){var o=Math.round(this.map.coordinate.zoom);var n=this.map.pointCoordinate(new b.Point(0,0)).zoomTo(o).container();var i=this.map.pointCoordinate(this.map.dimensions).zoomTo(o).container().right().down();var k={};var m=this.createOrGetLevel(n.zoom);var h=n.copy();for(h.column=n.column;h.column<=i.column;h.column++){for(h.row=n.row;h.row<=i.row;h.row++){var d=this.inventoryVisibleTile(m,h);while(d.length){k[d.pop()]=true}}}for(var f in this.levels){if(this.levels.hasOwnProperty(f)){var p=parseInt(f,10);if(p>=n.zoom-5&&p<n.zoom+2){continue}var e=this.levels[f];e.style.display="none";var g=this.tileElementsInLevel(e);while(g.length){this.provider.releaseTile(g[0].coord);this.requestManager.clearRequest(g[0].coord.toKey());e.removeChild(g[0]);g.shift()}}}var c=n.zoom-5;var l=n.zoom+2;for(var j=c;j<l;j++){this.adjustVisibleLevel(this.levels[j],j,k)}this.requestManager.clearExcept(k);this.requestManager.processQueue(this.getCenterDistanceCompare());this.checkCache()},inventoryVisibleTile:function(q,d){var i=d.toKey(),e=[i];if(i in this.tiles){var h=this.tiles[i];if(h.parentNode!=q){q.appendChild(h);if("reAddTile" in this.provider){this.provider.reAddTile(i,d,h)}}return e}if(!this.requestManager.hasRequest(i)){var p=this.provider.getTile(d);if(typeof p=="string"){this.addTileImage(i,d,p)}else{if(p){this.addTileElement(i,d,p)}}}var f=false;var n=d.zoom;for(var j=1;j<=n;j++){var c=d.zoomBy(-j).container();var o=c.toKey();if(this.enablePyramidLoading){e.push(o);var m=this.createOrGetLevel(c.zoom);if(o in this.tiles){var l=this.tiles[o];if(l.parentNode!=m){m.appendChild(l)}}else{if(!this.requestManager.hasRequest(o)){var g=this.provider.getTile(c);if(typeof g=="string"){this.addTileImage(o,c,g)}else{this.addTileElement(o,c,g)}}}}else{if(o in this.tiles){e.push(o);f=true;break}}}if(!f&&!this.enablePyramidLoading){var k=d.zoomBy(1);e.push(k.toKey());k.column+=1;e.push(k.toKey());k.row+=1;e.push(k.toKey());k.column-=1;e.push(k.toKey())}return e},tileElementsInLevel:function(e){var c=[];for(var d=e.firstChild;d;d=d.nextSibling){if(d.nodeType==1){c.push(d)}}return c},adjustVisibleLevel:function(d,m,f){var e=new Date().getTime();if(!d){return}var g=1;var l=this.map.coordinate.copy();if(d.childNodes.length>0){d.style.display="block";g=Math.pow(2,this.map.coordinate.zoom-m);l=l.zoomTo(m)}else{d.style.display="none"}var j=this.map.tileSize.x*g;var h=this.map.tileSize.y*g;var c=new b.Point(this.map.dimensions.x/2,this.map.dimensions.y/2);var k=this.tileElementsInLevel(d);while(k.length){var i=k.pop();if(!f[i.id]){this.provider.releaseTile(i.coord);this.requestManager.clearRequest(i.coord.toKey());d.removeChild(i)}else{b.moveElement(i,{x:Math.round(c.x+(i.coord.column-l.column)*j),y:Math.round(c.y+(i.coord.row-l.row)*h),scale:g,width:this.map.tileSize.x,height:this.map.tileSize.y});this.recentTilesById[i.id].lastTouchedTime=e}}},createOrGetLevel:function(c){if(c in this.levels){return this.levels[c]}var d=document.createElement("div");d.id=this.parent.id+"-zoom-"+c;d.style.cssText=this.parent.style.cssText;d.style.zIndex=c;this.parent.appendChild(d);this.levels[c]=d;return d},addTileImage:function(d,e,c){this.requestManager.requestTile(d,e,c)},addTileElement:function(e,f,d){d.id=e;d.coord=f.copy();this.tiles[e]=d;this.tileCacheSize++;var c={id:e,lastTouchedTime:new Date().getTime()};this.recentTilesById[e]=c;this.recentTiles.push(c);this.positionTile(d)},positionTile:function(g){var f=this.map.coordinate.zoomTo(g.coord.zoom);var h=Math.pow(2,this.map.coordinate.zoom-g.coord.zoom);g.style.cssText="position:absolute;-webkit-user-select: none;-webkit-user-drag: none;-moz-user-drag: none;";g.ondragstart=function(){return false};var d=((this.map.dimensions.x/2)+(g.coord.column-f.column)*this.map.tileSize.x*h);var c=((this.map.dimensions.y/2)+(g.coord.row-f.row)*this.map.tileSize.y*h);b.moveElement(g,{x:Math.round(d),y:Math.round(c),scale:h,width:this.map.tileSize.x,height:this.map.tileSize.y});var e=this.levels[g.coord.zoom];e.appendChild(g);g.className="map-tile-loaded";if(Math.round(this.map.coordinate.zoom)==g.coord.zoom){e.style.display="block"}this.requestRedraw()},_redrawTimer:undefined,requestRedraw:function(){if(!this._redrawTimer){this._redrawTimer=setTimeout(this.getRedraw(),1000)}},_redraw:null,getRedraw:function(){if(!this._redraw){var c=this;this._redraw=function(){c.draw();c._redrawTimer=0}}return this._redraw},checkCache:function(){var g=this.parent.getElementsByTagName("img").length;var e=Math.max(g,this.maxTileCacheSize);if(this.tileCacheSize>e){this.recentTiles.sort(function(i,h){return h.lastTouchedTime<i.lastTouchedTime?-1:h.lastTouchedTime>i.lastTouchedTime?1:0})}while(this.tileCacheSize>e){var d=this.recentTiles.pop();var c=new Date().getTime();delete this.recentTilesById[d.id];var f=this.tiles[d.id];if(f.parentNode){alert("Gah: trying to removing cached tile even though it's still in the DOM")}else{delete this.tiles[d.id];this.tileCacheSize--}}},setProvider:function(d){var e=(this.provider===null);if(!e){this.requestManager.clear();for(var c in this.levels){if(this.levels.hasOwnProperty(c)){var f=this.levels[c];while(f.firstChild){this.provider.releaseTile(f.firstChild.coord);f.removeChild(f.firstChild)}}}}this.tiles={};this.tileCacheSize=0;this.maxTileCacheSize=64;this.recentTilesById={};this.recentTiles=[];this.provider=d;if(!e){this.draw()}},getCenterDistanceCompare:function(){var c=this.map.coordinate.zoomTo(Math.round(this.map.coordinate.zoom));return function(f,e){if(f&&e){var h=f.coord;var g=e.coord;if(h.zoom==g.zoom){var d=Math.abs(c.row-h.row-0.5)+Math.abs(c.column-h.column-0.5);var i=Math.abs(c.row-g.row-0.5)+Math.abs(c.column-g.column-0.5);return d<i?1:d>i?-1:0}else{return h.zoom<g.zoom?1:h.zoom>g.zoom?-1:0}}return f?1:e?-1:0}},destroy:function(){this.requestManager.clear();this.requestManager.removeCallback("requestcomplete",this.getTileComplete());this.provider=null;if(this.parent.parentNode){this.parent.parentNode.removeChild(this.parent)}this.map=null}};b.Map=function(g,f,h,k){if(typeof g=="string"){g=document.getElementById(g);if(!g){throw"The ID provided to modest maps could not be found."}}this.parent=g;this.parent.style.padding="0";this.parent.style.overflow="hidden";var c=b.getStyle(this.parent,"position");if(c!="relative"&&c!="absolute"){this.parent.style.position="relative"}this.layers=[];if(!(f instanceof Array)){f=[f]}for(var e=0;e<f.length;e++){this.addLayer(f[e])}this.projection=new b.MercatorProjection(0,b.deriveTransformation(-Math.PI,Math.PI,0,0,Math.PI,Math.PI,1,0,-Math.PI,-Math.PI,0,1));this.tileSize=new b.Point(256,256);this.coordLimits=[new b.Coordinate(0,-Infinity,0),new b.Coordinate(1,Infinity,0).zoomTo(18)];this.coordinate=new b.Coordinate(0.5,0.5,0);if(!h){h=new b.Point(this.parent.offsetWidth,this.parent.offsetHeight);this.autoSize=true;b.addEvent(window,"resize",this.windowResize())}else{this.autoSize=false;this.parent.style.width=Math.round(h.x)+"px";this.parent.style.height=Math.round(h.y)+"px"}this.dimensions=h;this.callbackManager=new b.CallbackManager(this,["zoomed","panned","centered","extentset","resized","drawn"]);if(k===undefined){this.eventHandlers=[new b.MouseHandler(this),new b.TouchHandler(this)]}else{this.eventHandlers=k;if(k instanceof Array){for(var d=0;d<k.length;d++){k[d].init(this)}}}};b.Map.prototype={parent:null,dimensions:null,projection:null,coordinate:null,tileSize:null,coordLimits:null,layers:null,callbackManager:null,eventHandlers:null,autoSize:null,toString:function(){return"Map(#"+this.parent.id+")"},addCallback:function(c,d){this.callbackManager.addCallback(c,d);return this},removeCallback:function(c,d){this.callbackManager.removeCallback(c,d);return this},dispatchCallback:function(d,c){this.callbackManager.dispatchCallback(d,c);return this},windowResize:function(){if(!this._windowResize){var c=this;this._windowResize=function(d){c.dimensions=new b.Point(c.parent.offsetWidth,c.parent.offsetHeight);c.draw();c.dispatchCallback("resized",[c.dimensions])}}return this._windowResize},setZoomRange:function(d,c){this.coordLimits[0]=this.coordLimits[0].zoomTo(d);this.coordLimits[1]=this.coordLimits[1].zoomTo(c)},zoomBy:function(c){this.coordinate=this.enforceLimits(this.coordinate.zoomBy(c));b.getFrame(this.getRedraw());this.dispatchCallback("zoomed",c);return this},zoomIn:function(){return this.zoomBy(1)},zoomOut:function(){return this.zoomBy(-1)},setZoom:function(c){return this.zoomBy(c-this.coordinate.zoom)},zoomByAbout:function(d,c){var f=this.pointLocation(c);this.coordinate=this.enforceLimits(this.coordinate.zoomBy(d));var e=this.locationPoint(f);this.dispatchCallback("zoomed",d);return this.panBy(c.x-e.x,c.y-e.y)},panBy:function(d,c){this.coordinate.column-=d/this.tileSize.x;this.coordinate.row-=c/this.tileSize.y;this.coordinate=this.enforceLimits(this.coordinate);b.getFrame(this.getRedraw());this.dispatchCallback("panned",[d,c]);return this},panLeft:function(){return this.panBy(100,0)},panRight:function(){return this.panBy(-100,0)},panDown:function(){return this.panBy(0,-100)},panUp:function(){return this.panBy(0,100)},setCenter:function(c){return this.setCenterZoom(c,this.coordinate.zoom)},setCenterZoom:function(c,d){this.coordinate=this.projection.locationCoordinate(c).zoomTo(parseFloat(d)||0);b.getFrame(this.getRedraw());this.dispatchCallback("centered",[c,d]);return this},setExtent:function(q,r){if(q instanceof b.MapExtent){q=q.toArray()}var u,k;for(var l=0;l<q.length;l++){var m=this.projection.locationCoordinate(q[l]);if(u){u.row=Math.min(u.row,m.row);u.column=Math.min(u.column,m.column);u.zoom=Math.min(u.zoom,m.zoom);k.row=Math.max(k.row,m.row);k.column=Math.max(k.column,m.column);k.zoom=Math.max(k.zoom,m.zoom)}else{u=m.copy();k=m.copy()}}var j=this.dimensions.x+1;var h=this.dimensions.y+1;var n=(k.column-u.column)/(j/this.tileSize.x);var s=Math.log(n)/Math.log(2);var o=u.zoom-(r?s:Math.ceil(s));var p=(k.row-u.row)/(h/this.tileSize.y);var e=Math.log(p)/Math.log(2);var f=u.zoom-(r?e:Math.ceil(e));var c=Math.min(o,f);c=Math.min(c,this.coordLimits[1].zoom);c=Math.max(c,this.coordLimits[0].zoom);var d=(u.row+k.row)/2;var t=(u.column+k.column)/2;var g=u.zoom;this.coordinate=new b.Coordinate(d,t,g).zoomTo(c);this.draw();this.dispatchCallback("extentset",q);return this},setSize:function(c){this.dimensions=new b.Point(c.x,c.y);this.parent.style.width=Math.round(this.dimensions.x)+"px";this.parent.style.height=Math.round(this.dimensions.y)+"px";if(this.autoSize){b.removeEvent(window,"resize",this.windowResize());this.autoSize=false}this.draw();this.dispatchCallback("resized",this.dimensions);return this},coordinatePoint:function(d){if(d.zoom!=this.coordinate.zoom){d=d.zoomTo(this.coordinate.zoom)}var c=new b.Point(this.dimensions.x/2,this.dimensions.y/2);c.x+=this.tileSize.x*(d.column-this.coordinate.column);c.y+=this.tileSize.y*(d.row-this.coordinate.row);return c},pointCoordinate:function(c){var d=this.coordinate.copy();d.column+=(c.x-this.dimensions.x/2)/this.tileSize.x;d.row+=(c.y-this.dimensions.y/2)/this.tileSize.y;return d},locationCoordinate:function(c){return this.projection.locationCoordinate(c)},coordinateLocation:function(c){return this.projection.coordinateLocation(c)},locationPoint:function(c){return this.coordinatePoint(this.locationCoordinate(c))},pointLocation:function(c){return this.coordinateLocation(this.pointCoordinate(c))},getExtent:function(){var c=[];c.push(this.pointLocation(new b.Point(0,0)));c.push(this.pointLocation(this.dimensions));return c},extent:function(c,d){if(c){return this.setExtent(c,d)}else{return this.getExtent()}},getCenter:function(){return this.projection.coordinateLocation(this.coordinate)},center:function(c){if(c){return this.setCenter(c)}else{return this.getCenter()}},getZoom:function(){return this.coordinate.zoom},zoom:function(c){if(c!==undefined){return this.setZoom(c)}else{return this.getZoom()}},coerceLayer:function(c){if("draw" in c&&typeof c.draw=="function"){return c}else{if(typeof c=="string"){return new b.Layer(new b.TemplatedMapProvider(c))}else{return new b.Layer(c)}}},getLayers:function(){return this.layers.slice()},getLayerAt:function(c){return this.layers[c]},addLayer:function(c){c=this.coerceLayer(c);this.layers.push(c);if(!c.parent.parentNode){this.parent.appendChild(c.parent)}c.map=this;return this},removeLayer:function(d){for(var c=0;c<this.layers.length;c++){if(d==this.layers[c]){this.removeLayerAt(c);break}}return this},setLayerAt:function(c,d){if(c<0||c>=this.layers.length){throw new Error("invalid index in setLayerAt(): "+c)}d=this.coerceLayer(d);if(this.layers[c]!=d){if(c<this.layers.length){this.layers[c].destroy()}this.layers[c]=d;this.parent.appendChild(d.parent);d.map=this;b.getFrame(this.getRedraw())}return this},insertLayerAt:function(d,e){if(d<0||d>this.layers.length){throw new Error("invalid index in insertLayerAt(): "+d)}e=this.coerceLayer(e);if(d==this.layers.length){this.layers.push(e);this.parent.appendChild(e.parent)}else{var c=this.layers[d];this.parent.insertBefore(e.parent,c.parent);this.layers.splice(d,0,e)}e.map=this;b.getFrame(this.getRedraw());return this},removeLayerAt:function(d){if(d<0||d>=this.layers.length){throw new Error("invalid index in removeLayer(): "+d)}var c=this.layers[d];this.layers.splice(d,1);c.destroy();return this},swapLayersAt:function(d,c){if(d<0||d>=this.layers.length||c<0||c>=this.layers.length){throw new Error("invalid index in swapLayersAt(): "+index)}var g=this.layers[d],e=this.layers[c],f=document.createElement("div");this.parent.replaceChild(f,e.parent);this.parent.replaceChild(e.parent,g.parent);this.parent.replaceChild(g.parent,f);this.layers[d]=e;this.layers[c]=g;return this},enforceZoomLimits:function(f){var d=this.coordLimits;if(d){var e=d[0].zoom;var c=d[1].zoom;if(f.zoom<e){f=f.zoomTo(e)}else{if(f.zoom>c){f=f.zoomTo(c)}}}return f},enforcePanLimits:function(h){var d=this.coordLimits;if(d){h=h.copy();var f=d[0].zoomTo(h.zoom);var c=d[1].zoomTo(h.zoom);var e=this.pointCoordinate(new b.Point(0,0));var g=this.pointCoordinate(this.dimensions);if(c.row-f.row<g.row-e.row){h.row=(c.row+f.row)/2}else{if(e.row<f.row){h.row+=f.row-e.row}else{if(g.row>c.row){h.row-=g.row-c.row}}}if(c.column-f.column<g.column-e.column){h.column=(c.column+f.column)/2}else{if(e.column<f.column){h.column+=f.column-e.column}else{if(g.column>c.column){h.column-=g.column-c.column}}}}return h},enforceLimits:function(c){return this.enforcePanLimits(this.enforceZoomLimits(c))},draw:function(){this.coordinate=this.enforceLimits(this.coordinate);if(this.dimensions.x<=0||this.dimensions.y<=0){if(this.autoSize){var c=this.parent.offsetWidth,e=this.parent.offsetHeight;this.dimensions=new b.Point(c,e);if(c<=0||e<=0){return}}else{return}}for(var d=0;d<this.layers.length;d++){this.layers[d].draw()}this.dispatchCallback("drawn")},_redrawTimer:undefined,requestRedraw:function(){if(!this._redrawTimer){this._redrawTimer=setTimeout(this.getRedraw(),1000)}},_redraw:null,getRedraw:function(){if(!this._redraw){var c=this;this._redraw=function(){c.draw();c._redrawTimer=0}}return this._redraw},destroy:function(){for(var c=0;c<this.layers.length;c++){this.layers[c].destroy()}this.layers=[];this.projection=null;for(var d=0;d<this.eventHandlers.length;d++){this.eventHandlers[d].remove()}if(this.autoSize){b.removeEvent(window,"resize",this.windowResize())}}};if(typeof module!=="undefined"&&module.exports){module.exports={Point:b.Point,Projection:b.Projection,MercatorProjection:b.MercatorProjection,LinearProjection:b.LinearProjection,Transformation:b.Transformation,Location:b.Location,MapProvider:b.MapProvider,TemplatedMapProvider:b.TemplatedMapProvider,Coordinate:b.Coordinate,deriveTransformation:b.deriveTransformation}}})(MM);
{
"name": "modestmaps",
"description": "a display and interaction library for tile-based maps",
"version": "0.21.0",
"version": "1.0.0-alpha",
"author": {

@@ -12,2 +12,3 @@ "name": "Tom Carden",

"Mike Migurski <mike-fromsite@teczno.com>",
"Shawn Allen <shawn@stamen.com>",
"Tom MacWright <tom@macwright.org>"

@@ -24,3 +25,2 @@ ],

"docco": "~0.3.0",
"expresso": "~0.7.0",
"uglify-js": "~1.0.0"

@@ -27,0 +27,0 @@ },

@@ -11,5 +11,6 @@ if (typeof module !== 'undefined' && module.exports) {

TemplatedMapProvider: MM.TemplatedMapProvider,
Coordinate: MM.Coordinate
Coordinate: MM.Coordinate,
deriveTransformation: MM.deriveTransformation
};
}
})(com.modestmaps);
})(MM);

@@ -13,2 +13,5 @@ // Location

return "(" + this.lat.toFixed(3) + ", " + this.lon.toFixed(3) + ")";
},
copy: function() {
return new MM.Location(this.lat, this.lon);
}

@@ -15,0 +18,0 @@ };

@@ -8,4 +8,5 @@

// Can also be an ID of a DOM element
// * `provider` (required MapProvider)
// Provides tile URLs and map projections
// * `layerOrLayers` (required MM.Layer or Array of MM.Layers)
// each one must implement draw(), destroy(), have a .parent DOM element and a .map property
// (an array of URL templates or MM.MapProviders is also acceptable)
// * `dimensions` (optional Point)

@@ -16,3 +17,3 @@ // Size of map to create

// Otherwise, each handler will be called with init(map)
MM.Map = function(parent, provider, dimensions, eventHandlers) {
MM.Map = function(parent, layerOrLayers, dimensions, eventHandlers) {

@@ -38,40 +39,44 @@ if (typeof parent == 'string') {

this.layers = [];
if(!(layerOrLayers instanceof Array)) {
layerOrLayers = [ layerOrLayers ];
}
for (var i = 0; i < layerOrLayers.length; i++) {
this.addLayer(layerOrLayers[i]);
}
// default to Google-y Mercator style maps
this.projection = new MM.MercatorProjection(0,
MM.deriveTransformation(-Math.PI, Math.PI, 0, 0,
Math.PI, Math.PI, 1, 0,
-Math.PI, -Math.PI, 0, 1));
this.tileSize = new MM.Point(256, 256);
// default 0-18 zoom level
// with infinite horizontal pan and clamped vertical pan
this.coordLimits = [
new MM.Coordinate(0,-Infinity,0), // top left outer
new MM.Coordinate(1,Infinity,0).zoomTo(18) // bottom right inner
];
// eyes towards null island
this.coordinate = new MM.Coordinate(0.5, 0.5, 0);
// if you don't specify dimensions we assume you want to fill the parent
// unless the parent has no w/h, in which case we'll still use a default
if (!dimensions) {
dimensions = new MM.Point(
this.parent.offsetWidth,
this.parent.offsetHeight);
dimensions = new MM.Point(this.parent.offsetWidth,
this.parent.offsetHeight);
this.autoSize = true;
// FIXME: listeners like this will stop the map being removed cleanly?
// when does removeEvent get called?
var theMap = this;
// use destroy to get rid of this handler from the DOM
MM.addEvent(window, 'resize', this.windowResize());
}
else {
} else {
this.autoSize = false;
// don't call setSize here because it calls draw()
this.parent.style.width = Math.round(dimensions.x) + 'px';
this.parent.style.height = Math.round(dimensions.y) + 'px';
}
this.dimensions = dimensions;
this.requestManager = new MM.RequestManager(this.parent);
this.requestManager.addCallback('requestcomplete', this.getTileComplete());
this.layers = {};
this.layerParent = document.createElement('div');
this.layerParent.id = this.parent.id + '-layers';
// this text is also used in createOrGetLayer
this.layerParent.style.cssText = 'position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; margin: 0; padding: 0; z-index: 0';
this.parent.appendChild(this.layerParent);
this.coordinate = new MM.Coordinate(0.5, 0.5, 0);
this.setProvider(provider);
this.enablePyramidLoading = false;
this.callbackManager = new MM.CallbackManager(this, [

@@ -88,9 +93,11 @@ 'zoomed',

if (eventHandlers === undefined) {
this.eventHandlers = [];
this.eventHandlers.push(new MM.MouseHandler(this));
this.eventHandlers = [
new MM.MouseHandler(this),
new MM.TouchHandler(this)
];
} else {
this.eventHandlers = eventHandlers;
if (eventHandlers instanceof Array) {
for (var i = 0; i < eventHandlers.length; i++) {
eventHandlers[i].init(this);
for (var j = 0; j < eventHandlers.length; j++) {
eventHandlers[j].init(this);
}

@@ -104,25 +111,19 @@ }

parent: null,
provider: null,
dimensions: null,
coordinate: null,
parent: null, // DOM Element
dimensions: null, // MM.Point with x/y size of parent element
tiles: null,
layers: null,
layerParent: null,
projection: null, // MM.Projection of first known layer
coordinate: null, // Center of map MM.Coordinate with row/column/zoom
tileSize: null, // MM.Point with x/y size of tiles
requestManager: null,
coordLimits: null, // Array of [ topLeftOuter, bottomLeftInner ] MM.Coordinates
tileCacheSize: null,
layers: null, // Array of MM.Layer (interface = .draw(), .destroy(), .parent and .map)
maxTileCacheSize: null,
recentTiles: null,
recentTilesById: null,
recentTileSize: null,
callbackManager: null, // MM.CallbackManager, handles map events
callbackManager: null,
eventHandlers: null,
autoSize: null,
eventHandlers: null, // Array of interaction handlers, just a MM.MouseHandler by default
autoSize: null, // Boolean, true if we have a window resize listener
toString: function() {

@@ -163,2 +164,10 @@ return 'Map(#' + this.parent.id + ')';

// A convenience function to restrict interactive zoom ranges.
// (you should also adjust map provider to restrict which tiles get loaded,
// or modify map.coordLimits and provider.tileLimits for finer control)
setZoomRange: function(minZoom, maxZoom) {
this.coordLimits[0] = this.coordLimits[0].zoomTo(minZoom);
this.coordLimits[1] = this.coordLimits[1].zoomTo(maxZoom);
},
// zooming

@@ -188,4 +197,4 @@ zoomBy: function(zoomOffset) {

panBy: function(dx, dy) {
this.coordinate.column -= dx / this.provider.tileWidth;
this.coordinate.row -= dy / this.provider.tileHeight;
this.coordinate.column -= dx / this.tileSize.x;
this.coordinate.row -= dy / this.tileSize.y;

@@ -202,4 +211,4 @@ this.coordinate = this.enforceLimits(this.coordinate);

panZoom: function(dx, dy, zoom) {
this.coordinate.column -= dx / this.provider.tileWidth;
this.coordinate.row -= dy / this.provider.tileHeight;
this.coordinate.column -= dx / this.tileSize.x;
this.coordinate.row -= dy / this.tileSize.y;
this.coordinate = this.coordinate.zoomTo(zoom);

@@ -225,4 +234,4 @@

setCenterZoom: function(location, zoom) {
this.coordinate = this.provider.locationCoordinate(location).zoomTo(parseFloat(zoom) || 0);
this.draw();
this.coordinate = this.projection.locationCoordinate(location).zoomTo(parseFloat(zoom) || 0);
MM.getFrame(this.getRedraw());
this.dispatchCallback('centered', [location, zoom]);

@@ -232,7 +241,11 @@ return this;

setExtent: function(locations, any) {
setExtent: function(locations, precise) {
// coerce locations to an array if it's a MapExtent instance
if (locations instanceof MM.MapExtent) {
locations = locations.toArray();
}
var TL, BR;
for (var i = 0; i < locations.length; i++) {
var coordinate = this.provider.locationCoordinate(locations[i]);
var coordinate = this.projection.locationCoordinate(locations[i]);
if (TL) {

@@ -256,3 +269,3 @@ TL.row = Math.min(TL.row, coordinate.row);

// multiplication factor between horizontal span and map width
var hFactor = (BR.column - TL.column) / (width / this.provider.tileWidth);
var hFactor = (BR.column - TL.column) / (width / this.tileSize.x);

@@ -263,6 +276,6 @@ // multiplication factor expressed as base-2 logarithm, for zoom difference

// possible horizontal zoom to fit geographical extent in map width
var hPossibleZoom = TL.zoom - (any ? hZoomDiff : Math.ceil(hZoomDiff));
var hPossibleZoom = TL.zoom - (precise ? hZoomDiff : Math.ceil(hZoomDiff));
// multiplication factor between vertical span and map height
var vFactor = (BR.row - TL.row) / (height / this.provider.tileHeight);
var vFactor = (BR.row - TL.row) / (height / this.tileSize.y);

@@ -273,3 +286,3 @@ // multiplication factor expressed as base-2 logarithm, for zoom difference

// possible vertical zoom to fit geographical extent in map height
var vPossibleZoom = TL.zoom - (any ? vZoomDiff : Math.ceil(vZoomDiff));
var vPossibleZoom = TL.zoom - (precise ? vZoomDiff : Math.ceil(vZoomDiff));

@@ -279,6 +292,5 @@ // initial zoom to fit extent vertically and horizontally

// additionally, make sure it's not outside the boundaries set by provider limits
// this also catches Infinity stuff
initZoom = Math.min(initZoom, this.provider.outerLimits()[1].zoom);
initZoom = Math.max(initZoom, this.provider.outerLimits()[0].zoom);
// additionally, make sure it's not outside the boundaries set by map limits
initZoom = Math.min(initZoom, this.coordLimits[1].zoom);
initZoom = Math.max(initZoom, this.coordLimits[0].zoom);

@@ -291,3 +303,3 @@ // coordinate of extent center

this.coordinate = new MM.Coordinate(centerRow, centerColumn, centerZoom).zoomTo(initZoom);
this.draw(); // draw calls enforceLimits
this.draw(); // draw calls enforceLimits
// (if you switch to getFrame, call enforceLimits first)

@@ -301,13 +313,15 @@

// `resized` to make sure that the map's presentation is still correct.
setSize: function(dimensionsOrX, orY) {
if (dimensionsOrX.hasOwnProperty('x') && dimensionsOrX.hasOwnProperty('y')) {
this.dimensions = dimensionsOrX;
}
else if (orY !== undefined && !isNaN(orY)) {
this.dimensions = new MM.Point(dimensionsOrX, orY);
}
setSize: function(dimensions) {
// Ensure that, whether a raw object or a Point object is passed,
// this.dimensions will be a Point.
this.dimensions = new MM.Point(dimensions.x, dimensions.y);
this.parent.style.width = Math.round(this.dimensions.x) + 'px';
this.parent.style.height = Math.round(this.dimensions.y) + 'px';
this.draw();
this.dispatchCallback('resized', [this.dimensions]);
if (this.autoSize) {
MM.removeEvent(window, 'resize', this.windowResize());
this.autoSize = false;
}
this.draw(); // draw calls enforceLimits
// (if you switch to getFrame, call enforceLimits first)
this.dispatchCallback('resized', this.dimensions);
return this;

@@ -325,4 +339,4 @@ },

var point = new MM.Point(this.dimensions.x / 2, this.dimensions.y / 2);
point.x += this.provider.tileWidth * (coord.column - this.coordinate.column);
point.y += this.provider.tileHeight * (coord.row - this.coordinate.row);
point.x += this.tileSize.x * (coord.column - this.coordinate.column);
point.y += this.tileSize.y * (coord.row - this.coordinate.row);

@@ -337,4 +351,4 @@ return point;

var coord = this.coordinate.copy();
coord.column += (point.x - this.dimensions.x / 2) / this.provider.tileWidth;
coord.row += (point.y - this.dimensions.y / 2) / this.provider.tileHeight;
coord.column += (point.x - this.dimensions.x / 2) / this.tileSize.x;
coord.row += (point.y - this.dimensions.y / 2) / this.tileSize.y;

@@ -344,5 +358,15 @@ return coord;

// Return an MM.Coordinate (row,col,zoom) for an MM.Location (lat,lon).
locationCoordinate: function(location) {
return this.projection.locationCoordinate(location);
},
// Return an MM.Location (lat,lon) for an MM.Coordinate (row,col,zoom).
coordinateLocation: function(coordinate) {
return this.projection.coordinateLocation(coordinate);
},
// Return an x, y point on the map image for a given geographical location.
locationPoint: function(location) {
return this.coordinatePoint(this.provider.locationCoordinate(location));
return this.coordinatePoint(this.locationCoordinate(location));
},

@@ -352,7 +376,6 @@

pointLocation: function(point) {
return this.provider.coordinateLocation(this.pointCoordinate(point));
return this.coordinateLocation(this.pointCoordinate(point));
},
// inspecting
getExtent: function() {

@@ -365,7 +388,23 @@ var extent = [];

extent: function(locations, precise) {
if (locations) {
return this.setExtent(locations, precise);
} else {
return this.getExtent();
}
},
// Get the current centerpoint of the map, returning a `Location`
getCenter: function() {
return this.provider.coordinateLocation(this.coordinate);
return this.projection.coordinateLocation(this.coordinate);
},
center: function(location) {
if (location) {
return this.setCenter(location);
} else {
return this.getCenter();
}
},
// Get the current zoom level of the map, returning a number

@@ -376,333 +415,254 @@ getZoom: function() {

// Replace the existing provider or set a provider on the map, clearing
// out existing tiles and requests.
setProvider: function(newProvider) {
zoom: function(zoom) {
if (zoom !== undefined) {
return this.setZoom(zoom);
} else {
return this.getZoom();
}
},
var firstProvider = false;
if (this.provider === null) {
firstProvider = true;
// layers
// HACK for 0.x.y - stare at @RandomEtc
// this method means we can also pass a URL template or a MapProvider to addLayer
coerceLayer: function(layerish) {
if ('draw' in layerish && typeof layerish.draw == 'function') {
// good enough, though we should probably enforce .parent and .destroy() too
return layerish;
} else if (typeof layerish == 'string') {
// probably a template string
return new MM.Layer(new MM.TemplatedMapProvider(layerish));
} else {
// probably a MapProvider
return new MM.Layer(layerish);
}
},
// if we already have a provider the we'll need to
// clear the DOM, cancel requests and redraw
if (!firstProvider) {
// return a copy of the layers array
getLayers: function() {
return this.layers.slice();
},
this.requestManager.clear();
// return the layer at the given index
getLayerAt: function(index) {
return this.layers[index];
},
for (var name in this.layers) {
if (this.layers.hasOwnProperty(name)) {
var layer = this.layers[name];
while (layer.firstChild) {
layer.removeChild(layer.firstChild);
}
}
// put the given layer on top of all the others
addLayer: function(layer) {
layer = this.coerceLayer(layer);
this.layers.push(layer);
// make sure layer.parent doesn't already have a parentNode
if (!layer.parent.parentNode) {
this.parent.appendChild(layer.parent);
}
layer.map = this; // TODO: remove map property from MM.Layer?
return this;
},
// find the given layer and remove it
removeLayer: function(layer) {
for (var i = 0; i < this.layers.length; i++) {
if (layer == this.layers[i]) {
this.removeLayerAt(i);
break;
}
}
return this;
},
// first provider or not we'll init/reset some values...
// replace the current layer at the given index with the given layer
setLayerAt: function(index, layer) {
this.tiles = {};
if (index < 0 || index >= this.layers.length) {
throw new Error('invalid index in setLayerAt(): ' + index);
}
this.tileCacheSize = 0;
layer = this.coerceLayer(layer);
this.maxTileCacheSize = 64;
this.recentTiles = [];
this.recentTilesById = {};
if (this.layers[index] != layer) {
// for later: check geometry of old provider and set a new coordinate center
// if needed (now? or when?)
// clear existing layer at this index
if (index < this.layers.length) {
this.layers[index].destroy();
}
this.provider = newProvider;
// pass it on.
this.layers[index] = layer;
this.parent.appendChild(layer.parent);
layer.map = this; // TODO: remove map property from MM.Layer
if (!firstProvider) {
this.draw();
MM.getFrame(this.getRedraw());
}
return this;
},
// stats
// put the given layer at the given index, moving others if necessary
insertLayerAt: function(index, layer) {
/*
getStats: function() {
return {
'Request Queue Length': this.requestManager.requestQueue.length,
'Open Request Count': this.requestManager.requestCount,
'Tile Cache Size': this.tileCacheSize,
'Tiles On Screen': this.parent.getElementsByTagName('img').length
};
},*/
if (index < 0 || index > this.layers.length) {
throw new Error('invalid index in insertLayerAt(): ' + index);
}
// Prevent the user from navigating the map outside the `outerLimits`
// of the map's provider.
enforceLimits: function(coord) {
coord = coord.copy();
var limits = this.provider.outerLimits();
if (limits) {
var minZoom = limits[0].zoom;
var maxZoom = limits[1].zoom;
if (coord.zoom < minZoom) {
coord = coord.zoomTo(minZoom);
}
else if (coord.zoom > maxZoom) {
coord = coord.zoomTo(maxZoom);
}
layer = this.coerceLayer(layer);
if(index == this.layers.length) {
// it just gets tacked on to the end
this.layers.push(layer);
this.parent.appendChild(layer.parent);
} else {
// it needs to get slipped in amongst the others
var other = this.layers[index];
this.parent.insertBefore(layer.parent, other.parent);
this.layers.splice(index, 0, layer);
}
return coord;
},
// Redraw the tiles on the map, reusing existing tiles.
draw: function() {
layer.map = this; // TODO: remove map property from MM.Layer
// make sure we're not too far in or out:
this.coordinate = this.enforceLimits(this.coordinate);
MM.getFrame(this.getRedraw());
// if we're in between zoom levels, we need to choose the nearest:
var baseZoom = Math.round(this.coordinate.zoom);
return this;
},
// if we don't have dimensions, check the parent size
if (this.dimensions.x <= 0 || this.dimensions.y <= 0) {
if (this.autoSize) {
// maybe the parent size has changed?
var w = this.parent.offsetWidth,
h = this.parent.offsetHeight
this.dimensions = new MM.Point(w,h);
if (w <= 0 || h <= 0) {
return;
}
}
else {
// the issue can only be corrected with setSize
return;
}
// remove the layer at the given index, call .destroy() on the layer
removeLayerAt: function(index) {
if (index < 0 || index >= this.layers.length) {
throw new Error('invalid index in removeLayer(): ' + index);
}
// these are the top left and bottom right tile coordinates
// we'll be loading everything in between:
var startCoord = this.pointCoordinate(new MM.Point(0, 0)).zoomTo(baseZoom).container();
var endCoord = this.pointCoordinate(this.dimensions).zoomTo(baseZoom).container().right().down();
// gone baby gone.
var old = this.layers[index];
this.layers.splice(index, 1);
old.destroy();
var tilePadding = 0;
if (tilePadding) {
startCoord = startCoord.left(tilePadding).up(tilePadding);
endCoord = endCoord.right(tilePadding).down(tilePadding);
return this;
},
// switch the stacking order of two layers, by index
swapLayersAt: function(i, j) {
if (i < 0 || i >= this.layers.length || j < 0 || j >= this.layers.length) {
throw new Error('invalid index in swapLayersAt(): ' + index);
}
// tiles with invalid keys will be removed from visible layers
// requests for tiles with invalid keys will be canceled
// (this object maps from a tile key to a boolean)
var validTileKeys = { };
var layer1 = this.layers[i],
layer2 = this.layers[j],
dummy = document.createElement('div');
// make sure we have a container for tiles in the current layer
var thisLayer = this.createOrGetLayer(startCoord.zoom);
// kick layer2 out, replace it with the dummy.
this.parent.replaceChild(dummy, layer2.parent);
// use this coordinate for generating keys, parents and children:
var tileCoord = startCoord.copy();
// put layer2 back in and kick layer1 out
this.parent.replaceChild(layer2.parent, layer1.parent);
for (tileCoord.column = startCoord.column;
tileCoord.column <= endCoord.column;
tileCoord.column += 1) {
for (tileCoord.row = startCoord.row;
tileCoord.row <= endCoord.row;
tileCoord.row += 1) {
var tileKey = tileCoord.toKey();
validTileKeys[tileKey] = true;
if (tileKey in this.tiles) {
var tile = this.tiles[tileKey];
// ensure it's in the DOM:
if (tile.parentNode != thisLayer) {
thisLayer.appendChild(tile);
}
} else {
if (!this.requestManager.hasRequest(tileKey)) {
var tileURL = this.provider.getTileUrl(tileCoord);
this.requestManager.requestTile(tileKey, tileCoord, tileURL);
}
// look for a parent tile in our image cache
var tileCovered = false;
var maxStepsOut = tileCoord.zoom;
for (var pz = 1; pz <= maxStepsOut; pz++) {
var parentCoord = tileCoord.zoomBy(-pz).container();
var parentKey = parentCoord.toKey();
// put layer1 back in and ditch the dummy
this.parent.replaceChild(layer1.parent, dummy);
if (this.enablePyramidLoading) {
// mark all parent tiles valid
validTileKeys[parentKey] = true;
var parentLayer = this.createOrGetLayer(parentCoord.zoom);
/* parentLayer.coordinate = parentCoord.copy(); */
if (parentKey in this.tiles) {
var parentTile = this.tiles[parentKey];
if (parentTile.parentNode != parentLayer) {
parentLayer.appendChild(parentTile);
}
} else if (!this.requestManager.hasRequest(parentKey)) {
// force load of parent tiles we don't already have
this.requestManager.requestTile(parentKey, parentCoord,
this.provider.getTileUrl(parentCoord));
}
} else {
// only mark it valid if we have it already
if (parentKey in this.tiles) {
validTileKeys[parentKey] = true;
tileCovered = true;
break;
}
}
// now do it to the layers array
this.layers[i] = layer2;
this.layers[j] = layer1;
}
// if we didn't find a parent, look at the children:
if (!tileCovered && !this.enablePyramidLoading) {
var childCoord = tileCoord.zoomBy(1);
// mark everything valid whether or not we have it:
validTileKeys[childCoord.toKey()] = true;
childCoord.column += 1;
validTileKeys[childCoord.toKey()] = true;
childCoord.row += 1;
validTileKeys[childCoord.toKey()] = true;
childCoord.column -= 1;
validTileKeys[childCoord.toKey()] = true;
}
}
}
}
return this;
},
// i from i to zoom-5 are layers that would be scaled too big,
// i from zoom+2 to layers.length are layers that would be
// scaled too small (and tiles would be too numerous)
for (var name in this.layers) {
if (this.layers.hasOwnProperty(name)) {
var zoom = parseInt(name, 10);
if (zoom >= startCoord.zoom - 5 && zoom < startCoord.zoom + 2) {
continue;
}
var layer = this.layers[name];
layer.style.display = 'none';
var visibleTiles = layer.getElementsByTagName('img');
for (var j = visibleTiles.length - 1; j >= 0; j--) {
layer.removeChild(visibleTiles[j]);
}
// limits
enforceZoomLimits: function(coord) {
var limits = this.coordLimits;
if (limits) {
// clamp zoom level:
var minZoom = limits[0].zoom;
var maxZoom = limits[1].zoom;
if (coord.zoom < minZoom) {
coord = coord.zoomTo(minZoom);
}
else if (coord.zoom > maxZoom) {
coord = coord.zoomTo(maxZoom);
}
}
return coord;
},
// for tracking time of tile usage:
var now = new Date().getTime();
enforcePanLimits: function(coord) {
// layers we want to see, if they have tiles in validTileKeys
var minLayer = startCoord.zoom - 5;
var maxLayer = startCoord.zoom + 2;
for (var i = minLayer; i < maxLayer; i++) {
var limits = this.coordLimits;
var layer = this.layers[i];
if (limits) {
if (!layer) {
// no tiles for this layer yet
continue;
}
coord = coord.copy();
// getElementsByTagName is x10 faster than childNodes, and
// let's reuse the access.
var scale = 1,
theCoord = this.coordinate.copy(),
visibleTiles = layer.getElementsByTagName('img');
// clamp pan:
var topLeftLimit = limits[0].zoomTo(coord.zoom);
var bottomRightLimit = limits[1].zoomTo(coord.zoom);
var currentTopLeft = this.pointCoordinate(new MM.Point(0,0));
var currentBottomRight = this.pointCoordinate(this.dimensions);
if (visibleTiles.length > 0) {
layer.style.display = 'block';
scale = Math.pow(2, this.coordinate.zoom - i);
theCoord = theCoord.zoomTo(i);
} else {
layer.style.display = 'none';
// this handles infinite limits:
// (Infinity - Infinity) is Nan
// NaN is never less than anything
if (bottomRightLimit.row - topLeftLimit.row < currentBottomRight.row - currentTopLeft.row) {
// if the limit is smaller than the current view center it
coord.row = (bottomRightLimit.row + topLeftLimit.row) / 2;
}
var tileWidth = this.provider.tileWidth * scale,
tileHeight = this.provider.tileHeight * scale,
center = new MM.Point(this.dimensions.x / 2, this.dimensions.y / 2);
for (var j = visibleTiles.length - 1; j >= 0; j--) {
var tile = visibleTiles[j];
if (!validTileKeys[tile.id]) {
layer.removeChild(tile);
} else {
// position tiles
MM.moveElement(tile, {
x: Math.round(center.x +
(tile.coord.column - theCoord.column) * tileWidth),
y: Math.round(center.y +
(tile.coord.row - theCoord.row) * tileHeight),
scale: scale,
width: this.provider.tileWidth,
height: this.provider.tileHeight
});
// log last-touched-time of currently cached tiles
this.recentTilesById[tile.id].lastTouchedTime = now;
else {
if (currentTopLeft.row < topLeftLimit.row) {
coord.row += topLeftLimit.row - currentTopLeft.row;
}
else if (currentBottomRight.row > bottomRightLimit.row) {
coord.row -= currentBottomRight.row - bottomRightLimit.row;
}
}
if (bottomRightLimit.column - topLeftLimit.column < currentBottomRight.column - currentTopLeft.column) {
// if the limit is smaller than the current view, center it
coord.column = (bottomRightLimit.column + topLeftLimit.column) / 2;
}
else {
if (currentTopLeft.column < topLeftLimit.column) {
coord.column += topLeftLimit.column - currentTopLeft.column;
}
else if (currentBottomRight.column > bottomRightLimit.column) {
coord.column -= currentBottomRight.column - bottomRightLimit.column;
}
}
}
// cancel requests that aren't visible:
this.requestManager.clearExcept(validTileKeys);
return coord;
},
// get newly requested tiles, sort according to current view:
this.requestManager.processQueue(this.getCenterDistanceCompare());
// make sure we don't have too much stuff:
this.checkCache();
this.dispatchCallback('drawn');
// Prevent accidentally navigating outside the `coordLimits` of the map.
enforceLimits: function(coord) {
return this.enforcePanLimits(this.enforceZoomLimits(coord));
},
_tileComplete: null,
// rendering
getTileComplete: function() {
if (!this._tileComplete) {
var theMap = this;
this._tileComplete = function(manager, tile) {
// Redraw the tiles on the map, reusing existing tiles.
draw: function() {
// make sure we're not too far in or out:
this.coordinate = this.enforceLimits(this.coordinate);
// cache the tile itself:
theMap.tiles[tile.id] = tile;
theMap.tileCacheSize++;
// also keep a record of when we last touched this tile:
var record = {
id: tile.id,
lastTouchedTime: new Date().getTime()
};
theMap.recentTilesById[tile.id] = record;
theMap.recentTiles.push(record);
var theCoord = theMap.coordinate.zoomTo(tile.coord.zoom);
var scale = Math.pow(2, theMap.coordinate.zoom - tile.coord.zoom);
var tx = ((theMap.dimensions.x / 2) +
(tile.coord.column - theCoord.column) * theMap.provider.tileWidth * scale);
var ty = ((theMap.dimensions.y / 2) +
(tile.coord.row - theCoord.row) * theMap.provider.tileHeight * scale);
MM.moveElement(tile, {
x: Math.round(tx),
y: Math.round(ty),
scale: scale,
// TODO: pass only scale or only w/h
width: theMap.provider.tileWidth,
height: theMap.provider.tileHeight
});
// Support style transition if available.
// add tile to its layer
var theLayer = theMap.layers[tile.coord.zoom];
theLayer.appendChild(tile);
tile.className = 'map-tile-loaded';
// ensure the layer is visible if it's still the current layer
if (Math.round(theMap.coordinate.zoom) === tile.coord.zoom) {
theLayer.style.display = 'block';
// if we don't have dimensions, check the parent size
if (this.dimensions.x <= 0 || this.dimensions.y <= 0) {
if (this.autoSize) {
// maybe the parent size has changed?
var w = this.parent.offsetWidth,
h = this.parent.offsetHeight;
this.dimensions = new MM.Point(w,h);
if (w <= 0 || h <= 0) {
return;
}
} else {
// the issue can only be corrected with setSize
return;
}
}
// request a lazy redraw of all layers
// this will remove tiles that were only visible
// to cover this tile while it loaded:
theMap.requestRedraw();
};
// draw layers one by one
for(var i = 0; i < this.layers.length; i++) {
this.layers[i].draw();
}
return this._tileComplete;
this.dispatchCallback('drawn');
},
_redrawTimer: undefined,

@@ -735,83 +695,17 @@

createOrGetLayer: function(zoom) {
if (zoom in this.layers) {
return this.layers[zoom];
}
//console.log('creating layer ' + zoom);
var layer = document.createElement('div');
layer.id = this.parent.id + '-zoom-' + zoom;
layer.style.cssText = this.layerParent.style.cssText;
layer.style.zIndex = zoom;
this.layerParent.appendChild(layer);
this.layers[zoom] = layer;
return layer;
},
// keeps cache below max size
// (called every time we receive a new tile and add it to the cache)
checkCache: function() {
var numTilesOnScreen = this.parent.getElementsByTagName('img').length;
var maxTiles = Math.max(numTilesOnScreen, this.maxTileCacheSize);
if (this.tileCacheSize > maxTiles) {
// sort from newest (highest) to oldest (lowest)
this.recentTiles.sort(function(t1, t2) {
return t2.lastTouchedTime < t1.lastTouchedTime ?
-1 :
t2.lastTouchedTime > t1.lastTouchedTime ? 1 : 0;
});
}
while (this.tileCacheSize > maxTiles) {
// delete the oldest record
var tileRecord = this.recentTiles.pop();
var now = new Date().getTime();
delete this.recentTilesById[tileRecord.id];
/*window.console.log('removing ' + tileRecord.id +
' last seen ' + (now-tileRecord.lastTouchedTime) + 'ms ago'); */
// now actually remove it from the cache...
var tile = this.tiles[tileRecord.id];
if (tile.parentNode) {
// I'm leaving this uncommented for now but you should never see it:
alert("Gah: trying to removing cached tile even though it's still in the DOM");
} else {
delete this.tiles[tileRecord.id];
this.tileCacheSize--;
}
}
},
// Compares manhattan distance from center of
// requested tiles to current map center
// NB:- requested tiles are *popped* from queue, so we do a descending sort
getCenterDistanceCompare: function() {
var theCoord = this.coordinate.zoomTo(Math.round(this.coordinate.zoom));
return function(r1, r2) {
if (r1 && r2) {
var c1 = r1.coord;
var c2 = r2.coord;
if (c1.zoom == c2.zoom) {
var ds1 = Math.abs(theCoord.row - c1.row - 0.5) +
Math.abs(theCoord.column - c1.column - 0.5);
var ds2 = Math.abs(theCoord.row - c2.row - 0.5) +
Math.abs(theCoord.column - c2.column - 0.5);
return ds1 < ds2 ? 1 : ds1 > ds2 ? -1 : 0;
}
else {
return c1.zoom < c2.zoom ? 1 : c1.zoom > c2.zoom ? -1 : 0;
}
}
return r1 ? 1 : r2 ? -1 : 0;
};
},
// Attempts to destroy all attachment a map has to a page
// and clear its memory usage.
destroy: function() {
this.requestManager.clear();
for (var j = 0; j < this.layers.length; j++) {
this.layers[j].destroy();
}
this.layers = [];
this.projection = null;
for (var i = 0; i < this.eventHandlers.length; i++) {
this.eventHandlers[i].remove();
}
this.parent.removeChild(this.layerParent);
MM.removeEvent(window, 'resize', this.windowResize());
return this;
if (this.autoSize) {
MM.removeEvent(window, 'resize', this.windowResize());
}
}
};

@@ -24,7 +24,14 @@ // Event Handlers

// when page would scroll up, and out when the page would scroll down.
MM.MouseWheelHandler = function(map) {
if (map !== undefined) this.init(map);
MM.MouseWheelHandler = function(map, precise) {
// only init() if we get a map
if (map) {
this.init(map, precise);
// allow (null, true) as constructor args
} else if (arguments.length > 1) {
this.precise = precise ? true : false;
}
};
MM.MouseWheelHandler.prototype = {
precise: false,

@@ -34,2 +41,7 @@ init: function(map) {

this._mouseWheel = MM.bind(this.mouseWheel, this);
this._zoomDiv = document.body.appendChild(document.createElement('div'));
this._zoomDiv.style.cssText = 'visibility:hidden;top:0;height:0;width:0;overflow-y:scroll';
var innerDiv = this._zoomDiv.appendChild(document.createElement('div'));
innerDiv.style.height = '2000px';
MM.addEvent(map.parent, 'mousewheel', this._mouseWheel);

@@ -40,2 +52,3 @@ },

MM.removeEvent(this.map.parent, 'mousewheel', this._mouseWheel);
this._zoomDiv.parentNode.removeChild(this._zoomDiv);
},

@@ -47,6 +60,8 @@

if (e.wheelDelta) {
delta = e.wheelDelta;
} else if (e.detail) {
delta = -e.detail;
try {
this._zoomDiv.scrollTop = 1000;
this._zoomDiv.dispatchEvent(e);
delta = 1000 - this._zoomDiv.scrollTop;
} catch (error) {
delta = e.wheelDelta || (-e.detail * 5);
}

@@ -57,3 +72,3 @@

if (Math.abs(delta) > 0 && (timeSince > 200)) {
if (Math.abs(delta) > 0 && (timeSince > 200) && !this.precise) {
var point = MM.getMousePoint(e, this.map);

@@ -63,2 +78,5 @@ this.map.zoomByAbout(delta > 0 ? 1 : -1, point);

this.prevTime = new Date().getTime();
} else if (this.precise) {
var point = MM.getMousePoint(e, this.map);
this.map.zoomByAbout(delta * 0.001, point);
}

@@ -65,0 +83,0 @@

@@ -12,2 +12,5 @@ // Point

return "(" + this.x.toFixed(3) + ", " + this.y.toFixed(3) + ")";
},
copy: function() {
return new MM.Point(this.x, this.y);
}

@@ -14,0 +17,0 @@ };

@@ -1,8 +0,11 @@

// Providers
// ---------
// Providers provide tile URLs and possibly elements for layers.
MM.MapProvider = function(getTileUrl) {
if (getTileUrl) {
this.getTileUrl = getTileUrl;
//
// MapProvider ->
// TemplatedMapProvider
//
MM.MapProvider = function(getTile) {
if (getTile) {
this.getTile = getTile;
}

@@ -12,44 +15,35 @@ };

MM.MapProvider.prototype = {
// defaults to Google-y Mercator style maps
projection: new MM.MercatorProjection( 0,
MM.deriveTransformation(-Math.PI, Math.PI, 0, 0,
Math.PI, Math.PI, 1, 0,
-Math.PI, -Math.PI, 0, 1) ),
tileWidth: 256,
tileHeight: 256,
// these are limits for available *tiles*
// panning limits will be different (since you can wrap around columns)
// but if you put Infinity in here it will screw up sourceCoordinate
topLeftOuterLimit: new MM.Coordinate(0,0,0),
bottomRightInnerLimit: new MM.Coordinate(1,1,0).zoomTo(18),
tileLimits: [ new MM.Coordinate(0,0,0), // top left outer
new MM.Coordinate(1,1,0).zoomTo(18) ], // bottom right inner
getTileUrl: function(coordinate) {
throw "Abstract method not implemented by subclass.";
},
locationCoordinate: function(location) {
return this.projection.locationCoordinate(location);
getTile: function(coordinate) {
throw "Abstract method not implemented by subclass.";
},
coordinateLocation: function(coordinate) {
return this.projection.coordinateLocation(coordinate);
releaseTile: function(element) {
// releaseTile is not required
},
outerLimits: function() {
return [ this.topLeftOuterLimit.copy(),
this.bottomRightInnerLimit.copy() ];
},
// use this to tell MapProvider that tiles only exist between certain zoom levels.
// Map will respect thse zoom limits and not allow zooming outside this range
// use this to tell MapProvider that tiles only exist between certain zoom levels.
// should be set separately on Map to restrict interactive zoom/pan ranges
setZoomRange: function(minZoom, maxZoom) {
this.topLeftOuterLimit = this.topLeftOuterLimit.zoomTo(minZoom);
this.bottomRightInnerLimit = this.bottomRightInnerLimit.zoomTo(maxZoom);
this.tileLimits[0] = this.tileLimits[0].zoomTo(minZoom);
this.tileLimits[1] = this.tileLimits[1].zoomTo(maxZoom);
},
// return null if coord is above/below row extents
// wrap column around the world if it's outside column extents
// ... you should override this function if you change the tile limits
// ... see enforce-limits in examples for details
sourceCoordinate: function(coord) {
var TL = this.topLeftOuterLimit.zoomTo(coord.zoom);
var BR = this.bottomRightInnerLimit.zoomTo(coord.zoom);
var TL = this.tileLimits[0].zoomTo(coord.zoom);
var BR = this.tileLimits[1].zoomTo(coord.zoom);
var vSize = BR.row - TL.row;

@@ -70,20 +64,82 @@ if (coord.row < 0 | coord.row >= vSize) {

// A simple tileprovider builder that supports `XYZ`-style tiles.
/**
* FIXME: need a better explanation here! This is a pretty crucial part of
* understanding how to use ModestMaps.
*
* TemplatedMapProvider is a tile provider that generates tile URLs from a
* template string by replacing the following bits for each tile
* coordinate:
*
* {Z}: the tile's zoom level (from 1 to ~20)
* {X}: the tile's X, or column (from 0 to a very large number at higher
* zooms)
* {Y}: the tile's Y, or row (from 0 to a very large number at higher
* zooms)
*
* E.g.:
*
* var osm = new MM.TemplatedMapProvider("http://tile.openstreetmap.org/{Z}/{X}/{Y}.png");
*
* Or:
*
* var placeholder = new MM.TemplatedMapProvider("http://placehold.it/256/f0f/fff.png&text={Z}/{X}/{Y}");
*
*/
MM.TemplatedMapProvider = function(template, subdomains) {
MM.MapProvider.call(this, function(coordinate) {
coordinate = this.sourceCoordinate(coordinate);
if (!coordinate) {
var isQuadKey = false;
if (template.match(/{(Q|quadkey)}/)) {
isQuadKey = true;
// replace Microsoft style substitution strings
template = template
.replace('{subdomains}', '{S}')
.replace('{zoom}', '{Z}')
.replace('{quadkey}', '{Q}');
}
var hasSubdomains = (subdomains &&
subdomains.length && template.indexOf("{S}") >= 0);
var getTileUrl = function(coordinate) {
var coord = this.sourceCoordinate(coordinate);
if (!coord) {
return null;
}
var base = template;
if (subdomains && subdomains.length && base.indexOf("{S}") >= 0) {
var subdomain = parseInt(coordinate.zoom + coordinate.row + coordinate.column, 10) % subdomains.length;
base = base.replace('{S}', subdomains[subdomain]);
if (hasSubdomains) {
var index = parseInt(coord.zoom + coord.row + coord.column, 10) %
subdomains.length;
base = base.replace('{S}', subdomains[index]);
}
return base.replace('{Z}', coordinate.zoom.toFixed(0))
.replace('{X}', coordinate.column.toFixed(0))
.replace('{Y}', coordinate.row.toFixed(0));
});
if (isQuadKey) {
return base
.replace('{Z}', coord.zoom.toFixed(0))
.replace('{Q}', this.quadKey(coord.row,
coord.column,
coord.zoom));
} else {
return base
.replace('{Z}', coord.zoom.toFixed(0))
.replace('{X}', coord.column.toFixed(0))
.replace('{Y}', coord.row.toFixed(0));
}
};
MM.MapProvider.call(this, getTileUrl);
};
MM.TemplatedMapProvider.prototype = {
// quadKey generator
quadKey: function(row, column, zoom) {
var key = '';
for (var i = 1; i <= zoom; i++) {
key += (((row >> zoom - i) & 1) << 1) | ((column >> zoom - i) & 1);
}
return key || '0';
},
getTile: function(coord) {
return this.getTileUrl(coord);
},
releaseTile: function() { }
};
MM.extend(MM.TemplatedMapProvider, MM.MapProvider);

@@ -17,3 +17,4 @@ // RequestManager

this.callbackManager = new MM.CallbackManager(this, ['requestcomplete']);
this.callbackManager = new MM.CallbackManager(this, [
'requestcomplete', 'requesterror']);
};

@@ -59,6 +60,19 @@

// Clear everything in the queue except for certain ids, speciied
clearRequest: function(id) {
if(id in this.requestsById) {
delete this.requestsById[id];
}
for(var i = 0; i < this.requestQueue.length; i++) {
var request = this.requestQueue[i];
if(request && request.id == id) {
this.requestQueue[i] = null;
}
}
},
// Clear everything in the queue except for certain keys, specified
// by an object of the form
//
// { id: throwawayvalue }
// { key: throwawayvalue }
clearExcept: function(validIds) {

@@ -126,2 +140,3 @@

},
getProcessQueue: function() {

@@ -137,2 +152,3 @@ // let's only create this closure once...

},
// Select images from the `requestQueue` and create image elements for

@@ -217,2 +233,3 @@ // them, attaching their load events to the function returned by

// in requestsById - is that right?
theManager.dispatchCallback('requesterror', img.src);
img.src = null;

@@ -219,0 +236,0 @@ }

/*!
* Modest Maps JS v0.21.0
* Modest Maps JS v1.0.0-alpha
* http://modestmaps.com/

@@ -12,13 +12,20 @@ *

* See CHANGELOG and http://semver.org/ for more details.
*
*
*/
// namespacing!
var previousMM = MM;
// namespacing for backwards-compatibility
if (!com) {
var com = { };
if (!com.modestmaps) {
com.modestmaps = {};
}
var com = {};
if (!com.modestmaps) com.modestmaps = {};
}
var MM = com.modestmaps = {
noConflict: function() {
MM = previousMM;
return this;
}
};
(function(MM) {

@@ -1,2 +0,6 @@

MM.TouchHandler = function() { };
MM.TouchHandler = function(map, options) {
if (map) {
this.init(map, options);
}
};

@@ -17,2 +21,5 @@ MM.TouchHandler.prototype = {

// Fail early if this isn't a touch device.
if (!this.isTouchable()) return false;
this._touchStartMachine = MM.bind(this.touchStartMachine, this);

@@ -32,3 +39,12 @@ this._touchMoveMachine = MM.bind(this.touchMoveMachine, this);

isTouchable: function() {
var el = document.createElement('div');
el.setAttribute('ongesturestart', 'return;');
return (typeof el.ongesturestart === 'function');
},
remove: function() {
// Fail early if this isn't a touch device.
if (!this.isTouchable()) return false;
MM.removeEvent(this.map.parent, 'touchstart',

@@ -35,0 +51,0 @@ this._touchStartMachine);

@@ -108,17 +108,2 @@ // Make inheritance bearable: clone one level of properties

// see http://ejohn.org/apps/jselect/event.html for the originals
MM.addEvent = function(obj, type, fn) {
if (obj.attachEvent) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){ obj['e'+type+fn](window.event); };
obj.attachEvent('on'+type, obj[type+fn]);
}
else {
obj.addEventListener(type, fn, false);
if (type == 'mousewheel') {
obj.addEventListener('DOMMouseScroll', fn, false);
}
}
};
// From underscore.js

@@ -137,8 +122,18 @@ MM.bind = function(func, obj) {

// see http://ejohn.org/apps/jselect/event.html for the originals
MM.addEvent = function(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
if (type == 'mousewheel') {
obj.addEventListener('DOMMouseScroll', fn, false);
}
} else if (obj.attachEvent) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){ obj['e'+type+fn](window.event); };
obj.attachEvent('on'+type, obj[type+fn]);
}
};
MM.removeEvent = function( obj, type, fn ) {
if ( obj.detachEvent ) {
obj.detachEvent('on'+type, obj[type+fn]);
obj[type+fn] = null;
}
else {
if (obj.removeEventListener) {
obj.removeEventListener(type, fn, false);

@@ -148,2 +143,5 @@ if (type == 'mousewheel') {

}
} else if (obj.detachEvent) {
obj.detachEvent('on'+type, obj[type+fn]);
obj[type+fn] = null;
}

@@ -150,0 +148,0 @@ };

describe('DoubleClickHandler', function() {
var map, mm = com.modestmaps;
var map;

@@ -12,8 +12,8 @@ beforeEach(function() {

var subdomains = [ '', 'a.', 'b.', 'c.' ];
var provider = new com.modestmaps.TemplatedMapProvider(template, subdomains);
var provider = new MM.TemplatedMapProvider(template, subdomains);
map = new com.modestmaps.Map(div, provider, [
new mm.DoubleClickHandler()
map = new MM.Map(div, provider, [
new MM.DoubleClickHandler()
]);
map.setCenterZoom(new com.modestmaps.Location(0, 0), 0);
map.setCenterZoom(new MM.Location(0, 0), 0);
});

@@ -20,0 +20,0 @@

describe('DragHandler', function() {
var map, mm = com.modestmaps;
var map;

@@ -12,8 +12,8 @@ beforeEach(function() {

var subdomains = [ '', 'a.', 'b.', 'c.' ];
var provider = new com.modestmaps.TemplatedMapProvider(template, subdomains);
var provider = new MM.TemplatedMapProvider(template, subdomains);
map = new com.modestmaps.Map(div, provider, [
new mm.DragHandler()
map = new MM.Map(div, provider, [
new MM.DragHandler()
]);
map.setCenterZoom(new com.modestmaps.Location(0, 0), 0);
map.setCenterZoom(new MM.Location(0, 0), 0);
});

@@ -20,0 +20,0 @@

@@ -16,6 +16,6 @@ describe('Map', function() {

var subdomains = [ '', 'a.', 'b.', 'c.' ];
var provider = new com.modestmaps.TemplatedMapProvider(template, subdomains);
var provider = new MM.TemplatedMapProvider(template, subdomains);
map = new com.modestmaps.Map(div, provider, new com.modestmaps.Point(400, 400));
map.setCenterZoom(new com.modestmaps.Location(0, 0), 0);
map = new MM.Map(div, provider, new MM.Point(400, 400));
map.setCenterZoom(new MM.Location(0, 0), 0);
});

@@ -37,48 +37,108 @@

it('binds and calls drawn', function() {
spyOn(sink, 'receive');
map.addCallback('drawn', sink.receive);
describe('Navigation', function() {
it('binds and calls drawn', function() {
spyOn(sink, 'receive');
map.addCallback('drawn', sink.receive);
runs(function() {
map.draw();
runs(function() {
map.draw();
});
waits(500);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, undefined);
});
});
waits(500);
it('binds and calls zoomed', function() {
spyOn(sink, 'receive');
map.addCallback('zoomed', sink.receive);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, undefined);
runs(function() {
map.zoomIn();
});
waits(500);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, 1);
});
});
it('binds and calls panned', function() {
spyOn(sink, 'receive');
map.addCallback('panned', sink.receive);
runs(function() {
map.panBy(2, 2);
});
waits(500);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, [2, 2]);
});
});
});
it('binds and calls zoomed', function() {
spyOn(sink, 'receive');
map.addCallback('zoomed', sink.receive);
describe('Layer Interface', function() {
it('Can set a new layer at 0', function() {
var p = new MM.TemplatedMapProvider(
'http://{S}.tile.openstreetmap.org/{Z}/{X}/{Y}.png', ['a']);
var l = new MM.Layer(p);
map.setLayerAt(0, l);
runs(function() {
map.zoomIn();
expect(map.getLayerAt(0)).toEqual(l);
});
it('Can insert a new layer at 0', function() {
var p = new MM.TemplatedMapProvider(
'http://{S}.tile.openstreetmap.org/{Z}/{X}/{Y}.png', ['a']);
var l = new MM.Layer(p);
waits(500);
expect(map.insertLayerAt(0, l)).toEqual(map);
expect(map.getLayerAt(0)).toEqual(l);
expect(map.getLayers().length).toEqual(2);
});
it('Can remove a new layer at 0', function() {
var p = new MM.TemplatedMapProvider(
'http://{S}.tile.openstreetmap.org/{Z}/{X}/{Y}.png', ['a']);
var l = new MM.Layer(p);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, 1);
expect(map.insertLayerAt(0, l)).toEqual(map);
expect(map.getLayerAt(0)).toEqual(l);
expect(map.getLayers().length).toEqual(2);
expect(map.removeLayerAt(0)).toEqual(map);
expect(map.getLayers().length).toEqual(1);
});
});
it('binds and calls panned', function() {
spyOn(sink, 'receive');
map.addCallback('panned', sink.receive);
it('Can swap a new layer at 0', function() {
var p = new MM.TemplatedMapProvider(
'http://{S}.tile.openstreetmap.org/{Z}/{X}/{Y}.png', ['a']);
var l = new MM.Layer(p);
runs(function() {
map.panBy(2, 2);
var l1 = map.getLayerAt(0);
expect(map.insertLayerAt(1, l)).toEqual(map);
expect(map.swapLayersAt(0, 1)).toEqual(map);
expect(map.getLayerAt(0)).toEqual(l);
expect(map.getLayerAt(1)).toEqual(l1);
expect(map.getLayers().length).toEqual(2);
});
waits(500);
it('Can remove a specific layer', function() {
var p = new MM.TemplatedMapProvider(
'http://{S}.tile.openstreetmap.org/{Z}/{X}/{Y}.png', ['a']);
var l = new MM.Layer(p);
runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, [2, 2]);
expect(map.insertLayerAt(1, l)).toEqual(map);
expect(map.removeLayer(l)).toEqual(map);
expect(map.getLayers().length).toEqual(1);
});
});
it('binds and calls resized', function() {

@@ -97,3 +157,3 @@ spyOn(sink, 'receive');

runs(function() {
expect(sink.receive).toHaveBeenCalledWith(map, [{ x: 200, y: 300}]);
expect(sink.receive).toHaveBeenCalledWith(map, { x: 200, y: 300});
});

@@ -104,4 +164,4 @@ });

map.destroy();
expect(map.requestManager.openRequestCount).toEqual(0);
expect(map.layers.length).toEqual(0);
});
});
describe('MouseWheelHandler', function() {
var map, mm = com.modestmaps;
var map;

@@ -12,8 +12,8 @@ beforeEach(function() {

var subdomains = [ '', 'a.', 'b.', 'c.' ];
var provider = new com.modestmaps.TemplatedMapProvider(template, subdomains);
var provider = new MM.TemplatedMapProvider(template, subdomains);
map = new com.modestmaps.Map(div, provider, [
new mm.MouseWheelHandler()
map = new MM.Map(div, provider, [
new MM.MouseWheelHandler()
]);
map.setCenterZoom(new com.modestmaps.Location(0, 0), 0);
map.setCenterZoom(new MM.Location(0, 0), 0);
});

@@ -20,0 +20,0 @@

describe('Point', function() {
var MM = com.modestmaps;
it('creates a point', function() {
var p = new MM.Point(0, 1);
expect(p).toEqual({ x: 0, y: 1 });
expect(p.x).toEqual(0);
expect(p.y).toEqual(1);
});
});
describe('Projection', function() {
var MM = com.modestmaps,
m;
var m;

@@ -13,6 +12,4 @@ beforeEach(function() {

expect(m.locationCoordinate(new MM.Location(0, 0)).zoom).toEqual(10);
expect(m.coordinateLocation(new MM.Coordinate(0, 0, 10))).toEqual({
lon: 0,
lat: 0
});
expect(m.coordinateLocation(new MM.Coordinate(0, 0, 10)))
.toEqual(new MM.Location(0, 0));
});

@@ -19,0 +16,0 @@

describe('Providers', function() {
var MM = com.modestmaps;
// Currently not testing subdomain-based templatedmapprovider, since

@@ -4,0 +3,0 @@ // the implementation should be kind of undefined.

describe('Transformation', function() {
var MM = com.modestmaps;
it('can do an identity transform', function() {

@@ -10,5 +9,5 @@ var t = new MM.Transformation(1, 0, 0, 0, 1, 0);

expect(p).toEqual({ x: 1, y: 1 });
expect(p_).toEqual({ x: 1, y: 1 });
expect(p__).toEqual({ x: 1, y: 1 });
expect(p).toEqual(new MM.Point(1, 1));
expect(p_).toEqual(new MM.Point(1, 1));
expect(p__).toEqual(new MM.Point(1, 1));
});

@@ -23,5 +22,5 @@

expect(p).toEqual({ x: 0, y: 1 });
expect(p_).toEqual({ x: 1, y: 0 });
expect(p__).toEqual({ x: 0, y: 1 });
expect(p).toEqual(new MM.Point(0, 1));
expect(p_).toEqual(new MM.Point(1, 0));
expect(p__).toEqual(new MM.Point(0, 1));
});

@@ -36,6 +35,6 @@

expect(p).toEqual({ x: 0, y: 0 });
expect(p_).toEqual({ x: 1, y: 1 });
expect(p__).toEqual({ x: 0, y: 0 });
expect(p).toEqual(new MM.Point(0, 0));
expect(p_).toEqual(new MM.Point(1, 1));
expect(p__).toEqual(new MM.Point(0, 0));
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet