diff --git a/CHANGELOG b/CHANGELOG index 524ceb2..3d90391 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,10 @@ Following the semantic versioning recommendation best we can: minor version, and backwards incompatible API changes increment the major version." -- http://semver.org/ +v0.14.3 + - improve redraw behavior by ensuring layer is visible in getTileComplete + - use a closure in v0.14.2's setTimeout to ensure proper 'this' + v0.14.2 - add setTimeout to processQueue to avoid stack overflow/recursion bug in IE 7/8 (https://github.com/stamen/modestmaps-js/issues/12) diff --git a/modestmaps.js b/modestmaps.js index 09ae46c..695cab2 100644 --- a/modestmaps.js +++ b/modestmaps.js @@ -1,5 +1,5 @@ /*! - * Modest Maps JS v0.14.2 + * Modest Maps JS v0.14.3 * http://modestmaps.com/ * * Copyright (c) 2010 Stamen Design, All Rights Reserved. @@ -816,6 +816,17 @@ if (!com) { } } }, + + getProcessQueue: function() { + // let's only create this closure once... + if (!this._processQueue) { + var theManager = this; + this._processQueue = function() { + theManager.processQueue(); + } + } + return this._processQueue; + }, processQueue: function(sortFunc) { if (sortFunc && this.requestQueue.length > 8) { @@ -897,7 +908,7 @@ if (!com) { // use setTimeout() to avoid the IE recursion limit, see // http://cappuccino.org/discuss/2010/03/01/internet-explorer-global-variables-and-stack-overflows/ // and https://github.com/stamen/modestmaps-js/issues/12 - setTimeout(theManager.processQueue, 0); + setTimeout(theManager.getProcessQueue(), 0); }; } @@ -1559,17 +1570,6 @@ if (!com) { theMap.recentTilesById[tile.id] = record; theMap.recentTiles.push(record); - // add tile to its layer: - var theLayer = theMap.layers[tile.coord.zoom]; - theLayer.appendChild(tile); - - //if (!theMap.lastTileReceived) { - // theMap.lastTileReceived = new Date().getTime(); - //} - //var t = new Date().getTime(); - //console.log(tile.coord.toString() + ' ' + (t-theMap.lastTileReceived)); - //theMap.lastTileReceived = t; - // position this tile (avoids a full draw() call): var theCoord = theMap.coordinate.zoomTo(tile.coord.zoom); var scale = Math.pow(2, theMap.coordinate.zoom - tile.coord.zoom); @@ -1582,6 +1582,15 @@ if (!com) { tile.style.width = Math.ceil(theMap.provider.tileWidth * scale) + 'px'; tile.style.height = Math.ceil(theMap.provider.tileHeight * scale) + 'px'; + // add tile to its layer + var theLayer = theMap.layers[tile.coord.zoom]; + theLayer.appendChild(tile); + + // 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'; + } + // request a lazy redraw of all layers // this will remove tiles that were only visible // to cover this tile while it loaded: diff --git a/modestmaps.min.js b/modestmaps.min.js index 472f100..a45e085 100644 --- a/modestmaps.min.js +++ b/modestmaps.min.js @@ -1,5 +1,5 @@ /* - * Modest Maps JS v0.14.2 + * Modest Maps JS v0.14.3 * http://modestmaps.com/ * * Copyright (c) 2010 Stamen Design, All Rights Reserved. @@ -11,4 +11,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.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.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){var d=c.currentStyle[b]}else{if(window.getComputedStyle){var d=document.defaultView.getComputedStyle(c,null).getPropertyValue(b)}}return d};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[Math.floor(this.zoom),Math.floor(this.column),Math.floor(this.row)].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){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){alert("Abstract method not implemented by subclass.")},rawUnproject:function(b){alert("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){alert("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()]},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)%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.MouseHandler=function(b){if(b!==undefined){this.init(b)}};a.MouseHandler.prototype={init:function(b){this.map=b;a.addEvent(b.parent,"dblclick",this.getDoubleClick());a.addEvent(b.parent,"mousedown",this.getMouseDown());a.addEvent(b.parent,"mousewheel",this.getMouseWheel())},mouseDownHandler:null,getMouseDown:function(){if(!this.mouseDownHandler){var b=this;this.mouseDownHandler=function(c){a.addEvent(document,"mouseup",b.getMouseUp());a.addEvent(document,"mousemove",b.getMouseMove());b.prevMouse=new a.Point(c.clientX,c.clientY);b.map.parent.style.cursor="move";return a.cancelEvent(c)}}return this.mouseDownHandler},mouseMoveHandler:null,getMouseMove:function(){if(!this.mouseMoveHandler){var b=this;this.mouseMoveHandler=function(c){if(b.prevMouse){b.map.panBy(c.clientX-b.prevMouse.x,c.clientY-b.prevMouse.y);b.prevMouse.x=c.clientX;b.prevMouse.y=c.clientY}return a.cancelEvent(c)}}return this.mouseMoveHandler},mouseUpHandler:null,getMouseUp:function(){if(!this.mouseUpHandler){var b=this;this.mouseUpHandler=function(c){a.removeEvent(document,"mouseup",b.getMouseUp());a.removeEvent(document,"mousemove",b.getMouseMove());b.prevMouse=null;b.map.parent.style.cursor="";return a.cancelEvent(c)}}return this.mouseUpHandler},mouseWheelHandler:null,getMouseWheel:function(){if(!this.mouseWheelHandler){var c=this;var b=new Date().getTime();this.mouseWheelHandler=function(g){var h=0;if(g.wheelDelta){h=g.wheelDelta}else{if(g.detail){h=-g.detail}}var f=new Date().getTime()-b;if(Math.abs(h)>0&&(f>200)){var d=c.getMousePoint(g);c.map.zoomByAbout(h>0?1:-1,d);b=new Date().getTime()}return a.cancelEvent(g)}}return this.mouseWheelHandler},doubleClickHandler:null,getDoubleClick:function(){if(!this.doubleClickHandler){var b=this;this.doubleClickHandler=function(d){var c=b.getMousePoint(d);b.map.zoomByAbout(d.shiftKey?-1:1,c);return a.cancelEvent(d)}}return this.doubleClickHandler},getMousePoint:function(d){var b=new a.Point(d.clientX,d.clientY);b.x+=document.body.scrollLeft+document.documentElement.scrollLeft;b.y+=document.body.scrollTop+document.documentElement.scrollTop;for(var c=this.map.parent;c;c=c.offsetParent){b.x-=c.offsetLeft;b.y-=c.offsetTop}return b}};a.CallbackManager=function(b,d){this.owner=b;this.callbacks={};for(var c=0;c=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 g in this.requestsById){if(this.requestsById.hasOwnProperty(g)){if(!(g in f)){var e=this.requestsById[g];delete this.requestsById[g];if(e!=null){e=e.key=e.coord=e.url=null}}}}},hasRequest:function(b){return(b in this.requestsById)},requestTile:function(c,e,b){if(!(c in this.requestsById)){var d={key:c,coord:e.copy(),url:b};this.requestsById[c]=d;if(b){this.requestQueue.push(d)}}},processQueue:function(d){if(d&&this.requestQueue.length>8){this.requestQueue.sort(d)}while(this.openRequestCount0){var c=this.requestQueue.pop();if(c){this.openRequestCount++;var b=document.createElement("img");b.id=c.key;b.style.position="absolute";b.coord=c.coord;this.loadingBay.appendChild(b);b.onload=b.onerror=this.getLoadComplete();b.src=c.url;c=c.key=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(c.complete||(c.readyState&&c.readyState=="complete")){b.dispatchCallback("requestcomplete",c)}else{c.src=null}setTimeout(b.processQueue,0)}}return this._loadComplete}};a.Map=function(k,j,b,c){if(typeof k=="string"){k=document.getElementById(k)}this.parent=k;this.parent.style.padding="0";this.parent.style.overflow="hidden";var g=a.getStyle(this.parent,"position");if(g!="relative"&&g!="absolute"){this.parent.style.position="relative"}if(!b){var l=this.parent.offsetWidth;var f=this.parent.offsetHeight;if(!l){l=640;this.parent.style.width=l+"px"}if(!f){f=480;this.parent.style.height=f+"px"}b=new a.Point(l,f);var d=this;a.addEvent(window,"resize",function(h){d.dimensions=new a.Point(d.parent.offsetWidth,d.parent.offsetHeight);d.draw();d.dispatchCallback("resized",[d.dimensions])})}else{this.parent.style.width=Math.round(b.x)+"px";this.parent.style.height=Math.round(b.y)+"px"}this.dimensions=b;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(j);this.enablePyramidLoading=false;this.callbackManager=new a.CallbackManager(this,["zoomed","panned","centered","extentset","resized","drawn"]);if(c===undefined){this.eventHandlers=[];this.eventHandlers.push(new a.MouseHandler(this))}else{this.eventHandlers=c;if(c instanceof Array){for(var e=0;eb){e=e.zoomTo(b)}}}return e},draw:function(){this.coordinate=this.enforceLimits(this.coordinate);var o=Math.round(this.coordinate.zoom);var u=this.pointCoordinate(new a.Point(0,0)).zoomTo(o).container();var s=this.pointCoordinate(this.dimensions).zoomTo(o).container().right().down();var k=0;if(k){u=u.left(k).up(k);s=s.right(k).down(k)}var G={};var l=this.createOrGetLayer(u.zoom);var e=u.copy();for(e.column=u.column;e.column<=s.column;e.column+=1){for(e.row=u.row;e.row<=s.row;e.row+=1){var m=e.toKey();G[m]=true;if(m in this.tiles){var J=this.tiles[m];if(J.parentNode!=l){l.appendChild(J)}}else{if(!this.requestManager.hasRequest(m)){var n=this.provider.getTileUrl(e);this.requestManager.requestTile(m,e,n)}var q=false;var F=e.zoom;for(var r=1;r<=F;r++){var t=e.zoomBy(-r).container();var y=t.toKey();if(this.enablePyramidLoading){G[y]=true;var z=this.createOrGetLayer(t.zoom);if(y in this.tiles){var v=this.tiles[y];if(v.parentNode!=z){z.appendChild(v)}}else{if(!this.requestManager.hasRequest(y)){var n=this.provider.getTileUrl(t);this.requestManager.requestTile(y,t,n)}}}else{if(y in this.tiles){G[y]=true;q=true;break}}}if(!q&&!this.enablePyramidLoading){var h=e.zoomBy(1);G[h.toKey()]=true;h.column+=1;G[h.toKey()]=true;h.row+=1;G[h.toKey()]=true;h.column-=1;G[h.toKey()]=true}}}}for(var K in this.layers){if(this.layers.hasOwnProperty(K)){var d=parseInt(K,10);if(d>=u.zoom-5&&d=0;w--){I.removeChild(E[w])}}}var f=new Date().getTime();var A=u.zoom-5;var g=u.zoom+2;for(var x=A;x0){I.style.display="block";H=Math.pow(2,this.coordinate.zoom-x);c=c.zoomTo(x)}else{I.style.display="none"}var b=this.provider.tileWidth*H;var p=this.provider.tileHeight*H;var C=new a.Point(this.dimensions.x/2,this.dimensions.y/2);var E=I.getElementsByTagName("img");for(var w=E.length-1;w>=0;w--){var J=E[w];if(!G[J.id]){I.removeChild(J)}else{var D=C.x+(J.coord.column-c.column)*b;var B=C.y+(J.coord.row-c.row)*p;J.style.left=Math.round(D)+"px";J.style.top=Math.round(B)+"px";J.style.width=Math.ceil(b)+"px";J.style.height=Math.ceil(p)+"px";this.recentTilesById[J.id].lastTouchedTime=f}}}this.requestManager.clearExcept(G);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 i=b.layers[h.coord.zoom];i.appendChild(h);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);h.style.left=Math.round(d)+"px";h.style.top=Math.round(c)+"px";h.style.width=Math.ceil(b.provider.tileWidth*j)+"px";h.style.height=Math.ceil(b.provider.tileHeight*j)+"px";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.lastTouchedTimeh.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 ch?-1:0}else{return g.zoomf.zoom?-1:0}}return e?1:d?-1:0}}}})(com.modestmaps); \ No newline at end of file +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.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.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){var d=c.currentStyle[b]}else{if(window.getComputedStyle){var d=document.defaultView.getComputedStyle(c,null).getPropertyValue(b)}}return d};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[Math.floor(this.zoom),Math.floor(this.column),Math.floor(this.row)].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){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){alert("Abstract method not implemented by subclass.")},rawUnproject:function(b){alert("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){alert("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()]},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)%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.MouseHandler=function(b){if(b!==undefined){this.init(b)}};a.MouseHandler.prototype={init:function(b){this.map=b;a.addEvent(b.parent,"dblclick",this.getDoubleClick());a.addEvent(b.parent,"mousedown",this.getMouseDown());a.addEvent(b.parent,"mousewheel",this.getMouseWheel())},mouseDownHandler:null,getMouseDown:function(){if(!this.mouseDownHandler){var b=this;this.mouseDownHandler=function(c){a.addEvent(document,"mouseup",b.getMouseUp());a.addEvent(document,"mousemove",b.getMouseMove());b.prevMouse=new a.Point(c.clientX,c.clientY);b.map.parent.style.cursor="move";return a.cancelEvent(c)}}return this.mouseDownHandler},mouseMoveHandler:null,getMouseMove:function(){if(!this.mouseMoveHandler){var b=this;this.mouseMoveHandler=function(c){if(b.prevMouse){b.map.panBy(c.clientX-b.prevMouse.x,c.clientY-b.prevMouse.y);b.prevMouse.x=c.clientX;b.prevMouse.y=c.clientY}return a.cancelEvent(c)}}return this.mouseMoveHandler},mouseUpHandler:null,getMouseUp:function(){if(!this.mouseUpHandler){var b=this;this.mouseUpHandler=function(c){a.removeEvent(document,"mouseup",b.getMouseUp());a.removeEvent(document,"mousemove",b.getMouseMove());b.prevMouse=null;b.map.parent.style.cursor="";return a.cancelEvent(c)}}return this.mouseUpHandler},mouseWheelHandler:null,getMouseWheel:function(){if(!this.mouseWheelHandler){var c=this;var b=new Date().getTime();this.mouseWheelHandler=function(g){var h=0;if(g.wheelDelta){h=g.wheelDelta}else{if(g.detail){h=-g.detail}}var f=new Date().getTime()-b;if(Math.abs(h)>0&&(f>200)){var d=c.getMousePoint(g);c.map.zoomByAbout(h>0?1:-1,d);b=new Date().getTime()}return a.cancelEvent(g)}}return this.mouseWheelHandler},doubleClickHandler:null,getDoubleClick:function(){if(!this.doubleClickHandler){var b=this;this.doubleClickHandler=function(d){var c=b.getMousePoint(d);b.map.zoomByAbout(d.shiftKey?-1:1,c);return a.cancelEvent(d)}}return this.doubleClickHandler},getMousePoint:function(d){var b=new a.Point(d.clientX,d.clientY);b.x+=document.body.scrollLeft+document.documentElement.scrollLeft;b.y+=document.body.scrollTop+document.documentElement.scrollTop;for(var c=this.map.parent;c;c=c.offsetParent){b.x-=c.offsetLeft;b.y-=c.offsetTop}return b}};a.CallbackManager=function(b,d){this.owner=b;this.callbacks={};for(var c=0;c=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 g in this.requestsById){if(this.requestsById.hasOwnProperty(g)){if(!(g in f)){var e=this.requestsById[g];delete this.requestsById[g];if(e!=null){e=e.key=e.coord=e.url=null}}}}},hasRequest:function(b){return(b in this.requestsById)},requestTile:function(c,e,b){if(!(c in this.requestsById)){var d={key:c,coord:e.copy(),url:b};this.requestsById[c]=d;if(b){this.requestQueue.push(d)}}},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.openRequestCount0){var c=this.requestQueue.pop();if(c){this.openRequestCount++;var b=document.createElement("img");b.id=c.key;b.style.position="absolute";b.coord=c.coord;this.loadingBay.appendChild(b);b.onload=b.onerror=this.getLoadComplete();b.src=c.url;c=c.key=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(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(k,j,b,c){if(typeof k=="string"){k=document.getElementById(k)}this.parent=k;this.parent.style.padding="0";this.parent.style.overflow="hidden";var g=a.getStyle(this.parent,"position");if(g!="relative"&&g!="absolute"){this.parent.style.position="relative"}if(!b){var l=this.parent.offsetWidth;var f=this.parent.offsetHeight;if(!l){l=640;this.parent.style.width=l+"px"}if(!f){f=480;this.parent.style.height=f+"px"}b=new a.Point(l,f);var d=this;a.addEvent(window,"resize",function(h){d.dimensions=new a.Point(d.parent.offsetWidth,d.parent.offsetHeight);d.draw();d.dispatchCallback("resized",[d.dimensions])})}else{this.parent.style.width=Math.round(b.x)+"px";this.parent.style.height=Math.round(b.y)+"px"}this.dimensions=b;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(j);this.enablePyramidLoading=false;this.callbackManager=new a.CallbackManager(this,["zoomed","panned","centered","extentset","resized","drawn"]);if(c===undefined){this.eventHandlers=[];this.eventHandlers.push(new a.MouseHandler(this))}else{this.eventHandlers=c;if(c instanceof Array){for(var e=0;eb){e=e.zoomTo(b)}}}return e},draw:function(){this.coordinate=this.enforceLimits(this.coordinate);var o=Math.round(this.coordinate.zoom);var u=this.pointCoordinate(new a.Point(0,0)).zoomTo(o).container();var s=this.pointCoordinate(this.dimensions).zoomTo(o).container().right().down();var k=0;if(k){u=u.left(k).up(k);s=s.right(k).down(k)}var G={};var l=this.createOrGetLayer(u.zoom);var e=u.copy();for(e.column=u.column;e.column<=s.column;e.column+=1){for(e.row=u.row;e.row<=s.row;e.row+=1){var m=e.toKey();G[m]=true;if(m in this.tiles){var J=this.tiles[m];if(J.parentNode!=l){l.appendChild(J)}}else{if(!this.requestManager.hasRequest(m)){var n=this.provider.getTileUrl(e);this.requestManager.requestTile(m,e,n)}var q=false;var F=e.zoom;for(var r=1;r<=F;r++){var t=e.zoomBy(-r).container();var y=t.toKey();if(this.enablePyramidLoading){G[y]=true;var z=this.createOrGetLayer(t.zoom);if(y in this.tiles){var v=this.tiles[y];if(v.parentNode!=z){z.appendChild(v)}}else{if(!this.requestManager.hasRequest(y)){var n=this.provider.getTileUrl(t);this.requestManager.requestTile(y,t,n)}}}else{if(y in this.tiles){G[y]=true;q=true;break}}}if(!q&&!this.enablePyramidLoading){var h=e.zoomBy(1);G[h.toKey()]=true;h.column+=1;G[h.toKey()]=true;h.row+=1;G[h.toKey()]=true;h.column-=1;G[h.toKey()]=true}}}}for(var K in this.layers){if(this.layers.hasOwnProperty(K)){var d=parseInt(K,10);if(d>=u.zoom-5&&d=0;w--){I.removeChild(E[w])}}}var f=new Date().getTime();var A=u.zoom-5;var g=u.zoom+2;for(var x=A;x0){I.style.display="block";H=Math.pow(2,this.coordinate.zoom-x);c=c.zoomTo(x)}else{I.style.display="none"}var b=this.provider.tileWidth*H;var p=this.provider.tileHeight*H;var C=new a.Point(this.dimensions.x/2,this.dimensions.y/2);var E=I.getElementsByTagName("img");for(var w=E.length-1;w>=0;w--){var J=E[w];if(!G[J.id]){I.removeChild(J)}else{var D=C.x+(J.coord.column-c.column)*b;var B=C.y+(J.coord.row-c.row)*p;J.style.left=Math.round(D)+"px";J.style.top=Math.round(B)+"px";J.style.width=Math.ceil(b)+"px";J.style.height=Math.ceil(p)+"px";this.recentTilesById[J.id].lastTouchedTime=f}}}this.requestManager.clearExcept(G);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);h.style.left=Math.round(d)+"px";h.style.top=Math.round(c)+"px";h.style.width=Math.ceil(b.provider.tileWidth*j)+"px";h.style.height=Math.ceil(b.provider.tileHeight*j)+"px";var i=b.layers[h.coord.zoom];i.appendChild(h);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.lastTouchedTimeh.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 ch?-1:0}else{return g.zoomf.zoom?-1:0}}return e?1:d?-1:0}}}})(com.modestmaps); \ No newline at end of file diff --git a/src/map.js b/src/map.js index 699f532..51c109a 100644 --- a/src/map.js +++ b/src/map.js @@ -652,17 +652,6 @@ theMap.recentTilesById[tile.id] = record; theMap.recentTiles.push(record); - // add tile to its layer: - var theLayer = theMap.layers[tile.coord.zoom]; - theLayer.appendChild(tile); - - //if (!theMap.lastTileReceived) { - // theMap.lastTileReceived = new Date().getTime(); - //} - //var t = new Date().getTime(); - //console.log(tile.coord.toString() + ' ' + (t-theMap.lastTileReceived)); - //theMap.lastTileReceived = t; - // position this tile (avoids a full draw() call): var theCoord = theMap.coordinate.zoomTo(tile.coord.zoom); var scale = Math.pow(2, theMap.coordinate.zoom - tile.coord.zoom); @@ -675,6 +664,15 @@ tile.style.width = Math.ceil(theMap.provider.tileWidth * scale) + 'px'; tile.style.height = Math.ceil(theMap.provider.tileHeight * scale) + 'px'; + // add tile to its layer + var theLayer = theMap.layers[tile.coord.zoom]; + theLayer.appendChild(tile); + + // 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'; + } + // request a lazy redraw of all layers // this will remove tiles that were only visible // to cover this tile while it loaded: diff --git a/src/requests.js b/src/requests.js index 52cec8f..12ffd41 100644 --- a/src/requests.js +++ b/src/requests.js @@ -112,6 +112,17 @@ } } }, + + getProcessQueue: function() { + // let's only create this closure once... + if (!this._processQueue) { + var theManager = this; + this._processQueue = function() { + theManager.processQueue(); + } + } + return this._processQueue; + }, processQueue: function(sortFunc) { if (sortFunc && this.requestQueue.length > 8) { @@ -193,7 +204,7 @@ // use setTimeout() to avoid the IE recursion limit, see // http://cappuccino.org/discuss/2010/03/01/internet-explorer-global-variables-and-stack-overflows/ // and https://github.com/stamen/modestmaps-js/issues/12 - setTimeout(theManager.processQueue, 0); + setTimeout(theManager.getProcessQueue(), 0); }; } diff --git a/src/start.js b/src/start.js index 516c5f0..a65a4c7 100644 --- a/src/start.js +++ b/src/start.js @@ -1,5 +1,5 @@ /*! - * Modest Maps JS v0.14.2 + * Modest Maps JS v0.14.3 * http://modestmaps.com/ * * Copyright (c) 2010 Stamen Design, All Rights Reserved.