|
function lng2map(lon) { return (((lon+180)/360*Math.pow(2,0))); } |
|
function lat2map(lat) { return (((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,0))); } |
|
|
|
function svg_map(svg,p) { return new svg_map_obj(svg,p) } |
|
|
|
function svg_map_obj(svg,p) { |
|
var p = p ? p : {}, |
|
x0 = p.x0 ? p.x0 : 0.1286, // default x start location [0,1] |
|
y0 = p.y0 ? p.y0 : 0.33066, // default y start location [0,1] |
|
zoom = p.zoom ? p.zoom : 6, // default zoom at 6 |
|
update_delay = p.update_freq ? p.update_freq : 50, // How fast we look for new tiles |
|
zoom_delay = p.zoom_delay ? p.zoom_delay : 1000, // How long we keep old tiles when zooming |
|
tiles = [], keepTiles = [], // variables holding the tile ids |
|
mapLayer = svg.append("svg:g").attr("class","mapLayer"), |
|
viewBox = svg[0][0].viewBox.baseVal; |
|
|
|
function PixelWidthSVG() { return svg[0][0].clientWidth ? svg[0][0].clientWidth : svg[0][0].parentNode.clientWidth;} |
|
function PixelHeightSVG() { return svg[0][0].clientHeight ? svg[0][0].clientHeight : svg[0][0].parentNode.clientHeight;} |
|
|
|
function resize() { |
|
new_zoom = Math.floor(checkZoom()); |
|
viewBox.width = PixelWidthSVG() / (Math.pow(2,new_zoom)*256); |
|
viewBox.height = PixelHeightSVG() / (Math.pow(2,new_zoom)*256); |
|
loadTiles(); |
|
} |
|
|
|
checkZoom = function() { |
|
return Math.min(Math.max(Math.log(PixelWidthSVG()/(viewBox.width*256))/Math.log(2),0),18); |
|
} |
|
|
|
loadTiles = function() { |
|
new_zoom = Math.floor(checkZoom()); |
|
if (zoom != new_zoom) { |
|
zoom = new_zoom; |
|
if (keepTiles.length == 0) { |
|
keepTiles = tiles.slice(); |
|
setTimeout(function (){ keepTiles = []},1000) |
|
} |
|
} |
|
no_x = Math.floor(PixelWidthSVG() / 256)+3; |
|
no_y = Math.floor(PixelHeightSVG() / 256)+3; |
|
|
|
firstX = Math.max(Math.floor(viewBox.x * Math.pow(2,zoom)-1),0); |
|
firstY = Math.max(Math.floor(viewBox.y * Math.pow(2,zoom)-1),0); |
|
|
|
tiles = []; |
|
|
|
for (x=Math.max(firstX,0); x<Math.min(firstX+no_x,Math.pow(2,zoom));x++) { |
|
for (y=Math.max(firstY,0); y <Math.min(firstY+no_y,Math.pow(2,zoom));y++) { |
|
tiles.push({x:x,y:y,zoom:zoom}); |
|
}; |
|
}; |
|
|
|
images = mapLayer.selectAll("image").data(tiles.concat(keepTiles),function(d) { return d.zoom+"/"+d.x+"/"+d.y;}); |
|
images.enter() |
|
.append("svg:image") |
|
.attr("x",function(d) { return (d.x) / Math.pow(2,zoom);}) |
|
.attr("y",function(d) { return (d.y)/ Math.pow(2,zoom);}) |
|
.attr("height",1/Math.pow(2,zoom)) |
|
.attr("width",1/Math.pow(2,zoom)) |
|
.property("shape-rendering","crispEdges") |
|
.attr("xlink:href",function(d) { |
|
return "http://b.tile.cloudmade.com/"+p.api_key+"/1/256/"+zoom+"/"+d.x+"/"+d.y+".png";}) |
|
|
|
images.exit().remove(); |
|
} |
|
svg.attr("viewBox",x0+" "+y0+" "+"0.1 0.1") |
|
.attr("preserveAspectRatio", "xMinYMin meet"); // Ensure a viewbox exists with fixed aspect ratio |
|
resize(); |
|
setInterval(loadTiles,update_delay); // Keep looking for new tiles and discard old |
|
svg.svg_map = {checkZoom:checkZoom,resize:resize,loadTiles:loadTiles}; |
|
return svg.map_data; |
|
} |