Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active October 23, 2019 21:40
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 nitaku/9314561 to your computer and use it in GitHub Desktop.
Save nitaku/9314561 to your computer and use it in GitHub Desktop.
Clock
LAT = 43.62
LONG = 10.63
DAYS = ['Dom','Lun','Mar','Mer','Gio','Ven','Sab']
MONTHS = ['Gen','Feb','Mar','Apr','Mag','Giu','Lug','Ago','Set','Ott','Nov','Dic']
### add a zero in front of numbers < 10 ###
pad_time = (i) -> if i<10 then "0#{i}" else i
### add methods to Date to check if DST is in effect ###
### from http://stackoverflow.com/questions/11887934/check-if-daylight-saving-time-is-in-effect-and-if-it-is-for-how-many-hours ###
Date.prototype.stdTimezoneOffset = () ->
jan = new Date(this.getFullYear(), 0, 1)
jul = new Date(this.getFullYear(), 6, 1)
return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset())
Date.prototype.dst = () -> this.getTimezoneOffset() < this.stdTimezoneOffset()
### SEASONS ###
get_season = (now) ->
seasons = Date.getSeasons now.getFullYear()
if now < seasons[1]
return 'winter'
else if now < seasons[2]
return 'spring'
else if now < seasons[3]
return 'summer'
else if now < seasons[4]
return 'fall'
else
return 'winter'
### define a scale for SUN and MOON altitude ###
altitude = d3.scale.linear()
.domain([-1,1])
.range([600,0])
### DAY/NIGHT ###
get_day_night = (now) ->
times = SunCalc.getTimes(now, LAT, LONG)
if now < times.sunriseEnd
return 'night'
else if now < times.dusk
return 'day'
else
return 'night'
### update every 0.5 seconds ###
last_seconds = -1
last_sep = false
last_day_night = null
update_05_secs = () ->
### CLOCK ###
now = new Date()
h = now.getHours()
m = now.getMinutes()
s = now.getSeconds()
h = pad_time(h)
m = pad_time(m)
s = pad_time(s)
if s != last_seconds
last_sep = not last_sep
last_seconds = s
clock_string = h
if last_sep
clock_string += ':'
else
clock_string += ' '
clock_string += m
d3.select('#clock')
.text(clock_string)
### DAYLIGHT SAVINGS TIME ###
d3.select('#dst')
.text(if now.dst() then "LEG" else "SOL")
### CALENDAR ###
d3.select('#calendar')
.text("#{DAYS[now.getDay()]} #{now.getDate()} #{MONTHS[now.getMonth()]} #{now.getFullYear()}")
### SEASONS ###
d3.select('#season')
.text switch get_season(now)
when 'winter' then 'inverno'
when 'spring' then 'primavera'
when 'summer' then 'estate'
when 'fall' then 'autunno'
### NETWORK status ###
d3.select('#router')
.classed('ok', navigator.onLine) # FIXME check by ping
d3.select('#wifirouter')
.classed('ok', true) # FIXME check by ping
### SUN and MOON simulation ###
sun_alt = Math.sin SunCalc.getPosition(now, LAT, LONG).altitude
moon_alt = Math.sin SunCalc.getMoonPosition(now, LAT, LONG).altitude
moon_phase = SunCalc.getMoonIllumination(now)
d3.select('#sun')
.attr('y', altitude(sun_alt))
.attr('fill','#FFF268')
d3.select('#moon')
.attr('y', altitude(moon_alt))
.attr('fill','#BDDBFD')
d3.select('#moon_symbol > path')
.attr('d', if moon_phase.angle > 0 then "M0 30 A30 30 0 1 1 0 -30 A#{60*Math.abs(moon_phase.fraction-0.5)} 30 0 1 #{if moon_phase.fraction > 0.5 then 1 else 0} 0 30" else "M0 30 A#{60*Math.abs(moon_phase.fraction-0.5)} 30 0 1 #{if moon_phase.fraction > 0.5 then 1 else 0} 0 -30 A30 30 0 1 1 0 30")
### NIGHT and DAY ###
day_night = get_day_night(now)
if day_night != last_day_night
if day_night is 'day'
d3.select('body')
.transition().duration(3000)
.style('background', '#00BCD1')
d3.select('#land')
.transition().duration(3000)
.attr('fill', '#ABEC72')
else if day_night is 'night'
d3.select('body')
.transition().duration(3000)
.style('background', '#434367')
d3.select('#land')
.transition().duration(3000)
.attr('fill', '#0A8690')
last_day_night = day_night
setTimeout((()->update_05_secs()),500)
### update every 10 minutes ###
update_10_min = () ->
### WHEATER from OpenWeatherMap ###
d3.json 'http://api.openweathermap.org/data/2.5/weather?q=Ponsacco,it&APPID=eaecf85a68297fd2c57d209840cb81dc&lang=it', (data) ->
if not data?
return
d3.select('#temperature')
.text("#{Math.round(data.main.temp - 273.15)}°") # temp is in Kelvin degrees
d3.select('#humidity')
.text("#{Math.round(data.main.humidity)}%")
if data.weather? and data.weather[0]?
# console.debug data.weather[0].icon
status = +data.weather[0].icon[0...2]
### set haze visibility ###
if status < 4
d3.select('#haze')
.transition().duration(3000)
.attr('fill-opacity', 0)
else
d3.select('#haze')
.transition().duration(3000)
.attr('fill-opacity', 0.5)
### set clouds visibility ###
if status < 2 or status is 50
d3.select('#clouds')
.transition().duration(3000)
.attr('opacity', 0)
else
d3.select('#clouds')
.transition().duration(3000)
.attr('opacity', 1)
### set more clouds visibility ###
if status < 3 or status is 50
d3.select('#more_clouds')
.transition().duration(3000)
.attr('opacity', 0)
else
d3.select('#more_clouds')
.transition().duration(3000)
.attr('opacity', 1)
# if data.weather[0].icon[2] is 'd'
# day()
# else
# night()
# .attr('xlink:href', "http://openweathermap.org/img/w/#{data.weather[0].icon}.png")
# else
# d3.select('#weather_icon')
# .attr('xlink:href', '')
setTimeout((()->update_10_min()),600000) # OpenWeatherMap time limit is 10 minutes
update_05_secs()
update_10_min()
html, body {
padding: 0;
margin: 0;
overflow: hidden;
width: 1024px;
height: 748px;
background: gray;
}
@font-face {
font-family: "DroidSansMono";
src: url("DroidSansMono.ttf");
}
.tile {
font-family: "DroidSansMono";
fill: white;
}
#calendar {
font-size: 40px;
font-family: "Georgia";
text-anchor: middle;
}
#season {
text-transform: uppercase;
font-weight: bold;
text-anchor: middle;
}
#clock {
font-size: 120px;
text-anchor: middle;
}
#dst {
font-size: 16px;
font-weight: bold;
text-anchor: end;
}
#temperature {
font-size: 60px;
text-anchor: end;
}
#humidity {
font-size: 40px;
text-anchor: end;
}
/* statuses */
.status .icon {
fill: red;
}
.status.ok .icon {
fill: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Clock</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="suncalc.js"></script>
<script src="seasons.js"></script>
</head>
<body>
<svg width="1024" height="748">
<defs>
<symbol id="sun_symbol" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="33.715"/>
<g>
<polygon points="50,5 47.275,13.334 52.725,13.334 "/>
<polygon points="50,95 47.275,86.667 52.725,86.667 "/>
</g>
<g>
<polygon points="95,50 86.666,47.276 86.666,52.725 "/>
<polygon points="5,50 13.333,47.276 13.333,52.725 "/>
</g>
<g>
<polygon points="18.18,18.18 22.146,26 26,22.146 "/>
<polygon points="81.82,81.82 74.002,77.854 77.854,74 "/>
</g>
<g>
<polygon points="81.82,18.18 74.002,22.146 77.854,25.999 "/>
<polygon points="18.18,81.82 22.146,74 26,77.854 "/>
</g>
<g>
<polygon points="32.961,8.351 33.595,17.095 38.638,15.032 "/>
<polygon points="67.039,91.649 61.361,84.968 66.405,82.904 "/>
</g>
<g>
<polygon points="91.649,32.961 82.905,33.595 84.969,38.638 "/>
<polygon points="8.351,67.039 15.032,61.362 17.096,66.405 "/>
</g>
<g>
<polygon points="8.501,32.598 15.133,38.333 17.239,33.308 "/>
<polygon points="91.499,67.402 82.76,66.691 84.867,61.668 "/>
</g>
<g>
<polygon points="67.402,8.501 61.668,15.133 66.691,17.24 "/>
<polygon points="32.598,91.499 33.308,82.761 38.333,84.868 "/>
</g>
</symbol>
<symbol id="moon_symbol" viewBox="-34 -34 68 68">
<circle r="30" style="fill: black; fill-opacity: 0.1;"/>
<path d="M0 30 A30 30 0 1 1 0 -30 A30 30 0 1 1 0 30"/>
</symbol>
<symbol id="cloud_symbol" viewBox="0 0 100 100">
<path d="M642.02-364.11c-0.772,0-1.519,0.114-2.229,0.313c-0.17-6.744-5.679-12.162-12.464-12.162 c-4.368,0-8.201,2.251-10.428,5.65c-1.38-2.61-4.117-4.393-7.275-4.393c-2.621,0-4.95,1.229-6.456,3.139 c-2.865-6.496-9.357-11.031-16.913-11.031c-8.99,0-16.479,6.42-18.138,14.926c-0.937-0.248-1.911-0.393-2.925-0.393 c-6.312,0-11.427,5.116-11.427,11.427c0,0.907,0.117,1.787,0.317,2.634h95.921c0.146-0.609,0.229-1.243,0.229-1.896 C650.233-360.433,646.556-364.11,642.02-364.11z"/>
<path d="M90.02,48.188c-0.771,0-1.518,0.113-2.229,0.312c-0.17-6.744-5.678-12.162-12.463-12.162 c-4.369,0-8.201,2.251-10.428,5.65c-1.381-2.61-4.117-4.393-7.275-4.393c-2.621,0-4.951,1.229-6.457,3.139 c-2.865-6.496-9.357-11.031-16.913-11.031c-8.99,0-16.479,6.42-18.138,14.926c-0.937-0.248-1.911-0.393-2.925-0.393 c-6.312,0-11.427,5.116-11.427,11.427c0,0.907,0.117,1.786,0.317,2.634h95.92c0.146-0.609,0.23-1.243,0.23-1.896 C98.234,51.863,94.557,48.188,90.02,48.188z"/>
</symbol>
</defs>
<use id="sun" xlink:href="#sun_symbol" x="750" width="140" height="140"/>
<use id="moon" xlink:href="#moon_symbol" x="148" width="100" height="100"/>
<rect id="land" x="0" y="300" width="1024" height="448" fill="white"/>
<rect id="haze" x="0" y="0" width="1024" height="748" fill="#888" fill-opacity="0"/>
<g id="clouds" fill="white" fill-opacity="0.3" opacity="0">
<use xlink:href="#cloud_symbol" x="800" y="0" width="100" height="100"/>
<use xlink:href="#cloud_symbol" x="40" y="50" width="200" height="200"/>
<use xlink:href="#cloud_symbol" x="360" y="180" width="140" height="140"/>
</g>
<g id="more_clouds" fill="white" fill-opacity="0.3" opacity="0">
<use xlink:href="#cloud_symbol" x="240" y="-10" width="80" height="80"/>
<use xlink:href="#cloud_symbol" x="10" y="84" width="160" height="160"/>
<use xlink:href="#cloud_symbol" x="110" y="180" width="90" height="90"/>
<use xlink:href="#cloud_symbol" x="710" y="60" width="280" height="280"/>
<use xlink:href="#cloud_symbol" x="894" y="118" width="120" height="120"/>
<use xlink:href="#cloud_symbol" x="590" y="-184" width="500" height="500"/>
</g>
<g transform="translate(0,25)">
<line stroke="black" stroke-width="1" x1="0" x2="10" y1="0" y2="0"/>
<circle r="3" cx="10"/>
</g>
<a xlink:href="http://192.168.0.1" xlink:show="new" target="_blank">
<g id="router" class="status" transform="translate(35,25)">
<path class="icon" transform="scale(0.5) translate(-50,-50)" d="M49.249,17.499c-17.782,0-32.25,14.469-32.25,32.25c0,17.784,14.468,32.252,32.25,32.252 c17.78,0,32.251-14.469,32.251-32.252C81.5,31.968,67.029,17.499,49.249,17.499z M74.211,62.84c-0.006,0-0.012-0.006-0.018-0.006 h-6.654c0.986-3.357,1.666-7.1,1.852-11.121h7.979C77.086,55.717,75.992,59.461,74.211,62.84z M51.381,77.855V66.762h10.584 c-2.064,4.939-4.484,8.549-5.855,10.371C54.58,77.52,53.002,77.732,51.381,77.855z M42.543,77.182 c-1.364-1.799-3.809-5.432-5.896-10.42h10.808v11.127C45.774,77.781,44.131,77.57,42.543,77.182z M24.283,62.84 c-1.778-3.379-2.878-7.123-3.161-11.127h8.094c0.186,4.021,0.866,7.764,1.852,11.121h-6.763 C24.296,62.834,24.291,62.84,24.283,62.84z M24.469,36.313c0.019,0.003,0.032,0.012,0.048,0.012h6.681 c-1.24,3.988-1.821,7.815-1.971,11.462h-8.105C21.413,43.644,22.582,39.78,24.469,36.313z M47.456,21.606v10.792H36.892 c1.489-3.33,3.466-6.745,6.065-10.211C44.413,21.853,45.924,21.705,47.456,21.606z M55.686,22.231 c2.584,3.453,4.549,6.851,6.031,10.167H51.381V21.643C52.848,21.751,54.293,21.905,55.686,22.231z M63.246,36.325 c1.357,3.996,2.006,7.828,2.174,11.462H51.381V36.325H63.246z M47.456,36.325v11.462H33.187c0.17-3.634,0.819-7.466,2.18-11.462 H47.456z M33.182,51.713h14.274v11.121H35.202C34.143,59.516,33.381,55.783,33.182,51.713z M51.381,62.834V51.713h14.045 c-0.203,4.07-0.959,7.803-2.02,11.121H51.381z M69.379,47.787c-0.146-3.647-0.729-7.474-1.971-11.462h6.568 c0.014,0,0.031-0.009,0.049-0.012c1.883,3.467,3.055,7.331,3.344,11.474H69.379z M71.465,32.398h-5.52 c-1.045-2.558-2.316-5.154-3.941-7.796C65.711,26.494,68.92,29.147,71.465,32.398z M36.675,24.501 c-1.651,2.678-2.955,5.307-4.012,7.897h-5.635C29.616,29.093,32.892,26.396,36.675,24.501z M26.749,66.762h5.641 c1.202,3.137,2.576,5.816,3.854,8.002C32.514,72.814,29.276,70.098,26.749,66.762z M62.414,74.668 c1.264-2.168,2.619-4.813,3.801-7.906h5.525C69.254,70.049,66.078,72.725,62.414,74.668z"/>
<circle r="20" fill="transparent"/>
</g>
</a>
<g transform="translate(0,730)">
<line stroke="black" stroke-width="1" x1="0" x2="10" y1="0" y2="0"/>
<circle r="3" cx="10"/>
</g>
<a xlink:href="http://192.168.0.4" xlink:show="new" target="_blank">
<g id="wifirouter" class="status" transform="translate(33,720)">
<g transform="scale(0.15) translate(-125,-100)">
<path class="icon" d="M137.085,39.439c-48.16,0-91.761,19.869-123.06,51.829l17.67,17.669c26.77-27.434,64.121-44.497,105.39-44.497 c41.268,0,78.618,17.063,105.39,44.497l17.67-17.669C228.846,59.307,185.245,39.439,137.085,39.439z"/>
<path class="icon" d="M137.085,79.624c-37.081,0-70.638,15.361-94.658,40.046l17.669,17.669c19.492-20.159,46.801-32.715,76.989-32.715 s57.497,12.556,76.989,32.715l17.668-17.669C207.723,94.985,174.166,79.624,137.085,79.624z"/>
<path class="icon" d="M137.085,121.341c-25.58,0-48.71,10.681-65.173,27.813l17.684,17.685c11.932-12.608,28.802-20.498,47.489-20.498 s35.558,7.89,47.488,20.497l17.685-17.684C185.795,132.021,162.664,121.341,137.085,121.341z"/>
<circle class="icon" cx="136.754" cy="198.076" r="29.448"/>
</g>
</g>
</a>
<text id="calendar" class="tile" x="512" y="10" dy="1em"/>
<text id="season" class="tile" x="512" y="60" dy="1em"/>
<text id="clock" class="tile" x="512" y="160" dy=".35em"/>
<text id="dst" class="tile" x="670" y="240" dy=".35em"/>
<text id="temperature" class="tile" x="1014" y="10" dy="1em"/>
<text id="humidity" class="tile" x="1004" y="90" dy="1em"/>
</svg>
</body>
<script src="index.js"></script>
</html>
(function() {
var DAYS, LAT, LONG, MONTHS, altitude, get_day_night, get_season, last_day_night, last_seconds, last_sep, pad_time, update_05_secs, update_10_min;
LAT = 43.62;
LONG = 10.63;
DAYS = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'];
MONTHS = ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'];
/* add a zero in front of numbers < 10
*/
pad_time = function(i) {
if (i < 10) {
return "0" + i;
} else {
return i;
}
};
/* add methods to Date to check if DST is in effect
*/
/* from http://stackoverflow.com/questions/11887934/check-if-daylight-saving-time-is-in-effect-and-if-it-is-for-how-many-hours
*/
Date.prototype.stdTimezoneOffset = function() {
var jan, jul;
jan = new Date(this.getFullYear(), 0, 1);
jul = new Date(this.getFullYear(), 6, 1);
return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
};
Date.prototype.dst = function() {
return this.getTimezoneOffset() < this.stdTimezoneOffset();
};
/* SEASONS
*/
get_season = function(now) {
var seasons;
seasons = Date.getSeasons(now.getFullYear());
if (now < seasons[1]) {
return 'winter';
} else if (now < seasons[2]) {
return 'spring';
} else if (now < seasons[3]) {
return 'summer';
} else if (now < seasons[4]) {
return 'fall';
} else {
return 'winter';
}
};
/* define a scale for SUN and MOON altitude
*/
altitude = d3.scale.linear().domain([-1, 1]).range([600, 0]);
/* DAY/NIGHT
*/
get_day_night = function(now) {
var times;
times = SunCalc.getTimes(now, LAT, LONG);
if (now < times.sunriseEnd) {
return 'night';
} else if (now < times.dusk) {
return 'day';
} else {
return 'night';
}
};
/* update every 0.5 seconds
*/
last_seconds = -1;
last_sep = false;
last_day_night = null;
update_05_secs = function() {
/* CLOCK
*/
var clock_string, day_night, h, m, moon_alt, moon_phase, now, s, sun_alt;
now = new Date();
h = now.getHours();
m = now.getMinutes();
s = now.getSeconds();
h = pad_time(h);
m = pad_time(m);
s = pad_time(s);
if (s !== last_seconds) {
last_sep = !last_sep;
last_seconds = s;
}
clock_string = h;
if (last_sep) {
clock_string += ':';
} else {
clock_string += ' ';
}
clock_string += m;
d3.select('#clock').text(clock_string);
/* DAYLIGHT SAVINGS TIME
*/
d3.select('#dst').text(now.dst() ? "LEG" : "SOL");
/* CALENDAR
*/
d3.select('#calendar').text("" + DAYS[now.getDay()] + " " + (now.getDate()) + " " + MONTHS[now.getMonth()] + " " + (now.getFullYear()));
/* SEASONS
*/
d3.select('#season').text((function() {
switch (get_season(now)) {
case 'winter':
return 'inverno';
case 'spring':
return 'primavera';
case 'summer':
return 'estate';
case 'fall':
return 'autunno';
}
})());
/* NETWORK status
*/
d3.select('#router').classed('ok', navigator.onLine);
d3.select('#wifirouter').classed('ok', true);
/* SUN and MOON simulation
*/
sun_alt = Math.sin(SunCalc.getPosition(now, LAT, LONG).altitude);
moon_alt = Math.sin(SunCalc.getMoonPosition(now, LAT, LONG).altitude);
moon_phase = SunCalc.getMoonIllumination(now);
d3.select('#sun').attr('y', altitude(sun_alt)).attr('fill', '#FFF268');
d3.select('#moon').attr('y', altitude(moon_alt)).attr('fill', '#BDDBFD');
d3.select('#moon_symbol > path').attr('d', moon_phase.angle > 0 ? "M0 30 A30 30 0 1 1 0 -30 A" + (60 * Math.abs(moon_phase.fraction - 0.5)) + " 30 0 1 " + (moon_phase.fraction > 0.5 ? 1 : 0) + " 0 30" : "M0 30 A" + (60 * Math.abs(moon_phase.fraction - 0.5)) + " 30 0 1 " + (moon_phase.fraction > 0.5 ? 1 : 0) + " 0 -30 A30 30 0 1 1 0 30");
/* NIGHT and DAY
*/
day_night = get_day_night(now);
if (day_night !== last_day_night) {
if (day_night === 'day') {
d3.select('body').transition().duration(3000).style('background', '#00BCD1');
d3.select('#land').transition().duration(3000).attr('fill', '#ABEC72');
} else if (day_night === 'night') {
d3.select('body').transition().duration(3000).style('background', '#434367');
d3.select('#land').transition().duration(3000).attr('fill', '#0A8690');
}
last_day_night = day_night;
}
return setTimeout((function() {
return update_05_secs();
}), 500);
};
/* update every 10 minutes
*/
update_10_min = function() {
/* WHEATER from OpenWeatherMap
*/ d3.json('http://api.openweathermap.org/data/2.5/weather?q=Ponsacco,it&APPID=eaecf85a68297fd2c57d209840cb81dc&lang=it', function(data) {
var status;
if (!(data != null)) return;
d3.select('#temperature').text("" + (Math.round(data.main.temp - 273.15)) + "°");
d3.select('#humidity').text("" + (Math.round(data.main.humidity)) + "%");
if ((data.weather != null) && (data.weather[0] != null)) {
status = +data.weather[0].icon.slice(0, 2);
/* set haze visibility
*/
if (status < 4) {
d3.select('#haze').transition().duration(3000).attr('fill-opacity', 0);
} else {
d3.select('#haze').transition().duration(3000).attr('fill-opacity', 0.5);
}
/* set clouds visibility
*/
if (status < 2 || status === 50) {
d3.select('#clouds').transition().duration(3000).attr('opacity', 0);
} else {
d3.select('#clouds').transition().duration(3000).attr('opacity', 1);
}
/* set more clouds visibility
*/
if (status < 3 || status === 50) {
return d3.select('#more_clouds').transition().duration(3000).attr('opacity', 0);
} else {
return d3.select('#more_clouds').transition().duration(3000).attr('opacity', 1);
}
}
});
return setTimeout((function() {
return update_10_min();
}), 600000);
};
update_05_secs();
update_10_min();
}).call(this);
Date.fromJulian= function(j){
j= (+j)+(30.0/(24*60*60));
var A= Date.julianArray(j, true);
return new Date(Date.UTC.apply(Date, A));
}
Date.julianArray= function(j, n){
var F= Math.floor;
var j2, JA, a, b, c, d, e, f, g, h, z;
j+= .5;
j2= (j-F(j))*86400.0;
z= F(j);
f= j-z;
if(z< 2299161) a= z;
else{
g= F((z-1867216.25)/36524.25);
a= z+1+g-F(g/4);
}
b= a+1524;
c= F((b-122.1)/365.25);
d= F(365.25*c);
e= F((b-d)/30.6001);
h= F((e< 14)? (e-1): (e-13));
var JA= [F((h> 2)? (c-4716): (c-4715)),
h-1, F(b-d-F(30.6001*e)+f)];
var JB= [F(j2/3600), F((j2/60)%60), Math.round(j2%60)];
JA= JA.concat(JB);
if(typeof n== 'number') return JA.slice(0, n);
return JA;
}
Date.getSeasons= function(y, wch){
y= y || new Date().getFullYear();
if(y<1000 || y> 3000) throw y+' is out of range';
var Y1= (y-2000)/1000, Y2= Y1*Y1, Y3= Y2*Y1, Y4= Y3*Y1;
var jd, t, w, d, est= 0, i= 0, Cos= Math.degCos, A= [y],
e1= [485, 203, 199, 182, 156, 136, 77, 74, 70, 58, 52, 50, 45, 44, 29, 18, 17, 16, 14, 12, 12, 12, 9, 8],
e2= [324.96, 337.23, 342.08, 27.85, 73.14, 171.52, 222.54, 296.72, 243.58, 119.81, 297.17, 21.02,
247.54, 325.15, 60.93, 155.12, 288.79, 198.04, 199.76, 95.39, 287.11, 320.81, 227.73, 15.45],
e3= [1934.136, 32964.467, 20.186, 445267.112, 45036.886, 22518.443,
65928.934, 3034.906, 9037.513, 33718.147, 150.678, 2281.226,
29929.562, 31555.956, 4443.417, 67555.328, 4562.452, 62894.029,
31436.921, 14577.848, 31931.756, 34777.259, 1222.114, 16859.074];
while(i< 4){
switch(i){
case 0: jd= 2451623.80984 + 365242.37404*Y1 + 0.05169*Y2 - 0.00411*Y3 - 0.00057*Y4;
break;
case 1: jd= 2451716.56767 + 365241.62603*Y1 + 0.00325*Y2+ 0.00888*Y3 - 0.00030*Y4;
break;
case 2: jd= 2451810.21715 + 365242.01767*Y1 - 0.11575*Y2 + 0.00337*Y3 + 0.00078*Y4;
break;
case 3: jd= 2451900.05952 + 365242.74049*Y1 - 0.06223*Y2 - 0.00823*Y3 + 0.00032*Y4;
break;
}
var t= (jd- 2451545.0)/36525,
w= 35999.373*t - 2.47,
d= 1 + 0.0334*Cos(w)+ 0.0007*Cos(2*w);
est= 0;
for(var n= 0; n<24; n++){
est += e1[n]*Cos(e2[n]+(e3[n]*t));
}
jd+= (0.00001*est)/d;
A[++i]= Date.fromJulian(jd);
}
return wch && A[wch]? A[wch]: A;
}
Math.degRad= function(d){
return (d*Math.PI)/180.0
}
Math.degSin= function(d){
return Math.sin(Math.degRad(d))
}
Math.degCos= function(d){
return Math.cos(Math.degRad(d))
}
/*
(c) 2011-2014, Vladimir Agafonkin
SunCalc is a JavaScript library for calculating sun/mooon position and light phases.
https://github.com/mourner/suncalc
*/
(function () { "use strict";
// shortcuts for easier to read formulas
var PI = Math.PI,
sin = Math.sin,
cos = Math.cos,
tan = Math.tan,
asin = Math.asin,
atan = Math.atan2,
acos = Math.acos,
rad = PI / 180;
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
// date/time constants and conversions
var dayMs = 1000 * 60 * 60 * 24,
J1970 = 2440588,
J2000 = 2451545;
function toJulian(date) {
return date.valueOf() / dayMs - 0.5 + J1970;
}
function fromJulian(j) {
return new Date((j + 0.5 - J1970) * dayMs);
}
function toDays(date) {
return toJulian(date) - J2000;
}
// general calculations for position
var e = rad * 23.4397; // obliquity of the Earth
function getRightAscension(l, b) {
return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));
}
function getDeclination(l, b) {
return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));
}
function getAzimuth(H, phi, dec) {
return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi));
}
function getAltitude(H, phi, dec) {
return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));
}
function getSiderealTime(d, lw) {
return rad * (280.16 + 360.9856235 * d) - lw;
}
// general sun calculations
function getSolarMeanAnomaly(d) {
return rad * (357.5291 + 0.98560028 * d);
}
function getEquationOfCenter(M) {
return rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M));
}
function getEclipticLongitude(M, C) {
var P = rad * 102.9372; // perihelion of the Earth
return M + C + P + PI;
}
function getSunCoords(d) {
var M = getSolarMeanAnomaly(d),
C = getEquationOfCenter(M),
L = getEclipticLongitude(M, C);
return {
dec: getDeclination(L, 0),
ra: getRightAscension(L, 0)
};
}
var SunCalc = {};
// calculates sun position for a given date and latitude/longitude
SunCalc.getPosition = function (date, lat, lng) {
var lw = rad * -lng,
phi = rad * lat,
d = toDays(date),
c = getSunCoords(d),
H = getSiderealTime(d, lw) - c.ra;
return {
azimuth: getAzimuth(H, phi, c.dec),
altitude: getAltitude(H, phi, c.dec)
};
};
// sun times configuration (angle, morning name, evening name)
var times = [
[-0.83, 'sunrise', 'sunset' ],
[ -0.3, 'sunriseEnd', 'sunsetStart' ],
[ -6, 'dawn', 'dusk' ],
[ -12, 'nauticalDawn', 'nauticalDusk'],
[ -18, 'nightEnd', 'night' ],
[ 6, 'goldenHourEnd', 'goldenHour' ]
];
// adds a custom time to the times config
SunCalc.addTime = function (angle, riseName, setName) {
times.push([angle, riseName, setName]);
};
// calculations for sun times
var J0 = 0.0009;
function getJulianCycle(d, lw) {
return Math.round(d - J0 - lw / (2 * PI));
}
function getApproxTransit(Ht, lw, n) {
return J0 + (Ht + lw) / (2 * PI) + n;
}
function getSolarTransitJ(ds, M, L) {
return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L);
}
function getHourAngle(h, phi, d) {
return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d)));
}
// calculates sun times for a given date and latitude/longitude
SunCalc.getTimes = function (date, lat, lng) {
var lw = rad * -lng,
phi = rad * lat,
d = toDays(date),
n = getJulianCycle(d, lw),
ds = getApproxTransit(0, lw, n),
M = getSolarMeanAnomaly(ds),
C = getEquationOfCenter(M),
L = getEclipticLongitude(M, C),
dec = getDeclination(L, 0),
Jnoon = getSolarTransitJ(ds, M, L);
// returns set time for the given sun altitude
function getSetJ(h) {
var w = getHourAngle(h, phi, dec),
a = getApproxTransit(w, lw, n);
return getSolarTransitJ(a, M, L);
}
var result = {
solarNoon: fromJulian(Jnoon),
nadir: fromJulian(Jnoon - 0.5)
};
var i, len, time, angle, morningName, eveningName, Jset, Jrise;
for (i = 0, len = times.length; i < len; i += 1) {
time = times[i];
Jset = getSetJ(time[0] * rad);
Jrise = Jnoon - (Jset - Jnoon);
result[time[1]] = fromJulian(Jrise);
result[time[2]] = fromJulian(Jset);
}
return result;
};
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
function getMoonCoords(d) { // geocentric ecliptic coordinates of the moon
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
M = rad * (134.963 + 13.064993 * d), // mean anomaly
F = rad * (93.272 + 13.229350 * d), // mean distance
l = L + rad * 6.289 * sin(M), // longitude
b = rad * 5.128 * sin(F), // latitude
dt = 385001 - 20905 * cos(M); // distance to the moon in km
return {
ra: getRightAscension(l, b),
dec: getDeclination(l, b),
dist: dt
};
}
SunCalc.getMoonPosition = function (date, lat, lng) {
var lw = rad * -lng,
phi = rad * lat,
d = toDays(date),
c = getMoonCoords(d),
H = getSiderealTime(d, lw) - c.ra,
h = getAltitude(H, phi, c.dec);
// altitude correction for refraction
h = h + rad * 0.017 / tan(h + rad * 10.26 / (h + rad * 5.10));
return {
azimuth: getAzimuth(H, phi, c.dec),
altitude: h,
distance: c.dist
};
};
// calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus
// (Willmann-Bell, Richmond) 1998.
SunCalc.getMoonIllumination = function (date) {
var d = toDays(date),
s = getSunCoords(d),
m = getMoonCoords(d),
sdist = 149598000, // distance from Earth to Sun in km
phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)),
inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi));
return {
fraction: (1 + cos(inc)) / 2,
angle: atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec)
- cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra))
};
};
// export as AMD module / Node module / browser variable
if (typeof define === 'function' && define.amd) {
define(SunCalc);
} else if (typeof module !== 'undefined') {
module.exports = SunCalc;
} else {
window.SunCalc = SunCalc;
}
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment