Skip to content

Instantly share code, notes, and snippets.

@mbostock

mbostock/.block Secret

Created June 22, 2016 15:03
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 mbostock/e94d145a60278eada9945de3d630680e to your computer and use it in GitHub Desktop.
Save mbostock/e94d145a60278eada9945de3d630680e to your computer and use it in GitHub Desktop.
license: gpl-3.0
// Derived from https://github.com/d3/d3-plugins/blob/master/geo/tile/tile.js
d3.geoTile = 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;
};
<!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="//d3js.org/d3.v4.0.0-alpha.50.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="d3-geo-tile.js"></script>
<script>
var width = Math.max(960, window.innerWidth),
height = Math.max(500, window.innerHeight);
var tile = d3.geoTile()
.size([width, height]);
var projection = d3.geoMercator()
.scale((1 << 12) / 2 / Math.PI)
.translate([width / 2, height / 2]);
var center = projection([-100, 40]);
var path = d3.geoPath()
.projection(projection);
var zoom = d3.zoom()
.scaleExtent([1 << 11, 1 << 14])
.on("zoom", zoomed);
var initialTransform = d3.zoomIdentity
.translate(width - center[0], height - center[1])
.scale(projection.scale() * 2 * Math.PI);
// With the center computed, now adjust the projection such that
// it uses the zoom behavior’s translate and scale.
projection
.scale(1 / 2 / Math.PI)
.translate([0, 0]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var raster = svg.append("g");
var vector = svg.append("path");
d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
if (error) throw error;
svg.call(zoom).call(zoom.transform, initialTransform);
vector.attr("d", path(topojson.mesh(us, us.objects.counties)));
});
function zoomed() {
var transform = d3.event.transform;
var tiles = tile
.scale(transform.k)
.translate([transform.x, transform.y])
();
vector
.attr("transform", transform)
.style("stroke-width", 1 / transform.k);
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"][d[0] % 3] + ".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]; });
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment