Skip to content

Instantly share code, notes, and snippets.

@Andrew-Reid
Last active October 17, 2017 14:48
Show Gist options
  • Save Andrew-Reid/d95e59b71544706515632c4b7fb0402a to your computer and use it in GitHub Desktop.
Save Andrew-Reid/d95e59b71544706515632c4b7fb0402a to your computer and use it in GitHub Desktop.
Transition Rotation & Scale of Orthographic Projection with Easing
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.background {
fill: none;
pointer-events: all;
stroke:grey;
}
.feature, {
fill: #ccc;
cursor: pointer;
}
.feature.active {
fill: orange;
}
.mesh,.land {
fill: black;
stroke: #ddd;
stroke-linecap: round;
stroke-linejoin: round;
}
.water {
fill: #00248F;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script>
var width = 960,
height = 600,
active = d3.select(null);
var projection = d3.geo.orthographic()
.scale(250)
.translate([width / 2, height / 2])
.clipAngle(90);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", reset);
var g = svg.append("g")
.style("stroke-width", "1.5px");
var countries;
var countryIDs;
queue()
.defer(d3.json, "world.json")
.await(ready)
function ready(error, world) {
if (error) throw error;
countries = topojson.feature(world, world.objects.countries).features;
//Adding water
g.append("path")
.datum({type: "Sphere"})
.attr("class", "water")
.attr("d", path);
var world = g.selectAll("path.land")
.data(countries)
.enter().append("path")
.attr("class", "land")
.attr("d", path)
.on("click", clicked)
};
function clicked(d) {
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
// Clicked on feature:
var p = d3.geo.centroid(d);
// Store the current rotation and scale:
var currentRotate = projection.rotate();
var currentScale = projection.scale();
// Calculate the future bounding box after applying a rotation:
projection.rotate([-p[0], -p[1]]);
path.projection(projection);
// calculate the scale and translate required:
var b = path.bounds(d);
var nextScale = currentScale * 1 / Math.max((b[1][0] - b[0][0]) / (width/2), (b[1][1] - b[0][1]) / (height/2));
var nextRotate = projection.rotate();
// Update the map:
d3.selectAll("path")
.transition()
.attrTween("d", function(d) {
var r = d3.interpolate(currentRotate, nextRotate);
var s = d3.interpolate(currentScale, nextScale);
return function(t) {
projection
.rotate(r(Math.pow(t,0.33)))
.scale( currentScale > nextScale ? s(Math.pow(t,0.1)) : s(Math.pow(t,3)) );
path.projection(projection);
return path(d);
}
})
.duration(1000);
}
function reset() {
active.classed("active", false);
active = d3.select(null);
d3.selectAll("path")
.transition()
.attrTween("d", function(d) {
var s = d3.interpolate(projection.scale(), 250);
return function(t) {
projection
.scale(s(t));
path.projection(projection);
return path(d);
}
})
.duration(1000);
}
</script>
Display the source blob
Display the rendered blob
Raw
Loading
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