|
|
|
|
|
|
|
// utilities function used for both the watch and the calendar
|
|
|
|
|
|
|
|
// MOONPHASES PICTO
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
//shapes of the moon from north hemispheres
|
|
|
|
//otherwise the picto are left-right inversed (and at the equator the crescent are in the bottom-top direction)
|
|
|
|
const MOONPHASES = [
|
|
|
|
{ name_en: 'new moon', //not visible: not in nightsky, and in daysky it's the hidden side that's light up by the sun
|
|
|
|
name_fr: 'nouvelle lune',
|
|
|
|
name_nl: 'nieuwe maan',
|
|
|
|
name_es: 'luna nueva',
|
|
|
|
picto: '🌑',
|
|
|
|
},
|
|
|
|
{ name_en: 'waxing crescent', //in daysky, but a bit in the west: from late morning to post-dusk, not in nightsky
|
|
|
|
name_fr: 'premier croissant',
|
|
|
|
name_nl: 'jonge maansikkel',
|
|
|
|
name_es: 'creciente cóncava',
|
|
|
|
picto: '🌒',
|
|
|
|
},
|
|
|
|
{ name_en: 'first quarter', //at the west intersection of night and day skies -> begin to appear in night: afternoon to early evening
|
|
|
|
name_fr: 'premier quartier',
|
|
|
|
name_nl: 'eerste kwartier',
|
|
|
|
name_es: 'cuarto creciente',
|
|
|
|
picto: '🌓',
|
|
|
|
},
|
|
|
|
{ name_en: 'waxing gibbous', //in the nightsky, but a bit in the west: from late afternoon to most of the night
|
|
|
|
name_fr: 'gibbeuse croissante',
|
|
|
|
name_nl: 'wassende maan',
|
|
|
|
name_es: 'creciente gibosa',
|
|
|
|
picto: '🌔',
|
|
|
|
},
|
|
|
|
{ name_en: 'full moon', //all night: sunset to sunrise
|
|
|
|
name_fr: 'pleine lune',
|
|
|
|
name_nl: 'volle maan',
|
|
|
|
name_es: 'luna llena',
|
|
|
|
picto: '🌕',
|
|
|
|
},
|
|
|
|
{ name_en: 'waning gibbous', //in the nightsky, but a bit in the east: most of the night to early morning
|
|
|
|
name_fr: 'gibbeuse décroissante',
|
|
|
|
name_nl: 'krimpende maan',
|
|
|
|
name_es: 'menguante gibosa',
|
|
|
|
picto: '🌖',
|
|
|
|
},
|
|
|
|
{ name_en: 'last quarter', //at the east intersection of night and day skies -> begin to appear in day: late night to morning
|
|
|
|
name_fr: 'dernier quartier',
|
|
|
|
name_nl: 'laatste kwartier',
|
|
|
|
name_es: 'cuarto menguante',
|
|
|
|
picto: '🌗',
|
|
|
|
},
|
|
|
|
{ name_en: 'waning crescent', //in daysky, but a bit in the east: from pre-dawn to early afternoon, not in nightsky
|
|
|
|
name_fr: 'dernier croissant',
|
|
|
|
name_nl: 'krimpende maansikkel',
|
|
|
|
name_es: 'menguante cóncava',
|
|
|
|
picto: '🌘',
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
function getLocalFromURL(){
|
|
|
|
let local = "";
|
|
|
|
let url = window.location.href;
|
|
|
|
let filename = url.split("/").pop().split(".")[0];
|
|
|
|
let lang_split = filename.split("_");
|
|
|
|
|
|
|
|
if (lang_split.length == 1){
|
|
|
|
local = "en-gb";
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if (lang_split[1] == "fr"){
|
|
|
|
local = "fr-be";
|
|
|
|
}
|
|
|
|
else if (lang_split[1] == "nl"){
|
|
|
|
local = "nl-be";
|
|
|
|
}
|
|
|
|
else if (lang_split[1] == "es"){
|
|
|
|
local = "es-es";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return local;
|
|
|
|
}
|
|
|
|
|
|
|
|
// JS DATE FORMATING
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
function format_date_time(date){
|
|
|
|
// format date object everywhere the same on the website
|
|
|
|
|
|
|
|
formated_date = {}
|
|
|
|
|
|
|
|
formated_date['day'] = new Intl.DateTimeFormat('en-GB', {
|
|
|
|
weekday: 'long'
|
|
|
|
}).format(date);
|
|
|
|
|
|
|
|
// formated_date['date'] = new Intl.DateTimeFormat('fr-BE', {
|
|
|
|
// day: 'numeric',
|
|
|
|
// month: 'numeric',
|
|
|
|
// year: 'numeric'
|
|
|
|
// }).format(date);
|
|
|
|
|
|
|
|
formated_date['date'] = {
|
|
|
|
day: ('0' + date.getDate()).slice(-2),
|
|
|
|
month: ('0' + String(date.getMonth()+1)).slice(-2),
|
|
|
|
year: date.getFullYear().toString().slice(-2)
|
|
|
|
}
|
|
|
|
formated_date['date'] = Object.values(formated_date['date']).join(".");
|
|
|
|
|
|
|
|
formated_date['time'] = new Intl.DateTimeFormat('fr-BE', {
|
|
|
|
// timeStyle: 'long'
|
|
|
|
timeStyle: 'short'
|
|
|
|
}).format(date);
|
|
|
|
|
|
|
|
return formated_date;
|
|
|
|
}
|
|
|
|
|
|
|
|
function format_luxon_date(date){
|
|
|
|
formated_date = {};
|
|
|
|
|
|
|
|
date = date.setLocale(window.current_local);
|
|
|
|
// date = date.setLocale('en-gb');
|
|
|
|
// date = date.setLocale('fr-be');
|
|
|
|
// date = date.setLocale('sp');
|
|
|
|
// date = date.setLocale('nl-be');
|
|
|
|
|
|
|
|
formated_date['day'] = date.toLocaleString({weekday: 'long'});
|
|
|
|
formated_date['date'] = date.toLocaleString({month: '2-digit', day: '2-digit', year: '2-digit'});
|
|
|
|
formated_date['time'] = date.toLocaleString({timeStyle: 'short'});
|
|
|
|
|
|
|
|
// for stylistic purposes
|
|
|
|
formated_date['date'] = formated_date['date'].split("/").join(".");
|
|
|
|
|
|
|
|
return formated_date;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MOON COMPUTATION
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
// average length of a lunation
|
|
|
|
const LUNATION = 29.53058770576;
|
|
|
|
|
|
|
|
// eps is the little interval around singular event to consider them as short period
|
|
|
|
// otherwise we will never show "full moon" for example
|
|
|
|
// 0.5, means we show "full moon" 12h before and 12h after the exact event
|
|
|
|
const EPS = 0.5 / LUNATION;
|
|
|
|
|
|
|
|
function getMoonDataFromPhase(phase){
|
|
|
|
// take a 0 ot 1 number and return an object with all data for display
|
|
|
|
|
|
|
|
if (phase < EPS) return MOONPHASES[0];
|
|
|
|
else if(phase < 0.25 - EPS) return MOONPHASES[1];
|
|
|
|
else if(phase < 0.25 + EPS) return MOONPHASES[2];
|
|
|
|
else if(phase < 0.5 - EPS) return MOONPHASES[3];
|
|
|
|
else if(phase < 0.5 + EPS) return MOONPHASES[4];
|
|
|
|
else if(phase < 0.75 - EPS) return MOONPHASES[5];
|
|
|
|
else if(phase < 0.75 + EPS) return MOONPHASES[6];
|
|
|
|
else if(phase < 1 - EPS) return MOONPHASES[7];
|
|
|
|
else return MOONPHASES[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMoonStateFromDate(date, lat=0, long=0){
|
|
|
|
// return a moon object containing everything that we need
|
|
|
|
let mooncalc_illumination = SunCalc.getMoonIllumination(date);
|
|
|
|
let moon = getMoonDataFromPhase(mooncalc_illumination.phase);
|
|
|
|
moon['illumination'] = mooncalc_illumination.fraction;
|
|
|
|
moon['phase'] = mooncalc_illumination.phase;
|
|
|
|
|
|
|
|
/* TODO: those data depend of the location on earth!! lat and lon to precise */
|
|
|
|
let mooncalc_position = SunCalc.getMoonPosition(date, lat, long);
|
|
|
|
moon['distance'] = mooncalc_position.distance;
|
|
|
|
|
|
|
|
return moon;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getSunStateFromDate(date, lat=0, long=0, timezone){
|
|
|
|
|
|
|
|
// --- get suncalc sun object
|
|
|
|
// for complementary info such as: sunset time
|
|
|
|
// Note: suncalc gives us sunset time as a date object
|
|
|
|
// meaning if we just print it it will print in local user time
|
|
|
|
// what we need to do:
|
|
|
|
// js sunset_time --> ISO string in UTC --> luxon sunset_time
|
|
|
|
// set proper timezone to luxon sunset_time
|
|
|
|
// print it in it's timezone
|
|
|
|
let sun_calc = SunCalc.getTimes(date, lat, long);
|
|
|
|
let sunrise = sun_calc["sunrise"];
|
|
|
|
let sunset = sun_calc["sunset"];
|
|
|
|
|
|
|
|
let offset_sunset = luxon.DateTime.fromISO(sunset.toISOString());
|
|
|
|
offset_sunset = offset_sunset.setZone(timezone);
|
|
|
|
|
|
|
|
let offset_sunrise = luxon.DateTime.fromISO(sunrise.toISOString());
|
|
|
|
offset_sunrise = offset_sunrise.setZone(timezone);
|
|
|
|
|
|
|
|
return [offset_sunrise, offset_sunset];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PHASE TO TYPO
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
function mapValue(value, min, max, new_min, new_max){
|
|
|
|
return (((value - min) / (max - min)) * (new_max - new_min)) + new_min;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCircle(value){
|
|
|
|
// return a (x, y) tuple describing a circle of radius 1 at (0,0)
|
|
|
|
// value goes from 0 to 1
|
|
|
|
// with i=0 being the top pole, and i=0.5 is the bottom pole
|
|
|
|
let theta = value * 2 * Math.PI;
|
|
|
|
let x = Math.sin(theta);
|
|
|
|
let y = Math.cos(theta);
|
|
|
|
// console.log(i, x, y);
|
|
|
|
// NOTE: at i=0.5 we should have x=0 and y = -1, 7
|
|
|
|
// but we get a js rounding error for x
|
|
|
|
return [x,y];
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateAxis($element, value, secondAxis=true){
|
|
|
|
// take a jquery element and a value from 0 to 1
|
|
|
|
// and write the css line to update the two variable font axis
|
|
|
|
|
|
|
|
// OLD CODE for losange
|
|
|
|
// 0 at new moon, 1 at full moon
|
|
|
|
// let x = (Math.abs(i - 0.5) * -2) + 1;
|
|
|
|
// 1 at first quart and last quarter, 0 at new and full moon
|
|
|
|
// let y = (Math.abs(x - 0.5) * -2) + 1;
|
|
|
|
|
|
|
|
let [x, y] = getCircle(value);
|
|
|
|
|
|
|
|
// let weight = mapValue(x, 0, 1, 100, 500);
|
|
|
|
// let wght = '"wght" ' + weight;
|
|
|
|
// let slant = mapValue(y, 0, 1, 0, -10);
|
|
|
|
// let slnt = '"slnt" ' + slant;
|
|
|
|
|
|
|
|
let axis_1 = '"SERI" ' + mapValue(y, -1, 1, 100, 0);
|
|
|
|
let axis_2 = '"slnt" ' + mapValue(x, -1, 1, -100, 100);
|
|
|
|
let settings = secondAxis ? axis_1 + ", " + axis_2 : axis_1;
|
|
|
|
$element.css("font-variation-settings", settings);
|
|
|
|
$element.addClass("computed");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$(document).ready(function(){
|
|
|
|
window.current_local = getLocalFromURL();
|
|
|
|
});
|