index.html
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geo.albers().rotate([-132.5, 0]).center([0, -26.5]).parallels([-36, -18]);
var melb = projection([144.9631, -37.8136]),
center = projection.translate();
var scale,
translate,
area;
var clip = d3.geo.clipExtent()
.extent([[0, 0], [width, height]]);
var simplify = d3.geo.transform({
point: function(x, y, z) {
if (z >= area) this.stream.point(x * scale + translate[0], y * scale + translate[1]);
}
});
var zoom = d3.behavior.zoom()
.size([width, height])
.on("zoom", zoomed);
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
var path = d3.geo.path()
.projection({stream: function(s) { return simplify.stream(clip.stream(s)); }})
.context(context);
d3.json("combined.topo.json", function(error, geo) {
canvas
.datum([
topojson.mesh(topojson.presimplify(geo), geo.objects.electorates),
topojson.mesh(topojson.presimplify(geo), geo.objects.voronoi),
])
.call(zoomTo(melb, 200).event)
.transition()
.duration(4000)
.each(jump);
});
function zoomTo(point, scale) {
return zoom
.translate([width / 2 - point[0] * scale, height / 2 - point[1] * scale])
.scale(scale);
}
function zoomed(d) {
translate = zoom.translate();
scale = zoom.scale();
area = 4 / scale / scale;
context.clearRect(0, 0, width, height);
context.strokeStyle = '#222';
context.beginPath();
path(d[0]);
context.stroke();
context.strokeStyle = 'steelblue';
context.beginPath();
path(d[1]);
context.stroke();
}
function jump() {
var t = d3.select(this);
(function repeat() {
t = t.transition()
.call(zoomTo(center, 1).event)
.transition()
.call(zoomTo(melb, 200).event)
.each("end", repeat);
})();
}
</script>