Skip to content

Instantly share code, notes, and snippets.

@pcarleton
Last active October 23, 2019 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pcarleton/578c5ddfb1ac9a1e90d7 to your computer and use it in GitHub Desktop.
Save pcarleton/578c5ddfb1ac9a1e90d7 to your computer and use it in GitHub Desktop.
Moon Phase

This is an example of using D3's orthograph projections to visualize moon phases. My starting point for this was http://bl.ocks.org/mbostock/3795040.

GeoJSON

There is a nice geojson wsyiwig editor here: http://geojson.io/#map=1/16/-68.

When defining points, the first value is the angle in degrees from the prime meridian (-180, 180). The second is the angle in degrees from the equator [-90, 90]. So, any value [x, 90] is at the North pole, and any value [x, -90] is at the south pole. I was getting some funkiness when I put things directly on the poles, so I fudged it a little bit and went with 89.5.

You can read hemisphere.json like this:

  1. [90, -90] -- start at the south pole ([x, -90]), 1/4 of the way around travelling east from the prime meridian ([90, x]).
  2. [90, 90] -- Go to the north pole ([x, 90])
  3. [-90, 90] -- Travel halfway around the world, so you're 3/4 of the way past the prime meridian, or 1/4 of the way if you travel west ([-90, x])
  4. [-90, -90] -- Go back to the south pole
  5. [90, -90] -- Travel back to the starting point

It's important to have your first point and last point be identical, or nothing will render.

Display the source blob
Display the rendered blob
Raw
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">
<head>
<style>
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}
.body {
fill: black;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v3.js"></script>
<script>
var width = 400,
height = 300;
var geoScale = 100;
var projection = d3.geo.orthographic()
.scale(geoScale)
.translate([width / 2, height / 2])
.clipAngle(90);
var path = d3.geo.path()
.projection(projection);
var stationaryProjection = d3.geo.orthographic()
.scale(geoScale)
.translate([width / 2, height / 2])
.clipAngle(90);
var gratPath = d3.geo.path()
.projection(stationaryProjection);
var λ = d3.scale.linear()
.domain([0, width])
.range([-180, 180]);
var φ = d3.scale.linear()
.domain([0, height])
.range([90, -90]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var start = 0;
var day = 0;
var mod = 0;
var dayInt = 360/29.503;
var splits = 5;
var step = dayInt/splits;
setInterval(function() {
start += step;
mod += 1;
if (mod > splits) {
mod = 0;
day += 1;
if (day > 29) {
day = 1;
}
document.getElementById('daynum').innerHTML = day;
}
if (start > 180) {
start = -180 + (start - 180);
}
projection.rotate([start, 0]);
svg.selectAll("path.light").attr("d",path);
}, 100);
var graticule = d3.geo.graticule();
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", gratPath);
// Load our GeoJSON which just represents a hemisphere of darkness
d3.json("hemisphere.json", function(error, world) {
if (error) throw error;
svg.append("path")
.datum(world)
.attr("class", "light")
.attr("d", path);
});
</script>
<p>Day <span id="daynum">0</span></p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment