Skip to content

Instantly share code, notes, and snippets.

@croogie
Forked from mbostock/.block
Created April 6, 2015 11:44
Show Gist options
  • Save croogie/61bc60b39f5fd65572bc to your computer and use it in GitHub Desktop.
Save croogie/61bc60b39f5fd65572bc to your computer and use it in GitHub Desktop.
Map Pan & Zoom IV
.DS_Store
build
node_modules

This example uses d3.behavior.zoom with pre-projected geometry for map panning and zooming, in conjunction with dynamic simplification and viewport clipping. This approach is quite fast, but more work to implement than an SVG transform.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
canvas {
background: #eee;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<body>
<script>
var width = 960,
height = 960;
var scale,
translate,
area; // minimum area threshold for simplification
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()
.translate([0, 0])
.scale(1)
.scaleExtent([1, 8]);
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
context.lineJoin = "round";
context.lineCap = "round";
var path = d3.geo.path()
.projection({stream: function(s) { return simplify.stream(clip.stream(s)); }})
.context(context);
d3.json("world.json", function(error, world) {
topojson.presimplify(world);
var sphere = topojson.feature(world, world.objects.sphere),
land = topojson.feature(world, world.objects.land),
boundary = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; });
canvas
.call(zoom.on("zoom", zoomed))
.call(zoom.event);
function zoomed() {
translate = zoom.translate();
scale = zoom.scale();
area = 1 / scale / scale;
context.clearRect(0, 0, width, height);
context.save();
context.beginPath();
path(sphere);
context.fillStyle = "#fff";
context.fill();
context.beginPath();
path(land);
context.fillStyle = "#000";
context.fill();
context.beginPath();
path(boundary);
context.strokeStyle = "#fff";
context.stroke();
context.restore();
}
});
d3.select(self.frameElement).style("height", height + "px");
</script>
GENERATED_FILES = \
world.json
all: $(GENERATED_FILES)
clean:
rm -rf -- %(GENERATED_FILES)
.PHONY: all clean
build/ne_50m_admin_0_countries.zip:
mkdir -p $(dir $@)
curl -o $@ 'http://www.nacis.org/naturalearth/50m/cultural/$(notdir $@)'
build/ne_50m_admin_0_countries.shp: build/ne_50m_admin_0_countries.zip
unzip -d $(dir $@) $<
touch $@
world.json: build/ne_50m_admin_0_countries.shp sphere.json
node_modules/.bin/topojson \
-q 1e5 \
--projection='width = 960, height = 960, d3.geo.mercator() \
.translate([width / 2, height / 2]) \
.scale((width - 1) / 2 / Math.PI)' \
-- \
countries=build/ne_50m_admin_0_countries.shp \
sphere=sphere.json | \
node_modules/.bin/topojson-merge \
--io countries \
--oo land \
-o $@
{
"name": "anonymous",
"version": "0.0.1",
"private": true,
"dependencies": {
"topojson": "1"
}
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment