A remake of a previous block, Dynamic Globe Rotation, but with Fil's d3-inertia module.
TODO:
Currently, you must wait for the globe to come to a complete stop before you can adjust any of the range sliders. It would be cool if you could adjust one of the angles even as the other two continue on their paths.
UPDATE Fixed, thanks to Fil! This fix doesn't let you stop only one angle of the inertial movement while the other two continue, but it's an improvement.
if (inertia.timer) inertia.timer.stop();
Currently, the range sliders just behave like normal range sliders – when you release the slider, it stops moving, no matter how fast you slide it. It would be cool to somehow add inertia to the behavior of the range sliders.
xxxxxxxxxx
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
margin: 0;
}
#rotation {
position: absolute;
font-family: monospace;
padding: 10px;
background: rgba(255, 255, 255, .5);
}
#rotation input {
width: 300px;
}
.graticule {
fill: none;
stroke: #ccc;
}
.country {
stroke: #fff;
}
line {
stroke: tomato;
stroke-width: 3px;
}
</style>
</head>
<body>
<div id="rotation"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson@3.0.2/dist/topojson.js"></script>
<script src="https://unpkg.com/versor@0.0.3/build/versor.min.js"></script>
<script src="https://unpkg.com/d3-inertia@0.0.5/build/d3-inertia.min.js"></script>
<script>
var angles = ["λ", "φ", "γ"];
angles.forEach(function(angle, index){
d3.select("#rotation").append("div")
.attr("class", "angle-label angle-label-" + index)
.html(angle + ": <span>0</span>")
d3.select("#rotation").append("input")
.attr("type", "range")
.attr("class", "angle angle-" + index)
.attr("min", "-180")
.attr("max", "180")
.attr("value", "0");
});
var width = window.innerWidth, height = window.innerHeight;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geoOrthographic()
.scale(d3.min([width / 2, height / 2]))
.translate([width / 2, height / 2])
.precision(1);
var path = d3.geoPath()
.projection(projection);
// append the graticule
svg.append("path")
.datum(d3.geoGraticule().step([10, 10]))
.attr("class", "graticule")
.attr("d", path);
var line = svg.append("line"),
pts;
// inertia versor dragging
var inertia = d3.geoInertiaDrag(svg, function() { render(); }, projection);
function render(){
if (inertia.t){
// make the line
pts = [
[inertia.position[0] + inertia.velocity[0] / 10, inertia.position[1] + inertia.velocity[1] / 10],
[inertia.position[0] + inertia.velocity[0] * inertia.t / 10, inertia.position[1] + inertia.velocity[1] * inertia.t / 10]
];
line
.attr("x1", pts[0][0])
.attr("y1", pts[0][1])
.attr("x2", pts[1][0])
.attr("y2", pts[1][1]);
}
update(projection.rotate());
}
d3.selectAll("input").on("input", function(){
var p = [];
d3.selectAll("input").each(function(d, i){
p.push(+d3.select(this).property("value"));
});
if (inertia.timer) {
inertia.timer.stop();
removeLine();
}
update(p);
});
// this fixes a strange behavior, where when you click on the svg while the globe is moving,
// the movement stops but the line remains
svg.on("click", function(){
removeLine();
});
function update(eulerAngles){
angles.forEach(function(angle, index){
d3.select(".angle-label-" + index + " span").html(Math.round(eulerAngles[index]))
d3.select(".angle-" + index).property("value", eulerAngles[index])
});
projection.rotate(eulerAngles);
svg.selectAll("path").attr("d", path);
}
function removeLine(){
line.attr("x1", 0).attr("y1", 0).attr("x2", 0).attr("y2", 0);
}
d3.json("countries.json", function(error, countries){
if (error) throw error;
svg.selectAll(".country")
.data(topojson.feature(countries, countries.objects.polygons).features)
.enter().append("path")
.attr("class", "country")
.attr("d", path);
});
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://unpkg.com/topojson@3.0.2/dist/topojson.js
https://unpkg.com/versor@0.0.3/build/versor.min.js
https://unpkg.com/d3-inertia@0.0.5/build/d3-inertia.min.js