mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-29 09:23:16 -06:00
* Add PIP-Weather-Radar example (TV-style live radar overlay) A "cut to radar" PiP recipe: a Leaflet map (vendored locally for the CSP) with a CARTO dark basemap, an animated RainViewer radar loop, and live NWS warning polygons drawn and color-coded (tornado/severe-tstorm/ flash-flood/flood) with a pulsing "LIVE RADAR" HUD, count chips, and a legend. Auto-frames the view to the active warning polygon(s). Two modes: "always" (radar always up) and "on_warning" (default) which shows the radar only while a qualifying warning covers the configured point and clears it when the warnings expire — like a station breaking in during severe weather. 100% keyless / open data: RainViewer radar, CARTO/OSM basemap, NWS alerts. Zero Node deps; Leaflet is vendored client-side via vendor-leaflet.sh (gitignored). Offline test covers the warning gate, color map, RainViewer tile-URL builder, and overlay-URI round-trip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(radar): note Leaflet is vendored locally, not committed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
50 lines
3 KiB
JavaScript
50 lines
3 KiB
JavaScript
'use strict';
|
|
const r = require('./radar');
|
|
|
|
let pass = true;
|
|
const checks = [];
|
|
function ok(name, cond) { checks.push([name, !!cond]); if (!cond) pass = false; }
|
|
|
|
// fixture: NWS-style FeatureCollection
|
|
const now = Date.parse('2026-06-18T22:00:00Z');
|
|
const fc = {
|
|
type: 'FeatureCollection',
|
|
features: [
|
|
{ id: 'A', properties: { id: 'A', event: 'Tornado Warning', severity: 'Extreme', expires: '2026-06-18T22:30:00Z', headline: 'TOR until 5:30' }, geometry: { type: 'Polygon', coordinates: [[[0, 0]]] } },
|
|
{ id: 'B', properties: { id: 'B', event: 'Flood Warning', severity: 'Severe', expires: '2026-06-18T21:00:00Z', headline: 'expired' }, geometry: { type: 'Polygon', coordinates: [[[0, 0]]] } },
|
|
{ id: 'C', properties: { id: 'C', event: 'Heat Advisory', severity: 'Moderate', expires: '2026-06-19T00:00:00Z', headline: 'not a warning' }, geometry: { type: 'Polygon', coordinates: [[[0, 0]]] } },
|
|
{ id: 'D', properties: { id: 'D', event: 'Severe Thunderstorm Warning', severity: 'Severe', expires: '2026-06-18T22:45:00Z', headline: 'SVR' }, geometry: null },
|
|
],
|
|
};
|
|
const alerts = r.normaliseFeatureCollection(fc);
|
|
const byId = Object.fromEntries(alerts.map((a) => [a.identifier, a]));
|
|
|
|
ok('normalise parses 4', alerts.length === 4);
|
|
ok('normalise reads geometry flag', byId.A.hasGeometry === true && byId.D.hasGeometry === false);
|
|
|
|
const EV = ['Tornado Warning', 'Severe Thunderstorm Warning', 'Flash Flood Warning', 'Flood Warning'];
|
|
ok('qualifies: active tornado w/ polygon', r.qualifies(byId.A, { events: EV, now }) === true);
|
|
ok('qualifies: expired excluded', r.qualifies(byId.B, { events: EV, now }) === false);
|
|
ok('qualifies: non-listed event excluded', r.qualifies(byId.C, { events: EV, now }) === false);
|
|
ok('qualifies: missing geometry excluded', r.qualifies(byId.D, { events: EV, now }) === false);
|
|
|
|
ok('color: tornado red', r.colorForEvent('Tornado Warning') === '#FF2D2D');
|
|
ok('color: svr yellow', r.colorForEvent('Severe Thunderstorm Warning') === '#FFD12E');
|
|
ok('color: unknown -> default', r.colorForEvent('Dust Storm Warning') === r.DEFAULT_COLOR);
|
|
|
|
const url = r.frameTileUrl('https://tilecache.rainviewer.com', '/v2/radar/abc', 5, 8, 12);
|
|
ok('rainviewer tile url', url === 'https://tilecache.rainviewer.com/v2/radar/abc/256/5/8/12/4/1_1.png');
|
|
|
|
const uri = r.buildOverlayUri('https://s/radar-overlay.html', {
|
|
lat: 43.0389, lon: -87.9065, zoom: 8, area: 'Milwaukee County, WI', states: ['WI'], events: EV,
|
|
});
|
|
const back = new URLSearchParams(uri.split('?')[1]);
|
|
ok('overlay uri: lat/lon round-trip', back.get('lat') === '43.0389' && back.get('lon') === '-87.9065');
|
|
ok('overlay uri: area round-trip', back.get('area') === 'Milwaukee County, WI');
|
|
ok('overlay uri: states/events joined', back.get('states') === 'WI' && back.get('events') === EV.join(','));
|
|
|
|
console.log(`Weather-Radar checks (${checks.filter((c) => c[1]).length}/${checks.length}):`);
|
|
for (const [name, good] of checks) console.log(` ${good ? '✓' : '✗'} ${name}`);
|
|
console.log('\nRESULT:', pass ? 'PASS ✅' : 'FAIL ❌');
|
|
process.exit(pass ? 0 : 1);
|