A version of Mike Bostock’s animated world countries, which uses a more accurate spherical interpolation.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| .country { | |
| fill: #b8b8b8; | |
| stroke: #fff; | |
| stroke-width: .5px; | |
| stroke-linejoin: round; | |
| } | |
| .graticule { | |
| fill: none; | |
| stroke: #000; | |
| stroke-opacity: .3; | |
| stroke-width: .5px; | |
| } | |
| .graticule-outline { | |
| fill: none; | |
| stroke: #333; | |
| stroke-width: 1.5px; | |
| } | |
| text { | |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| font-size: 18px; | |
| font-weight: bold; | |
| text-anchor: middle; | |
| } | |
| </style> | |
| <body> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://d3js.org/topojson.v0.min.js"></script> | |
| <script> | |
| var width = 960, | |
| height = 500; | |
| var centroid = d3.geo.path() | |
| .projection(function(d) { return d; }) | |
| .centroid; | |
| var projection = d3.geo.orthographic() | |
| .scale(248) | |
| .clipAngle(90); | |
| var path = d3.geo.path() | |
| .projection(projection); | |
| var graticule = d3.geo.graticule() | |
| .extent([[-180, -90], [180 - .1, 90 - .1]]); | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", width) | |
| .attr("height", height); | |
| var line = svg.append("path") | |
| .datum(graticule) | |
| .attr("class", "graticule") | |
| .attr("d", path); | |
| svg.append("circle") | |
| .attr("class", "graticule-outline") | |
| .attr("cx", width / 2) | |
| .attr("cy", height / 2) | |
| .attr("r", projection.scale()); | |
| var title = svg.append("text") | |
| .attr("x", width / 2) | |
| .attr("y", height * 3 / 5); | |
| var rotate = d3_geo_greatArcInterpolator(); | |
| d3.json("readme-world-110m.json", function(error, world) { | |
| var countries = topojson.object(world, world.objects.countries).geometries, | |
| i = -1, | |
| n = countries.length; | |
| var country = svg.selectAll(".country") | |
| .data(countries) | |
| .enter().insert("path", ".graticule") | |
| .attr("class", "country") | |
| .attr("d", path); | |
| step(); | |
| function step() { | |
| if (++i >= n) i = 0; | |
| title.text(countries[i].id); | |
| country.transition() | |
| .style("fill", function(d, j) { return j === i ? "red" : "#b8b8b8"; }); | |
| d3.transition() | |
| .delay(250) | |
| .duration(1250) | |
| .tween("rotate", function() { | |
| var point = centroid(countries[i]); | |
| rotate.source(projection.rotate()).target([-point[0], -point[1]]).distance(); | |
| return function(t) { | |
| projection.rotate(rotate(t)); | |
| country.attr("d", path); | |
| line.attr("d", path); | |
| }; | |
| }) | |
| .transition() | |
| .each("end", step); | |
| } | |
| }); | |
| var d3_radians = Math.PI / 180; | |
| function d3_geo_greatArcInterpolator() { | |
| var x0, y0, cy0, sy0, kx0, ky0, | |
| x1, y1, cy1, sy1, kx1, ky1, | |
| d, | |
| k; | |
| function interpolate(t) { | |
| var B = Math.sin(t *= d) * k, | |
| A = Math.sin(d - t) * k, | |
| x = A * kx0 + B * kx1, | |
| y = A * ky0 + B * ky1, | |
| z = A * sy0 + B * sy1; | |
| return [ | |
| Math.atan2(y, x) / d3_radians, | |
| Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians | |
| ]; | |
| } | |
| interpolate.distance = function() { | |
| if (d == null) k = 1 / Math.sin(d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0))))); | |
| return d; | |
| }; | |
| interpolate.source = function(_) { | |
| var cx0 = Math.cos(x0 = _[0] * d3_radians), | |
| sx0 = Math.sin(x0); | |
| cy0 = Math.cos(y0 = _[1] * d3_radians); | |
| sy0 = Math.sin(y0); | |
| kx0 = cy0 * cx0; | |
| ky0 = cy0 * sx0; | |
| d = null; | |
| return interpolate; | |
| }; | |
| interpolate.target = function(_) { | |
| var cx1 = Math.cos(x1 = _[0] * d3_radians), | |
| sx1 = Math.sin(x1); | |
| cy1 = Math.cos(y1 = _[1] * d3_radians); | |
| sy1 = Math.sin(y1); | |
| kx1 = cy1 * cx1; | |
| ky1 = cy1 * sx1; | |
| d = null; | |
| return interpolate; | |
| }; | |
| return interpolate; | |
| } | |
| </script> |
aggieben
commented
Aug 27, 2015
aggieben
commented
Aug 27, 2015
Heh....nevermind. I wasn't setting the 'd' attribute on country or line. Still figuring out how to use lat/long though.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I've tried to boil this down a little simpler and do a single rotation to a given lat/long (that's a valid point in a geo projection, right?) and am not having much success. I replaced lines 87 - 112 with the following:
Nothing at all happens, and I'm a little bit at a loss as to why. Would you mind correcting me on what I've missed?