Skip to content

Instantly share code, notes, and snippets.

@kkdd
Last active July 2, 2017 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkdd/b924dd3b9be643ded350ff629210bcaf to your computer and use it in GitHub Desktop.
Save kkdd/b924dd3b9be643ded350ff629210bcaf to your computer and use it in GitHub Desktop.
equirectangular projection (d3.js)
<!DOCTYPE html>
<meta charset = "utf-8" >
<title>equirectangular projection</title>
<style>
.land {
fill: #eee;
stroke: #888;
stroke-width: .5px;
}
.boundary {
fill: none;
stroke: #ccc;
}
.spiral {
fill: red;
fill-opacity: .2;
stroke: #f00;
stroke-width: .5px;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: 0.3px;
stroke-opacity: 0.5;
}
</style>
<body>
<script src= "https://d3js.org/d3.v4.min.js" > </script>
<script src = "http://d3js.org/topojson.v3.min.js" > </script>
<script>
var nspiral = 12,
dlat = 5,
ndiv = 5,
ndivRange = [3, 48],
centerProjection = [-30, 0],
rotationSpeed = 20;
var width = 600,
height = 320,
SECOND = 1000;
var spiral, timer, doRotation = true;
var scaleProj = Math.min(width / 2, height) / Math.PI;
var projection = d3.geoEquirectangular().translate([width / 2, height / 2]).scale(scaleProj).rotate([-centerProjection[0], -centerProjection[1]]);
var path = d3.geoPath().projection(projection);
var graticule = d3.geoGraticule();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.on("wheel", redraw)
.call(d3.drag()
.subject(function() {
var rotate = projection.rotate();
return {
x: 2 * rotate[0],
y: -2 * rotate[1]
};
})
.on("start", function(d) {
doRotation = false;
clearTimeout(timer);
})
.on("end", function(d) {
restartRotation()
})
.on("drag", function() {
projection.rotate([d3.event.x / 2, -d3.event.y / 2, projection.rotate()[2]]);
svg.selectAll("path").attr("d", path);
}));
svg.selectAll(".graticule")
.data(graticule.lines)
.enter().append("path")
.attr("class", "graticule")
.attr("d", path);
drawSpiral(ndiv);
function restartRotation() {
timer = setTimeout(function() {
doRotation = true
}, 1 * SECOND);
}
function redraw() {
ndiv *= Math.exp(d3.event.deltaY * 0.004);
ndiv = clipRange(Math.ceil(ndiv), ndivRange);
drawSpiral(ndiv);
}
function clipRange(x, xRange) {
return Math.min(Math.max(x, xRange[0]), xRange[1]);
}
function makeSpiral(t, d) {
if (!d) {
d = 0
}
return [normalise(360 * nspiral * t), (180 - dlat) * t - 90 + dlat * d];
}
function normalise(x) {
return (x + 180) % 360 - 180;
}
function drawSpiral(ndiv) {
ndiv *= nspiral;
if (spiral) {
spiral.remove()
}
spiral = d3.range(0, ndiv + 1).map(function(w) {
return makeSpiral(w / ndiv, 1);
}).concat(d3.range(ndiv, -1, -1).map(function(w) {
return makeSpiral(w / ndiv);
}));
spiral.push(spiral[0]);
spiral = svg.append("path")
.datum({
type: "Polygon",
coordinates: [spiral]
})
.attr("class", "spiral")
.attr("d", path);
}
var url = "https://unpkg.com/world-atlas@1/world/110m.json";
d3.json(url, function(error, world) {
svg.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
svg.insert("g", ".graticule")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) {
return a !== b;
}))
.attr("class", "boundary")
.attr("d", path);
function autoRotate() {
if (doRotation) {
var o0 = projection.rotate();
o0[0] += 1;
projection.rotate(o0);
svg.selectAll("path")
.attr("d", path);
}
}
setInterval(autoRotate, rotationSpeed);
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment