From 944982f34a5830e94f8a68a851da0d3e707c3935 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Wed, 7 Oct 2026 08:03:27 +0200 Subject: [PATCH] Interpolate moon position between moonrise and moonset on orbit --- index.html | 72 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 5c17c1a..f91c8a4 100644 --- a/index.html +++ b/index.html @@ -363,6 +363,61 @@ return 'M ' + sp.x + ' ' + sp.y + ' A ' + radius + ' ' + radius + ' 0 ' + largeArc + ' 1 ' + ep.x + ' ' + ep.y; } + function getMoonPosition(now, moonTimes) { + var rise = moonTimes.rise; + var set = moonTimes.set; + + if (!rise || !set) { + return { point: pointOnCircle(now, MOON_ORBIT_RADIUS), isVisible: false }; + } + + // Determine if moon is visible (above horizon) + var isVisible; + if (rise <= set) { + isVisible = (now >= rise && now <= set); + } else { + isVisible = (now >= rise || now <= set); + } + + if (!isVisible) { + // Below horizon - position based on current time (grayed out) + return { point: pointOnCircle(now, MOON_ORBIT_RADIUS), isVisible: false }; + } + + // Above horizon - interpolate between moonrise and moonset + var riseAngle = angleForTime(rise); + var setAngle = angleForTime(set); + + // Calculate the angular difference (could be negative if crossing midnight) + var diff = setAngle - riseAngle; + // Normalize so we take the "shorter" path that matches the moon arc + if (diff > Math.PI) diff -= 2 * Math.PI; + if (diff < -Math.PI) diff += 2 * Math.PI; + + // Calculate progress (0 at rise, 1 at set) + var progress; + if (rise <= set) { + progress = (now.getTime() - rise.getTime()) / (set.getTime() - rise.getTime()); + } else { + if (now >= rise) { + var endMs = set.getTime() + 24 * 3600 * 1000; + progress = (now.getTime() - rise.getTime()) / (endMs - rise.getTime()); + } else { + progress = (now.getTime() + 24 * 3600 * 1000 - rise.getTime()) / + (set.getTime() + 24 * 3600 * 1000 - rise.getTime()); + } + } + + var moonAngle = riseAngle + diff * progress; + return { + point: { + x: 100 + Math.cos(moonAngle) * MOON_ORBIT_RADIUS, + y: 100 + Math.sin(moonAngle) * MOON_ORBIT_RADIUS + }, + isVisible: true + }; + } + function renderMoonPhaseIcon(phase) { var icon = document.getElementById('moon-phase-icon'); icon.innerHTML = ''; @@ -481,19 +536,10 @@ rpgSunGlow.setAttribute('opacity', isDaytime ? '0.4' : '0.15'); rpgSunCore.setAttribute('opacity', isDaytime ? '1' : '0.35'); - // Moon position - var moonP = pointOnCircle(now, MOON_ORBIT_RADIUS); - rpgMoon.setAttribute('transform', 'translate(' + moonP.x + ', ' + moonP.y + ')'); - - var moonVisible = false; - if (moonTimes.rise && moonTimes.set) { - if (moonTimes.rise < moonTimes.set) { - moonVisible = (now >= moonTimes.rise && now <= moonTimes.set); - } else { - moonVisible = (now >= moonTimes.rise || now <= moonTimes.set); - } - } - rpgMoon.setAttribute('opacity', moonVisible ? '1' : '0.35'); + // Moon position - interpolated between moonrise and moonset on the orbit + var moonPos = getMoonPosition(now, moonTimes); + rpgMoon.setAttribute('transform', 'translate(' + moonPos.point.x + ', ' + moonPos.point.y + ')'); + rpgMoon.setAttribute('opacity', moonPos.isVisible ? '1' : '0.35'); // Sun rise/set arrows var srP = pointOnCircle(sunTimes.sunrise, SUN_ORBIT_RADIUS);