Updated logo
Added average seasonal temps compare
This commit is contained in:
fraxle
2026-07-07 13:23:08 +01:00
parent fd7ed5dfcc
commit 0b260affd7
7 changed files with 151 additions and 24 deletions
+33 -1
View File
@@ -381,7 +381,7 @@ export function computeWhyFeelsLike(row, env) {
// variant - active sub-variant key e.g. "running", "beach" (or null)
// skinType - Fitzpatrick skin type key for UV burn time
// ------------------------------------------------------------------------
export function computeGlanceSummary(todayRows, profile, variant, skinType, cols = null, vehicleSpeed = 'static', weekDays = null, lat = null) {
export function computeGlanceSummary(todayRows, profile, variant, skinType, cols = null, vehicleSpeed = 'static', weekDays = null, lat = null, normals = null, dayKey = null) {
if (!todayRows || todayRows.length === 0) return [];
const show = (key) => !cols || !!cols[key];
@@ -491,6 +491,33 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
alert: maxRainProb >= 60,
};
// ── Vs seasonal average (climate anomaly) ──────────────────────────────
// Shown across every profile: how far this day's mean air temp sits above or
// below the 1991-2020 normal for the date. A small, honest climate-change cue.
const climateItem = (() => {
if (!normals) return [];
const key = dayKey || todayRows[0]?.iso?.slice(0, 10);
if (!key) return [];
const LEAP_CUM = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
const doy = LEAP_CUM[parseInt(key.slice(5, 7), 10) - 1] + (parseInt(key.slice(8, 10), 10) - 1);
const normal = normals[doy];
if (normal == null) return [];
const taVals = todayRows.map(r => r.Ta).filter(v => v != null);
if (taVals.length === 0) return [];
const dayMean = taVals.reduce((a, b) => a + b, 0) / taVals.length;
const anomaly = dayMean - normal;
const mag = Math.abs(anomaly);
const value = mag < 0.5
? 'About average'
: `${anomaly >= 0 ? '+' : ''}${mag.toFixed(1)}° ${anomaly >= 0 ? 'warmer' : 'cooler'}`;
return [{
icon: '🌡',
label: '1991-2020 Average',
value,
alert: anomaly >= 5,
}];
})();
// ── Good Driving Time ──────────────────────────────────────────────────
// Shown whenever a road speed (not Static) is selected and the vehicle cabin
// column is active - so it appears in both the Vehicle and Driver profiles.
@@ -527,6 +554,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
const maxPollen = Math.max(0, ...todayRows.map(r => r.grassPollen ?? 0));
return [
...climateItem,
{
icon: '⏱',
label: 'Best field work',
@@ -563,6 +591,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
const dangerFrom = todayRows.find(r => r.vehicleT != null && r.vehicleT >= 29);
return [
...climateItem,
...(show('vehicleT') ? [{
icon: '🌡',
label: 'Peak cabin temp',
@@ -601,6 +630,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
const maxPollen = Math.max(0, ...todayRows.map(r => r.grassPollen ?? 0));
return [
...climateItem,
...(show('indoorT') ? [{
icon: '🌡',
label: 'Peak indoor (unmanaged)',
@@ -648,6 +678,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
: null;
return [
...climateItem,
{
icon: '⏱',
label: `Best ${variant} window`,
@@ -690,6 +721,7 @@ export function computeGlanceSummary(todayRows, profile, variant, skinType, cols
: null;
return [
...climateItem,
...(drivingShown ? [drivingItem] : []),
{
icon: '🌤',