Add a next-8-hours strip to the Radar panel's forecast
Same Open-Meteo call and cache as the daily outlook, just with an hourly field added — a rolling window from now rather than "rest of today", so it doesn't shrink to nothing right before midnight.
This commit is contained in:
1 parent
254e9b4c61
commit
6911e67c81
2 files changed
+55
-2
No files matched your search
@@ -218,6 +218,29 @@ html, body {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.radar-control__forecast-hours {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 6px;
|
||||
margin-bottom: 4px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.radar-control__forecast-hour {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
flex: 0 0 auto;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.radar-control__forecast-hour span:first-child {
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.radar-control__forecast-day {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
+32
-2
@@ -12,6 +12,7 @@ const RAINVIEWER_API = "https://api.rainviewer.com/public/weather-maps.json";
|
||||
// radar animation above can't.
|
||||
const FORECAST_API = "https://api.open-meteo.com/v1/forecast";
|
||||
const FORECAST_DAYS = 3;
|
||||
const HOURLY_FORECAST_COUNT = 8;
|
||||
const FORECAST_CACHE_KEY = "maptool:forecast";
|
||||
|
||||
// A small subset of WMO weather codes (open-meteo's `weather_code`) mapped
|
||||
@@ -30,6 +31,21 @@ function weatherEmoji(code) {
|
||||
return WEATHER_EMOJI.find(([codes]) => codes.includes(code))?.[1] ?? "🌡️";
|
||||
}
|
||||
|
||||
// A rolling window from "now" rather than "rest of today" — the latter
|
||||
// shrinks to nothing right before midnight and balloons to ~24 entries just
|
||||
// after, for no good reason.
|
||||
function nextHours(hourly, count) {
|
||||
const now = new Date();
|
||||
return hourly.time
|
||||
.map((time, i) => ({
|
||||
time,
|
||||
code: hourly.weather_code[i],
|
||||
temp: Math.round(hourly.temperature_2m[i]),
|
||||
}))
|
||||
.filter((hour) => new Date(hour.time) >= now)
|
||||
.slice(0, count);
|
||||
}
|
||||
|
||||
// Matches the default window used by github.com/jpettitt/weather-radar-card
|
||||
// (60 minutes of history at RainViewer's native 10-minute cadence = 7
|
||||
// frames, the last one being "now").
|
||||
@@ -180,7 +196,17 @@ export class RadarControl {
|
||||
precip: data.daily.precipitation_probability_max[i],
|
||||
}));
|
||||
|
||||
const rows = days
|
||||
const hourRows = nextHours(data.hourly, HOURLY_FORECAST_COUNT)
|
||||
.map(
|
||||
(hour) => `
|
||||
<div class="radar-control__forecast-hour">
|
||||
<span>${new Date(hour.time).toLocaleTimeString([], { hour: "2-digit" })}</span>
|
||||
<span>${weatherEmoji(hour.code)}</span>
|
||||
<span>${hour.temp}°</span>
|
||||
</div>`,
|
||||
)
|
||||
.join("");
|
||||
const dayRows = days
|
||||
.map(
|
||||
(day) => `
|
||||
<div class="radar-control__forecast-day">
|
||||
@@ -194,7 +220,7 @@ export class RadarControl {
|
||||
const staleNote = cachedAt
|
||||
? `<p class="radar-control__forecast-stale">Cached from ${new Date(cachedAt).toLocaleString([], { dateStyle: "short", timeStyle: "short" })}</p>`
|
||||
: "";
|
||||
this._forecastEl.innerHTML = rows + staleNote;
|
||||
this._forecastEl.innerHTML = `<div class="radar-control__forecast-hours">${hourRows}</div>` + dayRows + staleNote;
|
||||
}
|
||||
|
||||
_addLayers() {
|
||||
@@ -299,6 +325,10 @@ async function fetchForecast(lat, lon) {
|
||||
url.searchParams.set("latitude", lat);
|
||||
url.searchParams.set("longitude", lon);
|
||||
url.searchParams.set("daily", "weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max");
|
||||
// Same call, same cached JSON (writeCachedForecast below) — the next-few-
|
||||
// hours strip alongside the multi-day outlook rather than a second
|
||||
// request/cache entry.
|
||||
url.searchParams.set("hourly", "weather_code,temperature_2m");
|
||||
url.searchParams.set("timezone", "auto");
|
||||
url.searchParams.set("forecast_days", String(FORECAST_DAYS));
|
||||
const response = await fetch(url);
|
||||
|
||||
Reference in new issue
Block a user