This map uses an orthographic projection with D3.js and Topojson to draw a map of India onto a spinning globe, rendered here with a graticule that is 10° by 10°.
The code for the rotation can be seen in the spinEarth()
function. In this case, we rotate the lambda (λ) axis with every tick of the timer. You can make the rotation go haywire by messing with the phi (φ) and gamma (γ) axes, which are the second and third items in the array passed to projection.rotate()
.
xxxxxxxxxx
<html>
<head>
<style>
body {
font-family: "Helvetica Neue", sans-serif;
margin: 0;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight;
var projection = d3.geoOrthographic()
.scale(width / 2)
.translate([width / 2, height / 2])
.precision(1);
var path = d3.geoPath()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
drawGraticule();
spinEarth();
d3.json("india.json", function(error, data){
var subunits = drawSubUnits(data);
colorSubunits(subunits);
drawSubUnitLabels(data);
drawOuterBoundary(data);
});
function colorSubunits(subunits) {
var c = d3.scaleOrdinal(d3.schemeCategory20);
subunits
.style("fill", function(d,i){ return c(i); })
.style("opacity", ".6");
}
function drawGraticule(){
var graticule = d3.geoGraticule()
.step([10, 10]);
g.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path)
.style("fill", "none")
.style("stroke", "#ccc");
}
function drawOuterBoundary(data, boundary){
g.append("path")
.datum(topojson.mesh(data, data.objects.polygons, function(a, b) { return a === b; }))
.attr("d", path)
.attr("class", "subunit-boundary")
.attr("fill", "none")
.attr("stroke", "#3a403d");
}
function drawSubUnits(data){
var subunits = g.selectAll(".subunit")
.data(topojson.feature(data, data.objects.polygons).features)
.enter().append("path")
.attr("class", "subunit")
.attr("d", path)
.style("stroke", "#fff")
.style("stroke-width", "1px");
return subunits;
}
function drawSubUnitLabels(data){
g.selectAll(".subunit-label")
.data(topojson.feature(data, data.objects.polygons).features)
.enter().append("text")
.attr("class", "subunit-label")
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("font-size", ".5em")
.style("text-shadow", "0px 0px 2px #fff")
.style("text-transform", "uppercase")
.text(function(d) { return d.properties.st_nm; });
}
function spinEarth(){
d3.timer(function(elapsed) {
projection.rotate([.01 * elapsed - 120, -30, 0]);
g.selectAll("path").attr("d", path);
g.selectAll("text").attr("transform", function(d) { return isNaN(path.centroid(d)[0]) ? "translate(-100, -100)" : "translate(" + path.centroid(d) + ")"; });
});
}
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js