Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emeeks/11051379 to your computer and use it in GitHub Desktop.
Save emeeks/11051379 to your computer and use it in GitHub Desktop.
D3 Tile Map with Hand-Drawn Polygon
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>D3 in Action Examples</title>
<meta charset="utf-8" />
</head>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript">
</script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js" type="text/javascript">
</script>
<script src="tile.js" type="text/javascript">
</script>
<body onload="createMap();">
<div id="vizcontainer">
<svg style="width:500px;height:500px;border:1px lightgray solid;" />
</div>
<footer>
<script>
function createMap() {
mBB = {geometry: {coordinates: [[[-74.0479, 40.8820], [-73.9067, 40.8820], [-73.9067, 40.6829], [-74.0479, 40.6829], [-74.0479, 40.8820]]], type: "Polygon"}, id: 999999, properties:{}, type: "Feature"};
var width = 500,
height = 500;
d3.select("svg").append("g").attr("id", "tiles");
d3.select("svg").append("g").attr("id", "vectors");
var tile = d3.geo.tile()
.size([width, height]);
var projection = d3.geo.mercator()
.scale((1 << 18) / 2 / Math.PI)
.translate([width / 2, height / 2]);
var center = projection([-73.95, 40.7]);
var path = d3.geo.path()
.projection(projection);
var zoom = d3.behavior.zoom()
.scale(projection.scale() * 2 * Math.PI)
.translate([width - center[0], height - center[1]])
.on("zoom", redraw);
d3.select("svg").call(zoom);
projection
.scale(1 / 2 / Math.PI)
.translate([0, 0]);
geoPath = d3.geo.path().projection(projection);
d3.select("#vectors").selectAll("path.countries").data([mBB])
.enter()
.append("path")
.attr("d", geoPath)
.attr("class", "countries")
.style("fill", "red")
.style("stroke-width", 3)
.style("stroke", "black")
.style("fill-opacity", .25)
redraw();
function redraw() {
var tiles = tile
.scale(zoom.scale())
.translate(zoom.translate())
();
var image = d3.select("#tiles").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", "d"][Math.random() * 4 | 0] + ".tiles.mapbox.com/v3/examples.map-zgrqqx0w/" + 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]; });
projection
.scale(zoom.scale() / 2 / Math.PI)
.translate(zoom.translate());
d3.selectAll("path")
.attr("d", geoPath);
}
}
</script>
</footer>
</body>
</html>
d3.geo.tile = function() {
var size = [960, 500],
scale = 256,
translate = [size[0] / 2, size[1] / 2],
zoomDelta = 0;
function tile() {
var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
z0 = Math.round(z + zoomDelta),
k = Math.pow(2, z - z0 + 8),
origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
tiles = [],
cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
rows.forEach(function(y) {
cols.forEach(function(x) {
tiles.push([x, y, z0]);
});
});
tiles.translate = origin;
tiles.scale = k;
return tiles;
}
tile.size = function(_) {
if (!arguments.length) return size;
size = _;
return tile;
};
tile.scale = function(_) {
if (!arguments.length) return scale;
scale = _;
return tile;
};
tile.translate = function(_) {
if (!arguments.length) return translate;
translate = _;
return tile;
};
tile.zoomDelta = function(_) {
if (!arguments.length) return zoomDelta;
zoomDelta = +_;
return tile;
};
return tile;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment