orrery.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // Orrery.js from Cqoicebordel
  2. // http://www.cqoicebordel.net
  3. // Name, color, angle, x, y
  4. var planets = [["Mercure", "#B87848"],
  5. ["Venus", "#EAD0A5"],
  6. ["Terre", "#619ABA"],
  7. ["Mars", "#B42406"],
  8. ["Jupiter", "#EE9D5F"],
  9. ["Saturne", "#DEC0AD"],
  10. ["Uranus", "#C8EDD7"],
  11. ["Neptune", "#4B89FF"],
  12. ["Pluton", "#A5825A"]];
  13. // Name, color, folder, planetIndex, index, angle, x, y
  14. var moons = [["Lune", "#A9A9A8", "e1", 2, 0],
  15. ["Phobos", "#989898", "m1", 3, 0],
  16. ["Deimos", "#757575", "m2", 3, 1],
  17. ["Io", "#D56E10", "j1", 4, 0],
  18. ["Europe", "#A19879", "j2", 4, 1],
  19. ["Ganymede", "#C9B19C", "j3", 4, 2],
  20. ["Callisto", "#553D3F", "j4", 4, 3],
  21. ["Mimas", "#B9B9B9", "s1", 5, 0],
  22. ["Encelade", "#E3E3E3", "s2", 5, 1],
  23. ["Téthys", "#C8C8C8", "s3", 5, 2],
  24. ["Dioné", "#BCBCBC", "s4", 5, 3],
  25. ["Rhéa", "#D5CFBF", "s5", 5, 4],
  26. ["Titan", "#C09858", "s6", 5, 5],
  27. ["Hypérion","#B4A392", "s7", 5, 6],
  28. ["Japet", "#929383", "s8", 5, 7],
  29. ["Miranda", "#D6C3C4", "u5", 6, 0],
  30. ["Ariel", "#AA9489", "u1", 6, 1],
  31. ["Umbriel", "#F2CF82", "u2", 6, 2],
  32. ["Titania", "#C4A68D", "u3", 6, 3],
  33. ["Obéron", "#BEB6AA", "u4", 6, 4],
  34. ["Triton", "#F5DBA5", "n1", 7, 0],
  35. ["Charon", "#A2917B", "p1", 8, 0],
  36. ["Styx", "#A2917B", "p5", 8, 1],
  37. ["Nix", "#F0C085", "p2", 8, 2],
  38. ["Kerbéros","#BD8871", "p4", 8, 3],
  39. ["Hydre", "#AE7063", "p3", 8, 4]];
  40. // Config
  41. var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
  42. var r = 8;
  43. var rM = 3;
  44. var margin = 50;
  45. var marginMoon = 15;
  46. var width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)-20;
  47. var height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)-20;
  48. var ratio = Math.min(width,height)/190;
  49. var ratioM = Math.min(width,height)/190;
  50. // Get planet angle from the Sun
  51. function getAnglePlanet(p, day){
  52. if (p.Name != "Sun") {
  53. var ec = p.EclipticAngularCoordinates (day);
  54. return ec.longitude;
  55. }
  56. }
  57. function getCSVDate(date){
  58. return date.getUTCFullYear() + "-" + months[date.getUTCMonth()] + "-" + ((date.getUTCDate()<10)?"0"+date.getUTCDate():date.getUTCDate()) + " " + ((date.getUTCHours()<10)?"0"+date.getUTCHours():date.getUTCHours()) + ":00:00";
  59. }
  60. // Calculate display coordinates from angle
  61. function coordinatesPlanet(numberPlanet, angle){
  62. var angleRad = angle*(Math.PI / 180);
  63. return [-(margin+ratio*numberPlanet)*Math.sin(angleRad), -(margin+ratio*numberPlanet)*Math.cos(angleRad)];
  64. }
  65. // Get the angle of a moon from the data stored in the CSVs
  66. function getAngleMoon(data, date, dateCSV){
  67. for(var i=0; i<data.length; i++){
  68. if(data[i][0] == dateCSV){
  69. return [(parseFloat(data[i][1]) + (date.getUTCMinutes() * (parseFloat(data[i+1][1]) - parseFloat(data[i][1])))/60), (parseFloat(data[i][2]) + (date.getUTCMinutes() * (parseFloat(data[i+1][2]) - parseFloat(data[i][2])))/60)];
  70. }
  71. }
  72. }
  73. // Get display coordinates of a moon, based on the coordinates of the parent planet, and the index of the moon
  74. function coordinatesMoon(xPlanet, yPlanet, indexMoon, angle){
  75. var angleRad = angle*(Math.PI / 180);
  76. return [xPlanet-(marginMoon+ratioM*indexMoon)*Math.sin(angleRad), yPlanet-(marginMoon+ratioM*indexMoon)*Math.cos(angleRad)];
  77. }
  78. // Update based on the current date
  79. function update(){
  80. var now = new Date();
  81. update(now);
  82. }
  83. // Update based on the date in the hash
  84. function updateFromHash(){
  85. var date = Date.parse(window.location.hash.substring(1));
  86. if(!isNaN(date)){
  87. update(new Date(date));
  88. }
  89. }
  90. // Change the date to create an animation
  91. function letsPlay(){
  92. var objDate;
  93. if(window.location.hash == "" || window.location.hash === undefined){
  94. objDate = new Date();
  95. }
  96. var date = Date.parse(window.location.hash.substring(1));
  97. if(!isNaN(date)){
  98. date = date + 3600000;
  99. var objDate = new Date(date);
  100. }
  101. window.location.hash = objDate.toISOString();
  102. }
  103. // Update the display
  104. function update(now){
  105. var dateCSV = getCSVDate(now);
  106. var day = Astronomy.DayValue(now);
  107. for (var i in Astronomy.Body) {
  108. planets[i][2] = getAnglePlanet(Astronomy.Body[i], day);
  109. var coord = coordinatesPlanet(i+1, planets[i][2]);
  110. planets[i][3] = coord[0];
  111. planets[i][4] = coord[1];
  112. d3.select("#p"+i)
  113. .attr("cx", planets[i][3])
  114. .attr("cy", planets[i][4]);
  115. d3.select("#titlep"+i).html(planets[i][0] + " - " + planets[i][2]);
  116. }
  117. for (let i=0; i<moons.length; i++){
  118. d3.text("./data/"+moons[i][2]+"/"+now.getUTCFullYear()+"-"+((now.getUTCMonth()+1<10)?"0"+(now.getUTCMonth()+1):(now.getUTCMonth()+1))+".csv", function(text){
  119. var data = d3.csvParseRows(text);
  120. var moonAngle = getAngleMoon(data, now, dateCSV);
  121. moons[i][5] = moonAngle[0];
  122. moons[i][6] = moonAngle[1]
  123. var coord = coordinatesMoon(planets[moons[i][3]][3], planets[moons[i][3]][4], moons[i][4], moons[i][5]);
  124. moons[i][7] = coord[0];
  125. moons[i][8] = coord[1];
  126. d3.select("#m"+i)
  127. .attr("cx", moons[i][7])
  128. .attr("cy", moons[i][8])
  129. .attr("r", rM + (moons[i][6]/40));
  130. d3.select("#titlem"+i).html(moons[i][0] + " - " + moons[i][5] + "x" + moons[i][6]);
  131. });
  132. }
  133. }
  134. // First draw
  135. function firstDraw(now){
  136. var dateCSV = getCSVDate(now);
  137. var day = Astronomy.DayValue(now);
  138. // Main display area
  139. var svg = d3.select("body").append("svg")
  140. .attr("width", width)
  141. .attr("height", height)
  142. .append("g")
  143. .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
  144. .attr("id", "pla");
  145. // Display the Sun
  146. svg.append("svg:image")
  147. .attr('x', -48)
  148. .attr('y', -48)
  149. .attr("xlink:href", "images/sun.png")
  150. .attr("id", "piselsun")
  151. // Display the planets
  152. for (var i in Astronomy.Body) {
  153. planets[i] = planets[i].concat(getAnglePlanet(Astronomy.Body[i], day));
  154. planets[i] = planets[i].concat(coordinatesPlanet(i+1, planets[i][2]));
  155. svg.append("circle")
  156. .attr("cx", 0)
  157. .attr("cy", 0)
  158. .attr("r", ratio*(i+1)+margin)
  159. .attr("fill", "none")
  160. .attr("stroke", "grey");
  161. svg.append("circle")
  162. .attr("cx", planets[i][3])
  163. .attr("cy", planets[i][4])
  164. .attr("id", "p"+i)
  165. .append("svg:title").attr("id", "titlep"+i).html(planets[i][0] + " - " + planets[i][2]);
  166. if (i==4)
  167. {
  168. svg.append("svg:image")
  169. .attr('x', planets[i][3]-10)
  170. .attr('y', planets[i][4]-19)
  171. .attr("xlink:href", "images/"+i+".png")
  172. .attr("id", "pisel"+i)
  173. }
  174. else {
  175. svg.append("svg:image")
  176. .attr('x', planets[i][3]-10)
  177. .attr('y', planets[i][4]-12)
  178. .attr("xlink:href", "images/"+i+".png")
  179. .attr("id", "pisel"+i)
  180. }
  181. }
  182. // Display the moons
  183. for (let i=0; i<moons.length; i++){
  184. d3.text("./data/"+moons[i][2]+"/"+now.getUTCFullYear()+"-"+((now.getUTCMonth()+1<10)?"0"+(now.getUTCMonth()+1):(now.getUTCMonth()+1))+".csv", function(text){
  185. var data = d3.csvParseRows(text);
  186. moons[i] = moons[i].concat(getAngleMoon(data, now, dateCSV));
  187. moons[i] = moons[i].concat(coordinatesMoon(planets[moons[i][3]][3], planets[moons[i][3]][4], moons[i][4], moons[i][5]));
  188. svg.append("circle")
  189. .attr("cx", moons[i][7])
  190. .attr("cy", moons[i][8])
  191. .attr("r", rM + (moons[i][6]/40))
  192. .attr("fill", moons[i][1])
  193. .attr("id", "m"+i)
  194. .append("svg:title").attr("id", "titlem"+i).html(moons[i][0] + " - " + moons[i][5] + "x" + moons[i][6]);
  195. });
  196. }
  197. }
  198. // In animation
  199. var play = false;
  200. // Current date
  201. var now;
  202. if(window.location.hash == "" || window.location.hash === undefined){
  203. now = new Date();
  204. firstDraw(now);
  205. }else{
  206. var date = Date.parse(window.location.hash.substring(1));
  207. if(!isNaN(date)){
  208. now = new Date(date);
  209. }else{
  210. now = new Date();
  211. }
  212. firstDraw(now);
  213. }
  214. // Autoupdates every minutes
  215. var updateID = window.setInterval(update, 60000);
  216. // If animated, this is the setInterval ID
  217. var playID;
  218. // Update when the hash has changed
  219. window.addEventListener("hashchange", updateFromHash, false);
  220. // Play/Pause
  221. document.body.addEventListener('keydown', function(e) {
  222. if (String.fromCharCode(e.keyCode).toLowerCase() == 'p' && !play) {
  223. clearInterval(updateID);
  224. playID = window.setInterval(letsPlay, 1000);
  225. play = true;
  226. }else if (String.fromCharCode(e.keyCode).toLowerCase() == 'p' && play){
  227. clearInterval(playID);
  228. play = false;
  229. }
  230. });