Created
February 3, 2016 15:48
-
-
Save jspeis/8cedd7f23b4dbfd7d22e to your computer and use it in GitHub Desktop.
proof of concept for saving map tiles from SVG to PNG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
margin: 0; | |
} | |
path { | |
fill: none; | |
stroke: red; | |
stroke-linejoin: round; | |
stroke-width: 1.5px; | |
} | |
</style> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script> | |
<script src="d3.geo.tile.min.js"></script> | |
<script type="text/javascript" src="http://gabelerner.github.io/canvg/rgbcolor.js"></script> | |
<script type="text/javascript" src="http://gabelerner.github.io/canvg/StackBlur.js"></script> | |
<script type="text/javascript" src="http://gabelerner.github.io/canvg/canvg.js"></script> | |
<script src="d3plus.js"></script> | |
<script src="FileSaver.js"></script> | |
<script src="canvas-toBlob.js"></script> | |
<button value="hello" onclick="go();">Go</button><br/> | |
<script> | |
function convert(url, callback){ | |
var img = new Image(); | |
img.crossOrigin = 'Anonymous'; | |
img.onload = function(){ | |
var canvas2 = document.createElement('CANVAS'); | |
var ctx2 = canvas2.getContext('2d'); | |
var dataURL; | |
canvas2.height = this.height; | |
canvas2.width = this.width; | |
ctx2.drawImage(this, 0, 0); | |
dataURL = canvas2.toDataURL('image/png'); | |
callback(url, dataURL); | |
canvas2 = null; | |
}; | |
img.src = url; | |
} | |
var cachedTiles = {}; | |
var width = 512, | |
height = 512; | |
var tile = d3.geo.tile() | |
.size([width, height]); | |
var projection = d3.geo.mercator() | |
.scale((1 << 12) / 2 / Math.PI) | |
.translate([width / 2, height / 2]); | |
var center = projection([-100, 40]); | |
var path = d3.geo.path() | |
.projection(projection); | |
var tilePath = path.context(context); | |
function drawTile(d, url, tiles) { | |
var k = Math.pow(2, d[2]) * 256; | |
var x = (d[0] + tiles.translate[0]) * tiles.scale; | |
var y = (d[1] + tiles.translate[1]) * tiles.scale; | |
var s = tiles.scale / 256; | |
tilePath | |
.projection() | |
.translate([ k / 2 - d[0] * 256, k / 2 - d[1] * 256 ]) | |
.scale(k / 2 / Math.PI); | |
context.save(); | |
context.translate(x, y); | |
context.scale(s, s); | |
var himg; | |
if (url in cachedTiles) { | |
himg = cachedTiles[url]; | |
context.drawImage(himg, 0, 0); | |
} else { | |
// himg = document.createElement("img"); | |
// himg.src = url; | |
// himg.crossOrigin = "Anonymous"; | |
convert(url, img_done); | |
} | |
context.restore(); | |
} | |
function img_done(url, b64Data){ | |
var himg = document.createElement("img"); | |
himg.src = b64Data; | |
if (!(url in cachedTiles)) { | |
cachedTiles[url] = himg; | |
} | |
} | |
var zoom = d3.behavior.zoom() | |
.scale(projection.scale() * 2 * Math.PI) | |
.scaleExtent([1 << 11, 1 << 14]) | |
.translate([width - center[0], height - center[1]]) | |
.on("zoom", zoomed); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var canvas = d3.select("body") | |
.append("canvas") | |
.attr("id", "drawcanvas") | |
.attr("width", width) | |
.attr("height", height); | |
var context = canvas.node().getContext("2d"); | |
var raster = svg.append("g"); | |
var vector = svg.append("path"); | |
d3.json("/mapdata/us.json", function(error, us) { | |
if (error) throw error; | |
svg.call(zoom); | |
vector.datum(topojson.mesh(us, us.objects.states)); | |
zoomed(); | |
}); | |
function zoomed() { | |
var tiles = tile | |
.scale(zoom.scale()) | |
.translate(zoom.translate()) | |
(); | |
context.clearRect(0, 0, width, height); | |
tiles.forEach(function(d) { | |
var letters = [ "a", "b", "c" ]; | |
var letter = letters[(d[0] * 31 + d[1]) % 3]; | |
var url = "http://" + ["a", "b", "c"][Math.random() * 3 | 0] + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; | |
drawTile(d, url, tiles); | |
}); | |
projection | |
.scale(zoom.scale() / 2 / Math.PI) | |
.translate(zoom.translate()); | |
vector | |
.attr("d", path); | |
var image = raster | |
.attr("transform", "scale(" + tiles.scale + ")translate(" + tiles.translate + ")") | |
.selectAll("image") | |
.data(tiles, function(d) { return d; }); | |
image.exit() | |
.remove(); | |
image.enter().append("image") | |
.attr("xlink:href", function(d) { return "http://" + ["a", "b", "c"][Math.random() * 3 | 0] + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; }) | |
.attr("width", 1) | |
.attr("height", 1) | |
.attr("x", function(d) { return d[0]; }) | |
.attr("y", function(d) { return d[1]; }); | |
} | |
function cap_canv(mycanvas) { | |
imgData = mycanvas.toDataURL('image/png'); | |
mycanvas.toBlob(function(blob) { | |
saveAs(blob, "pretty_image.png"); | |
}); | |
} | |
function go() { | |
zoomed(); | |
var tmp = vector.style({"stroke-width": "1.5px", "fill": "none", "stroke": "red", "stroke-linejoin": "round"}).node(); | |
if (d3plus.client.ie) { | |
tmp = (new XMLSerializer()).serializeToString(tmp); | |
context.drawSvg(tmp); | |
} else { | |
context.drawSvg(tmp.outerHTML); | |
} | |
cap_canv(canvas.node()); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment