Skip to content

Instantly share code, notes, and snippets.

@tophtucker

tophtucker/README.md

Last active Sep 23, 2015
Embed
What would you like to do?
Earth orbit

Click to fast-forward. Based on the math here. No guarantees of accuracy, this is not legal advice. Made in honor of Pi Day — which I think is borderline numerology, a random and arbitrary mapping, but I respect the ability to create meaning in life ex nihilo.

<link rel="stylesheet" href="style.css">
<div id="ecliptic"></div>
<p>Date: <span id="date"></span><p>
<p>Distance from sun: <span id="radius"></span> AU</p>
<p>True anomaly: <span id="true-anomaly"></span>°</p>
<p>True anomaly: <span id="true-anomaly-pi"></span>π</p>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="script.js" charset="utf-8"></script>
// ALL GOOD STUFF ADAPTED FROM THIS WONDERFUL OLD SITE:
// http://www.stargazing.net/kepler/ellipse.html
// angles are in degrees
// distances are in a.u.
////////////////////////////////////////////
// dates
var dayToMs = 24*60*60*1000;
var msToDay = 1/dayToMs;
// trig
var degToRad = (2*Math.PI)/360;
var radToDeg = 1/degToRad;
function sin(x) { return Math.sin(x * degToRad); }
function cos(x) { return Math.cos(x * degToRad); }
// "Osculating Elements"
var abbrevs = {
"i": "Inclination",
"o": "Longitude of the Ascending Node",
"p": "Longitude of Perihelion",
"a": "Mean distance",
"n": "Daily motion",
"e": "Eccentricity",
"L": "Mean Longitude",
"JD": "Julian Date"
}
var earth = {
"i": 0.00041,
"o": 349.2,
"p": 102.8517,
"a": 1.0000200,
"n": 0.9855796,
"e": 0.0166967,
"L": 328.40353,
"JD": 2450680.5,
"datetime": new Date("August 20, 1997 00:00:00"),
"radius": 0.000042563739
};
var mars = {
"i": 1.84992,
"o": 49.5664,
"p": 336.0882,
"a": 1.5236365,
"n": 0.5240613,
"e": 0.0934231,
"L": 262.42784,
"JD": 2450680.5,
"datetime": new Date("August 20, 1997 00:00:00"),
"radius": 0.00002263
};
var sun = {
"radius": 0.004649
}
// MATH
function meanAnomaly(satellite, time) {
var days = (time-satellite.datetime)*msToDay;
return ((satellite.n * days + satellite.L - satellite.p) % 360 + 360) % 360;
}
function trueAnomaly(satellite, time) {
var M = meanAnomaly(satellite, time);
return M + (180/Math.PI) *
(
(2 * satellite.e - Math.pow(satellite.e, 3)/4) * Math.sin(degToRad*M) +
(5/4 * Math.pow(satellite.e, 2)) * Math.sin(degToRad*M*2) +
(13/12 * Math.pow(satellite.e, 3)) * Math.sin(degToRad*M*3)
);
}
function radius(satellite, time) {
return satellite.a * (1 - Math.pow(satellite.e, 2)) / (1 + satellite.e * Math.cos(trueAnomaly(satellite, time)*degToRad));
}
function coordinates(satellite, time) {
var r = radius(satellite, time);
var v = trueAnomaly(satellite, time);
var o = satellite.o;
var p = satellite.p;
var i = satellite.i;
var X = r * (cos(o) * cos(v+p-o) - sin(o) * sin(v+p-o) * cos(i));
var Y = r * (sin(o) * cos(v+p-o) + cos(o) * sin(v+p-o) * cos(i));
var Z = r * (sin(v+p-o) * sin(i));
return [X,Y,Z];
}
// au to pixels
var minPx = Math.min(window.innerHeight, window.innerWidth);
var auScale = d3.scale.linear().domain([0,2.2]).range([0,minPx]);
var sunSel = d3.select("#ecliptic").append("div")
.classed('celestial-body', true)
.attr('id', 'sun')
.style('left', '0')
.style('top', '0')
.style('width', (auScale(sun.radius)*2)+'px')
.style('height', (auScale(sun.radius)*2)+'px');
var earthSel = d3.select("#ecliptic").append("div")
.classed('celestial-body', true)
.attr('id', 'earth')
.style('width', (auScale(earth.radius)*2)+'px')
.style('height', (auScale(earth.radius)*2)+'px');
function render(time) {
var earthRadius = radius(earth, time);
var earthTrueAnomaly = trueAnomaly(earth, time);
var earthCoords = coordinates(earth, time);
console.log(earthCoords);
d3.select("#date").text(time);
d3.select("#radius").text(earthRadius);
d3.select("#true-anomaly").text(earthTrueAnomaly);
d3.select("#true-anomaly-pi").text(earthTrueAnomaly*degToRad/Math.PI);
earthSel
.style('left', auScale(earthCoords[0]) + 'px')
.style('top', auScale(earthCoords[1]) + 'px')
}
render(new Date());
var realtime = setInterval(function() { render(new Date()); }, 1000);
var fastForward;
window.onclick = function() {
clearInterval(realtime);
clearInterval(fastForward);
var t = 0;
fastForward = setInterval(function() {
var newTime = new Date(+new Date() + t*dayToMs);
render(newTime);
t++;
}, 50);
}
html, body {
margin: 0;
padding: 0;
background: black;
width: 100%;
height: 100%;
min-width: 500px;
min-height: 500px;
color: #333;
font-family: courier;
font-size: 10px;
}
p { margin: 0; }
#ecliptic {
top: 50%;
left: 50%;
width: 1px;
height: 1px;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
position: relative;
}
.celestial-body {
border: 1px solid rgba(255,255,255,.5);
border-radius: 100px;
position: absolute;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-box-shadow: 0px 0px 3px 0px rgba(255, 255, 255, 0.75);
-moz-box-shadow: 0px 0px 3px 0px rgba(255, 255, 255, 0.75);
box-shadow: 0px 0px 3px 0px rgba(255, 255, 255, 0.75);
}
#sun {
background: yellow;
}
#earth {
background: lightblue;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment