feat: uuroverzicht per dag (temperatuur, regen, wind)
Tik op een dag in de verwachtingsstrook voor een uuroverzicht van
temperatuur, regen en wind (richting + snelheid), om de 2 uur, 12
punten per dag. Sluit na 20 seconden vanzelf of bij een tik op de
overlay zelf.
Backend: Open-Meteo levert hourly-data in dezelfde call als daily
(geen extra verzoek, dezelfde 60min-cache). Nieuwe HourlyForecastMapper
groepeert per kalenderdatum en bemonstert om het andere uur, robuust
voor de zomertijddag (23/25 uur). OpenMeteoClient::dailyForecast()
hernoemd naar forecast(), geeft nu {daily, hourly} terug. Elke dag in
de forecast-array krijgt een hourly-lijst.
Frontend: temperatuurlijn hergebruikt sparklinePath (nu ook als
sparklinePoints voor exacte uitlijning met de 12-koloms grid), regen
als kleine staafjes, windpijl (nieuw icoon) wijst waarheen de wind
waait. 20s-balk via CSS transition met reflow-restart. Servicewerker
naar v5.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+37
-1
@@ -119,7 +119,10 @@ test('msUntil computes the wait until the next local time', () => {
|
||||
assert.equal(msUntil(new Date('2026-09-11T22:00:00.000Z'), TZ, 0), 86400000, 'precies op het moment zelf: pas morgen weer');
|
||||
});
|
||||
|
||||
import { co2Level, fPct, fHpa, seriesRange, sparklinePath } from '../../public/format.js';
|
||||
import {
|
||||
co2Level, fPct, fHpa, seriesRange, sparklinePath, sparklinePoints,
|
||||
windArrowDeg, fKmh, formatHour, formatFullDate,
|
||||
} from '../../public/format.js';
|
||||
|
||||
test('co2Level uses the Netatmo thresholds', () => {
|
||||
assert.deepEqual(co2Level(612), { level: 'good', label: 'goed' });
|
||||
@@ -151,3 +154,36 @@ test('sparklinePath scales points into the box', () => {
|
||||
assert.equal(sparklinePath([1000], 100, 50), '');
|
||||
assert.equal(sparklinePath([], 100, 50), '');
|
||||
});
|
||||
|
||||
test('sparklinePoints gives x for every index and null y for unknown values', () => {
|
||||
const points = sparklinePoints([1000, null, 1010], 100, 50, 0);
|
||||
assert.deepEqual(points.map((p) => p.x), [0, 50, 100]);
|
||||
assert.equal(points[0].y, 50);
|
||||
assert.equal(points[1].y, null);
|
||||
assert.equal(points[2].y, 0);
|
||||
});
|
||||
|
||||
test('windArrowDeg rotates 180 degrees so the arrow points where the wind blows to', () => {
|
||||
assert.equal(windArrowDeg(0), 180);
|
||||
assert.equal(windArrowDeg(270), 90);
|
||||
assert.equal(windArrowDeg(200), 20);
|
||||
assert.equal(windArrowDeg(null), null);
|
||||
});
|
||||
|
||||
test('fKmh rounds to whole km/u', () => {
|
||||
assert.equal(fKmh(8.4), '8 km/u');
|
||||
assert.equal(fKmh(8.6), '9 km/u');
|
||||
assert.equal(fKmh(null), '–');
|
||||
});
|
||||
|
||||
test('formatHour gives a two-digit hour in the station timezone', () => {
|
||||
assert.equal(formatHour('2026-09-14T00:00:00+02:00', TZ), '00');
|
||||
assert.equal(formatHour('2026-09-14T14:00:00+02:00', TZ), '14');
|
||||
assert.equal(formatHour('2026-09-13T23:00:00Z', TZ), '01', '23:00 UTC is 01:00 de volgende dag in Berlijn');
|
||||
assert.equal(formatHour(null, TZ), '–');
|
||||
});
|
||||
|
||||
test('formatFullDate matches formatDate for the same calendar date', () => {
|
||||
assert.equal(formatFullDate('2026-09-14', TZ), 'Maandag 14 september');
|
||||
assert.equal(formatFullDate('kapot', TZ), '–');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user