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.
| .DS_Store | |
| build | |
| node_modules |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| canvas { | |
| background: #eee; | |
| } | |
| </style> | |
| <script src="//d3js.org/d3.v3.min.js"></script> | |
| <script src="//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) { | |
| if (error) throw error; | |
| 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" | |
| } | |
| } |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
melalj
commented
Aug 26, 2015
sfinktah
commented
Oct 5, 2015
$ cat sphere.json
{
"type": "Sphere"
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it possible to have the
sphere.json?