v1.42 - Fix Cosmic Events + Popups

This commit is contained in:
fraxle
2026-05-16 22:15:21 +01:00
parent b4d2a1427a
commit 40f651eb98
3 changed files with 133 additions and 7 deletions
+41 -6
View File
@@ -331,23 +331,54 @@ function checkStargazing(rows) {
}
function checkSunset(rows, location) {
// Perfect sunset: clear low cloud near sunset hour, good visibility
const sunsetRows = rows.filter(r => r.elev > -3 && r.elev < 8);
if (sunsetRows.length === 0) return null;
// Find the actual sunset window: the LAST contiguous run of rows where
// solar elevation is in the golden/civil-twilight band (-3° to 8°).
// This distinguishes sunset from sunrise (which is the first such run).
const twilightIndices = rows
.map((r, i) => ({ r, i }))
.filter(({ r }) => r.elev > -3 && r.elev < 8);
if (twilightIndices.length === 0) return null;
// Split into runs separated by gaps (midday gap separates sunrise from sunset)
const runs = [];
let run = [twilightIndices[0]];
for (let k = 1; k < twilightIndices.length; k++) {
if (twilightIndices[k].i === twilightIndices[k - 1].i + 1) {
run.push(twilightIndices[k]);
} else {
runs.push(run);
run = [twilightIndices[k]];
}
}
runs.push(run);
// Use the LAST run (sunset). If only one run exists it's either sunrise-only
// or a single dusk window — use it but we'll label generically.
const sunsetRun = runs[runs.length - 1];
const sunsetRows = sunsetRun.map(({ r }) => r);
const isSunrise = runs.length === 1 && sunsetRows[0].elev < sunsetRows[sunsetRows.length - 1].elev;
// If sun is rising through the band this is a sunrise window, not sunset — skip.
if (isSunrise) return null;
const avgCloud = sunsetRows.reduce((s, r) => s + r.cc, 0) / sunsetRows.length;
// We want some high cloud (colour) but not low cloud (obstruction)
const avgLowCloud = sunsetRows.reduce((s, r) => s + (r.ccLow || 0), 0) / sunsetRows.length;
if (avgLowCloud > 25) return null;
if (avgCloud < 5 || avgCloud > 75) return null; // pure clear = less dramatic
if (avgCloud < 5 || avgCloud > 75) return null;
// Store the ISO time range so getCellTagEvents can limit the icon to those hours
const firstISO = sunsetRun[0].r.iso;
const lastISO = sunsetRun[sunsetRun.length - 1].r.iso;
return {
id: 'perfect-sunset',
emoji: '🌅',
title: 'Spectacular Sunset Conditions',
message: `Low cloud is clear near the horizon but high cloud will scatter the light — conditions are ideal for a vivid sunset near ${location.name}.`,
message: `Low cloud is clear near the horizon but high cloud will scatter the light — conditions look ideal for a vivid sunset near ${location.name}.`,
color: '#3a1a00',
textColor: '#ffe0b0',
type: 'weather',
nightOnly: false,
isoRange: [firstISO, lastISO], // only show cell icon during these hours
};
}
@@ -709,6 +740,10 @@ export function getCellTagEvents(events, row) {
if (ev.type === 'promo') return false;
if (ev.nightOnly && row.elev >= -5) return false;
if (ev.id === 'heat-spike' && row.elev < 0) return false;
// Sunset/sunrise events: only show icon during the actual twilight window
if (ev.isoRange) {
if (row.iso < ev.isoRange[0] || row.iso > ev.isoRange[1]) return false;
}
return true;
});
}