Skip to content

Instantly share code, notes, and snippets.

@jspeis
Created February 3, 2016 15:48
Show Gist options
  • Save jspeis/8cedd7f23b4dbfd7d22e to your computer and use it in GitHub Desktop.
Save jspeis/8cedd7f23b4dbfd7d22e to your computer and use it in GitHub Desktop.
proof of concept for saving map tiles from SVG to PNG
<!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