clock+camera: sun and moon always from the SunCalc ephemeris (sine-curve sun and ecliptic-elongation moon removed), virtual clock via startAt/speed, optional camera aim at the moon
This commit is contained in:
1 parent
ee56f2a1c8
commit
21f75e64ce
1 file changed
+75
-172
+75
-172
@@ -643,46 +643,38 @@ window.addEventListener('resize', scheduleFitInfoPanel);
|
|||||||
return t * t * (3 - 2 * t);
|
return t * t * (3 - 2 * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Day simulation: CONFIG.day.simulation runs a full 24h cycle in
|
// ---- Virtual clock (CONFIG.day) ---------------------------------
|
||||||
// CONFIG.day.cycleSeconds (sun rises east, culminates south, sets
|
// Sun and moon are ALWAYS the real ones: every position comes from
|
||||||
// west). Off = real SunCalc positions.
|
// SunCalc, evaluated at sceneNow(). CONFIG.day only moves that clock.
|
||||||
var DAY_SIM = !!(window.CONFIG && window.CONFIG.day && window.CONFIG.day.simulation);
|
// startAt 'YYYY-MM-DDTHH:MM' - the moment the scene starts at
|
||||||
var CYCLE = ((window.CONFIG && window.CONFIG.day && window.CONFIG.day.cycleSeconds) || 20) * 1000;
|
// speed virtual seconds per real second (1 = real time,
|
||||||
// CONFIG.day.fixedTime freezes the simulated clock at one time of
|
// 1440 = one simulated day per minute)
|
||||||
// day: 'HH:MM', 'HH:MM:SS' or a number (0..24). null/unset = the
|
// Clock hands, digital readout, weather, calendar and the whole sky
|
||||||
// clock advances as before. Only the TIME OF DAY stops - cloud
|
// all read sceneNow(), so nothing drifts apart. Hash overrides:
|
||||||
// drift, car flow and the bobbing camera run on wall time, and
|
// #at=2026-10-27T19:14 and #speed=1.
|
||||||
// the weather sim has its own timer, so all of that keeps moving.
|
var SIM_START = (function () {
|
||||||
var FIXED_T = (function () {
|
var v = (window.CONFIG && window.CONFIG.day && window.CONFIG.day.startAt)
|
||||||
var v = window.CONFIG && window.CONFIG.day && window.CONFIG.day.fixedTime;
|
|| _hashParams.at;
|
||||||
if (v == null || v === '') return null;
|
if (!v) return null;
|
||||||
var h;
|
var m = String(v).match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{1,2}):(\d{2})(?::(\d{2}))?/);
|
||||||
if (typeof v === 'number') h = v;
|
if (!m) { console.warn('CONFIG.day.startAt not understood: ' + v); return null; }
|
||||||
else {
|
return new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +(m[6] || 0)).getTime();
|
||||||
var p = String(v).split(':');
|
|
||||||
h = parseInt(p[0], 10) || 0;
|
|
||||||
if (p.length > 1) h += parseInt(p[1], 10) / 60;
|
|
||||||
if (p.length > 2) h += parseInt(p[2], 10) / 3600;
|
|
||||||
}
|
|
||||||
return (h >= 0 && h < 24) ? h / 24 : null;
|
|
||||||
})();
|
})();
|
||||||
// simulated sun altitude (rad): t=0 midnight, 0.25 sunrise, 0.5 noon
|
var SIM_SPEED = (function () {
|
||||||
function simSunAlt(t) {
|
var d = (window.CONFIG && window.CONFIG.day) || {};
|
||||||
return Math.sin((t - 0.25) * Math.PI * 2) * 1.45;
|
var hs = parseFloat(_hashParams.speed);
|
||||||
|
if (!isNaN(hs) && hs > 0) return hs;
|
||||||
|
if (typeof d.speed === 'number' && d.speed > 0) return d.speed;
|
||||||
|
// legacy: cycleSeconds used to mean "seconds per simulated day"
|
||||||
|
if (typeof d.cycleSeconds === 'number' && d.cycleSeconds > 0) return 86400 / d.cycleSeconds;
|
||||||
|
return 1;
|
||||||
|
})();
|
||||||
|
var SIM_ACTIVE = SIM_START !== null;
|
||||||
|
var SIM_LOAD_MS = Date.now();
|
||||||
|
function sceneNow() {
|
||||||
|
if (SIM_START === null) return new Date();
|
||||||
|
return new Date(SIM_START + (Date.now() - SIM_LOAD_MS) * SIM_SPEED);
|
||||||
}
|
}
|
||||||
// Virtual calendar for day-switching features (weather forecast):
|
|
||||||
// same wall clock as reality, but the DATE advances one day per
|
|
||||||
// simulated cycle. The visible clock hands/digital stay real.
|
|
||||||
function simNow() {
|
|
||||||
if (!DAY_SIM) return new Date();
|
|
||||||
if (FIXED_T !== null) {
|
|
||||||
var f = new Date();
|
|
||||||
f.setHours(Math.floor(FIXED_T * 24), Math.round((FIXED_T * 1440) % 60), 0, 0);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
return new Date(startTime + (Date.now() - startTime) * (86400000 / CYCLE));
|
|
||||||
}
|
|
||||||
var __simT = 0;
|
|
||||||
|
|
||||||
var SITE_LAT = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lat) || 51.5074;
|
var SITE_LAT = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lat) || 51.5074;
|
||||||
var SITE_LON = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lon) || -0.1278;
|
var SITE_LON = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lon) || -0.1278;
|
||||||
@@ -909,12 +901,7 @@ window.sunPalettes = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getColor(t) {
|
function getColor(t) {
|
||||||
if (DAY_SIM) {
|
var now = sceneNow();
|
||||||
// t: 0 = Mitternacht, 0.25 Sonnenaufgang (Osten),
|
|
||||||
// 0.5 Mittag (Sueden), 0.75 Sonnenuntergang (Westen).
|
|
||||||
return getDayColor(simSunAlt(t));
|
|
||||||
}
|
|
||||||
var now = new Date();
|
|
||||||
var sunPos = SunCalc.getPosition(now, SITE_LAT, SITE_LON);
|
var sunPos = SunCalc.getPosition(now, SITE_LAT, SITE_LON);
|
||||||
var moonIllum = SunCalc.getMoonIllumination(now);
|
var moonIllum = SunCalc.getMoonIllumination(now);
|
||||||
|
|
||||||
@@ -1289,20 +1276,10 @@ window.sunPalettes = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateClockAndEvents() {
|
function updateClockAndEvents() {
|
||||||
var now = new Date();
|
var now = sceneNow();
|
||||||
// Simulated wall clock: with CONFIG.day.simulation the scene runs
|
|
||||||
// a whole day in cycleSeconds, so the clock hands, the digital
|
|
||||||
// readout and every sun/moon table follow the accelerated date
|
|
||||||
// instead of the real one - the scene and the clock stay in step.
|
|
||||||
// simNow() is the same accelerated date the weather/calendar
|
|
||||||
// layer uses, so nothing drifts apart.
|
|
||||||
if (DAY_SIM) now = simNow();
|
|
||||||
|
|
||||||
// Calculate real day progress based on sun position
|
// Calculate real day progress based on sun position
|
||||||
// 0% = midnight, 50% = noon, 100% = next midnight
|
// 0% = midnight, 50% = noon, 100% = next midnight
|
||||||
if (DAY_SIM) {
|
|
||||||
realDayProgress = __simT;
|
|
||||||
} else {
|
|
||||||
var sunTimes = SunCalc.getTimes(now, SITE_LAT, SITE_LON);
|
var sunTimes = SunCalc.getTimes(now, SITE_LAT, SITE_LON);
|
||||||
var sunrise = sunTimes.sunrise;
|
var sunrise = sunTimes.sunrise;
|
||||||
var sunset = sunTimes.sunset;
|
var sunset = sunTimes.sunset;
|
||||||
@@ -1314,8 +1291,7 @@ window.sunPalettes = [
|
|||||||
} else {
|
} else {
|
||||||
realDayProgress = 0.5 + (now.getTime() - sunset.getTime()) / (sunrise.getTime() + 24 * 3600 * 1000 - sunset.getTime()) * 0.5;
|
realDayProgress = 0.5 + (now.getTime() - sunset.getTime()) / (sunrise.getTime() + 24 * 3600 * 1000 - sunset.getTime()) * 0.5;
|
||||||
}
|
}
|
||||||
realDayProgress = Math.max(0, Math.min(1, realDayProgress));
|
realDayProgress = Math.max(0, Math.min(1, realDayProgress));
|
||||||
}
|
|
||||||
|
|
||||||
// Real-time clock hands and digital
|
// Real-time clock hands and digital
|
||||||
var h = now.getHours();
|
var h = now.getHours();
|
||||||
@@ -1635,8 +1611,9 @@ window.weatherThemes = {
|
|||||||
// At night, weather only tints slightly - we don't want a
|
// At night, weather only tints slightly - we don't want a
|
||||||
// 'cloudy' sky colour washing over deep night sky and
|
// 'cloudy' sky colour washing over deep night sky and
|
||||||
// making it look bright.
|
// making it look bright.
|
||||||
var _sunAlt = DAY_SIM ? (window.__currentSunAlt || 0)
|
var _sunAlt = window.__currentSunAlt !== undefined
|
||||||
: SunCalc.getPosition(new Date(), SITE_LAT, SITE_LON).altitude;
|
? window.__currentSunAlt
|
||||||
|
: SunCalc.getPosition(sceneNow(), SITE_LAT, SITE_LON).altitude;
|
||||||
var nightFactor = Math.max(0, Math.min(1, -_sunAlt / 0.4));
|
var nightFactor = Math.max(0, Math.min(1, -_sunAlt / 0.4));
|
||||||
// Daytime: 40% weather mix (was 60%) — keeps day/night
|
// Daytime: 40% weather mix (was 60%) — keeps day/night
|
||||||
// palette visible underneath, weather only adds tint.
|
// palette visible underneath, weather only adds tint.
|
||||||
@@ -1701,7 +1678,6 @@ window.weatherThemes = {
|
|||||||
if (typeof fetchWeather === 'function') fetchWeather();
|
if (typeof fetchWeather === 'function') fetchWeather();
|
||||||
// Force a debug update so the digital clock shows the new language
|
// Force a debug update so the digital clock shows the new language
|
||||||
if (typeof updateDebug === 'function') {
|
if (typeof updateDebug === 'function') {
|
||||||
var now = new Date();
|
|
||||||
updateDebug(0, null,
|
updateDebug(0, null,
|
||||||
{ sky: 0, cloud: 0, light: 0, bg: 0 },
|
{ sky: 0, cloud: 0, light: 0, bg: 0 },
|
||||||
currentWeatherThemeName, realDayProgress);
|
currentWeatherThemeName, realDayProgress);
|
||||||
@@ -1778,8 +1754,7 @@ window.weatherThemes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateDebug(t, palette, sceneColors, themeName, realDayProgress) {
|
function updateDebug(t, palette, sceneColors, themeName, realDayProgress) {
|
||||||
var now = new Date();
|
var now = sceneNow();
|
||||||
if (DAY_SIM) now = simNow();
|
|
||||||
var hh = now.getHours(), mm = now.getMinutes(), ss = now.getSeconds();
|
var hh = now.getHours(), mm = now.getMinutes(), ss = now.getSeconds();
|
||||||
document.getElementById('dbg-time').textContent =
|
document.getElementById('dbg-time').textContent =
|
||||||
(hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;
|
(hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;
|
||||||
@@ -1904,9 +1879,7 @@ window.weatherThemes = {
|
|||||||
var __fpsCount = 0, __fpsT0 = performance.now(), __dbgT0 = 0;
|
var __fpsCount = 0, __fpsT0 = performance.now(), __dbgT0 = 0;
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
var t = (DAY_SIM && FIXED_T !== null)
|
var t = realDayProgress;
|
||||||
? FIXED_T
|
|
||||||
: (Date.now() - startTime) / CYCLE % 1;
|
|
||||||
var c = getColor(t);
|
var c = getColor(t);
|
||||||
c = applyWeatherTheme(c);
|
c = applyWeatherTheme(c);
|
||||||
// Expose current palette + weather info for the WebGL scene
|
// Expose current palette + weather info for the WebGL scene
|
||||||
@@ -1915,112 +1888,42 @@ window.weatherThemes = {
|
|||||||
window.__currentDayProgress = realDayProgress;
|
window.__currentDayProgress = realDayProgress;
|
||||||
window.__currentThemeSpeed = currentThemeSpeed;
|
window.__currentThemeSpeed = currentThemeSpeed;
|
||||||
// Sun altitude in radians. Negative = below horizon (night).
|
// Sun altitude in radians. Negative = below horizon (night).
|
||||||
if (DAY_SIM) {
|
var _sunNow = sceneNow();
|
||||||
__simT = t;
|
var _sunPos = SunCalc.getPosition(_sunNow, SITE_LAT, SITE_LON);
|
||||||
window.__currentDayProgress = t;
|
window.__currentSunAlt = _sunPos.altitude;
|
||||||
// virtual weekday: starts at the real one and advances with
|
window.__flightDow = _sunNow.getDay();
|
||||||
// every simulated day, so weekends pass by in the 20s cycle
|
// Unit vector towards the sun in world space. SunCalc azimuth
|
||||||
if (typeof window.__simDow !== 'number') {
|
// is measured from the south, positive towards the west, so the
|
||||||
window.__simDow = new Date().getDay();
|
// compass bearing (0 = north, clockwise) is azimuth + PI.
|
||||||
window.__simLastT = t;
|
// World frame: +X = west, +Z = north, +Y = up -> east is -X.
|
||||||
} else if (t < window.__simLastT) {
|
var _sunBearingR = _sunPos.azimuth + Math.PI;
|
||||||
window.__simDow = (window.__simDow + 1) % 7;
|
window.__currentSunDir = [
|
||||||
}
|
-Math.cos(_sunPos.altitude) * Math.sin(_sunBearingR),
|
||||||
window.__simLastT = t;
|
Math.sin(_sunPos.altitude),
|
||||||
window.__flightDow = window.__simDow;
|
Math.cos(_sunPos.altitude) * Math.cos(_sunBearingR)
|
||||||
var _alt = simSunAlt(t);
|
];
|
||||||
window.__currentSunAlt = _alt;
|
|
||||||
// bearing: 6:00 (t=0.25) = east (pi/2), 12:00 = south (pi),
|
|
||||||
// 18:00 = west (3pi/2) -> bearing = 2*PI*t
|
|
||||||
var _sunBearing = t * Math.PI * 2;
|
|
||||||
// World frame (verified from the star frame and the terrain
|
|
||||||
// mesh): +X points WEST, +Y up, +Z north. The star frame maps
|
|
||||||
// RA=0 to +X and rotates it to due west after 6 h of sidereal
|
|
||||||
// time, and the mesh samples the mosaic with u = 0.5 - x/size,
|
|
||||||
// so east is -X. The east component therefore has to land on
|
|
||||||
// -cos(alt)*sin(bearing).
|
|
||||||
window.__currentSunDir = [
|
|
||||||
-Math.cos(_alt) * Math.sin(_sunBearing),
|
|
||||||
Math.sin(_alt),
|
|
||||||
Math.cos(_alt) * Math.cos(_sunBearing)
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
var _sunPos = SunCalc.getPosition(new Date(), SITE_LAT, SITE_LON);
|
|
||||||
window.__currentSunAlt = _sunPos.altitude;
|
|
||||||
window.__flightDow = new Date().getDay();
|
|
||||||
// Unit vector towards the sun in world space. SunCalc azimuth
|
|
||||||
// is measured from the south, positive towards the west, so
|
|
||||||
// the compass bearing (0 = north, clockwise) is azimuth + PI.
|
|
||||||
// World frame: +X = west, +Z = north, +Y = up -> east is -X.
|
|
||||||
var _sunBearingR = _sunPos.azimuth + Math.PI;
|
|
||||||
window.__currentSunDir = [
|
|
||||||
-Math.cos(_sunPos.altitude) * Math.sin(_sunBearingR),
|
|
||||||
Math.sin(_sunPos.altitude),
|
|
||||||
Math.cos(_sunPos.altitude) * Math.cos(_sunBearingR)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
// ---- Local sidereal time -------------------------------------
|
// ---- Local sidereal time -------------------------------------
|
||||||
// Same formula SunCalc uses internally (Meeus): GMST in degrees
|
// Same formula SunCalc uses internally (Meeus): GMST in degrees
|
||||||
// plus the observer's east longitude. This is what the star
|
// plus the observer's east longitude. This is what the star
|
||||||
// frame has to follow - a solar day fraction is 3 min 56 s per
|
// frame has to follow - a solar day fraction is 3 min 56 s per
|
||||||
// day off and has no absolute phase at all.
|
// day off and has no absolute phase at all.
|
||||||
var _sidD = (Date.now() - Date.UTC(2000, 0, 1, 12, 0, 0)) / 86400000;
|
var _sidD = (sceneNow().getTime() - Date.UTC(2000, 0, 1, 12, 0, 0)) / 86400000;
|
||||||
var _sidReal = (280.16 + 360.9856235 * _sidD + SITE_LON) * Math.PI / 180;
|
window.__currentSiderealRad = (280.16 + 360.9856235 * _sidD + SITE_LON) * Math.PI / 180;
|
||||||
if (DAY_SIM) {
|
|
||||||
if (typeof window.__sidStart !== 'number') {
|
|
||||||
window.__sidStart = _sidReal;
|
|
||||||
window.__sidStartMs = Date.now();
|
|
||||||
}
|
|
||||||
// simulated days elapsed * sidereal rate (1.0027379 solar days
|
|
||||||
// per sidereal day)
|
|
||||||
var _sidDays = (Date.now() - window.__sidStartMs) / CYCLE;
|
|
||||||
window.__currentSiderealRad = window.__sidStart + _sidDays * 2 * Math.PI * 1.0027379;
|
|
||||||
} else {
|
|
||||||
window.__currentSiderealRad = _sidReal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Moon direction ------------------------------------------
|
// ---- Moon direction ------------------------------------------
|
||||||
// Start elongation = real lunar phase (SunCalc: 0 new .. 0.5
|
// SunCalc solves the actual lunar ephemeris: the moon's own
|
||||||
// full); in day simulation the elongation advances 360/29.53
|
// altitude/azimuth, not a point kept on the sun's declination
|
||||||
// deg per simulated day -> correct waxing/waning as cycles pass.
|
// circle (the geometric construction that used to live here put
|
||||||
if (typeof window.__moonElong0 !== 'number') {
|
// the moon up to 28.5 deg away from its real sky position).
|
||||||
window.__moonElong0 = SunCalc.getMoonIllumination(new Date()).phase * Math.PI * 2;
|
var _moonNow = sceneNow();
|
||||||
window.__moonSimStartMs = Date.now();
|
var _moonPos = SunCalc.getMoonPosition(_moonNow, SITE_LAT, SITE_LON);
|
||||||
}
|
var _moonBearingR = _moonPos.azimuth + Math.PI;
|
||||||
var _simDays = (DAY_SIM && FIXED_T === null) ? (Date.now() - window.__moonSimStartMs) / CYCLE : 0;
|
window.__currentMoonDir = [
|
||||||
var _elong = window.__moonElong0 + _simDays * (Math.PI * 2 / 29.53);
|
-Math.cos(_moonPos.altitude) * Math.sin(_moonBearingR),
|
||||||
var _sd = window.__currentSunDir;
|
Math.sin(_moonPos.altitude),
|
||||||
var _cp = SITE_LAT * Math.PI / 180;
|
Math.cos(_moonPos.altitude) * Math.cos(_moonBearingR)
|
||||||
var _kp = [0, Math.sin(_cp), Math.cos(_cp)]; // celestial pole
|
];
|
||||||
var _ecs = Math.cos(_elong), _esn = Math.sin(_elong);
|
window.__currentMoonFrac = SunCalc.getMoonIllumination(_moonNow).fraction;
|
||||||
var _kdv = _kp[0]*_sd[0] + _kp[1]*_sd[1] + _kp[2]*_sd[2];
|
|
||||||
var _cx = _kp[1]*_sd[2] - _kp[2]*_sd[1];
|
|
||||||
var _cy = _kp[2]*_sd[0] - _kp[0]*_sd[2];
|
|
||||||
var _cz = _kp[0]*_sd[1] - _kp[1]*_sd[0];
|
|
||||||
if (DAY_SIM) {
|
|
||||||
window.__currentMoonDir = [
|
|
||||||
_sd[0]*_ecs + _cx*_esn + _kp[0]*_kdv*(1-_ecs),
|
|
||||||
_sd[1]*_ecs + _cy*_esn + _kp[1]*_kdv*(1-_ecs),
|
|
||||||
_sd[2]*_ecs + _cz*_esn + _kp[2]*_kdv*(1-_ecs)
|
|
||||||
];
|
|
||||||
// illuminated fraction straight from the elongation used above
|
|
||||||
// (0 = new, 1 = full) so other layers can light themselves by it
|
|
||||||
window.__currentMoonFrac = (1 - Math.cos(_elong)) * 0.5;
|
|
||||||
} else {
|
|
||||||
// Real mode: the geometric construction above keeps the moon on
|
|
||||||
// the SUN's declination circle. The real moon leaves it by up to
|
|
||||||
// 28.5 deg (obliquity 23.4 + lunar inclination 5.1), which puts
|
|
||||||
// it in the wrong part of the sky. SunCalc solves the actual
|
|
||||||
// lunar ephemeris, so use its altitude/azimuth directly.
|
|
||||||
var _moonPos = SunCalc.getMoonPosition(new Date(), SITE_LAT, SITE_LON);
|
|
||||||
var _moonBearingR = _moonPos.azimuth + Math.PI;
|
|
||||||
window.__currentMoonDir = [
|
|
||||||
-Math.cos(_moonPos.altitude) * Math.sin(_moonBearingR),
|
|
||||||
Math.sin(_moonPos.altitude),
|
|
||||||
Math.cos(_moonPos.altitude) * Math.cos(_moonBearingR)
|
|
||||||
];
|
|
||||||
window.__currentMoonFrac = SunCalc.getMoonIllumination(new Date()).fraction;
|
|
||||||
}
|
|
||||||
var __skyHex = '#' + ('00000' + c.sky.toString(16)).slice(-6);
|
var __skyHex = '#' + ('00000' + c.sky.toString(16)).slice(-6);
|
||||||
if (__skyHex !== window.__lastSkyHex) {
|
if (__skyHex !== window.__lastSkyHex) {
|
||||||
window.__lastSkyHex = __skyHex;
|
window.__lastSkyHex = __skyHex;
|
||||||
@@ -2065,8 +1968,8 @@ window.weatherThemes = {
|
|||||||
console.error('Tick error:', e);
|
console.error('Tick error:', e);
|
||||||
}
|
}
|
||||||
// simulated day/hour switch -> refresh the weather block
|
// simulated day/hour switch -> refresh the weather block
|
||||||
if (DAY_SIM && weatherData) {
|
if (SIM_START !== null && weatherData) {
|
||||||
var wh = Math.floor(simNow().getTime() / 3600000);
|
var wh = Math.floor(sceneNow().getTime() / 3600000);
|
||||||
if (wh !== __lastWeatherHour) {
|
if (wh !== __lastWeatherHour) {
|
||||||
__lastWeatherHour = wh;
|
__lastWeatherHour = wh;
|
||||||
try { updateWeatherDisplay(); } catch (e) { console.error(e); }
|
try { updateWeatherDisplay(); } catch (e) { console.error(e); }
|
||||||
@@ -2285,8 +2188,8 @@ window.weatherThemes = {
|
|||||||
function updateWeatherDisplay() {
|
function updateWeatherDisplay() {
|
||||||
if (!weatherData) return;
|
if (!weatherData) return;
|
||||||
|
|
||||||
var now = simNow(); // virtual calendar: real day-of-week start,
|
var now = sceneNow(); // virtual calendar: follows the same
|
||||||
// one simulated day per CYCLE (clock stays real!)
|
// clock the sky and the clock hands use
|
||||||
var current = weatherData.current;
|
var current = weatherData.current;
|
||||||
var hourly = weatherData.hourly;
|
var hourly = weatherData.hourly;
|
||||||
var daily = weatherData.daily;
|
var daily = weatherData.daily;
|
||||||
@@ -2298,11 +2201,11 @@ window.weatherThemes = {
|
|||||||
var spanMs = daily.time.length * 86400000;
|
var spanMs = daily.time.length * 86400000;
|
||||||
var eff = now;
|
var eff = now;
|
||||||
var wrapGuard = 0;
|
var wrapGuard = 0;
|
||||||
while (DAY_SIM && eff.getTime() >= firstDay.getTime() + spanMs && wrapGuard++ < 2000) {
|
while (SIM_ACTIVE && eff.getTime() >= firstDay.getTime() + spanMs && wrapGuard++ < 2000) {
|
||||||
eff = new Date(eff.getTime() - spanMs);
|
eff = new Date(eff.getTime() - spanMs);
|
||||||
}
|
}
|
||||||
if (DAY_SIM && eff.getTime() < firstDay.getTime()) eff = firstDay;
|
if (SIM_ACTIVE && eff.getTime() < firstDay.getTime()) eff = firstDay;
|
||||||
var dayOffset = DAY_SIM
|
var dayOffset = SIM_ACTIVE
|
||||||
? Math.max(0, Math.min(daily.time.length - 4,
|
? Math.max(0, Math.min(daily.time.length - 4,
|
||||||
Math.floor((eff - firstDay) / 86400000)))
|
Math.floor((eff - firstDay) / 86400000)))
|
||||||
: 0;
|
: 0;
|
||||||
@@ -2312,7 +2215,7 @@ window.weatherThemes = {
|
|||||||
// button has manual control)
|
// button has manual control)
|
||||||
var curTemp = current.temperature_2m;
|
var curTemp = current.temperature_2m;
|
||||||
var curCode = current.weather_code;
|
var curCode = current.weather_code;
|
||||||
if (DAY_SIM) {
|
if (SIM_ACTIVE) {
|
||||||
var curIdx = findHourlyIndex(eff, hourly.time);
|
var curIdx = findHourlyIndex(eff, hourly.time);
|
||||||
curTemp = hourly.temperature_2m[curIdx];
|
curTemp = hourly.temperature_2m[curIdx];
|
||||||
curCode = hourly.weather_code[curIdx];
|
curCode = hourly.weather_code[curIdx];
|
||||||
|
|||||||
Reference in new issue
Block a user