// door ranges const doors = [ ...Array.from({length: 138 - 124 + 1}, (_, i) => 124 + i), ...Array.from({length: 201 - 142 + 1}, (_, i) => 142 + i), ...Array.from({length: 209 - 202 + 1}, (_, i) => 202 + i), ]; // NOAA heat‐index formula function getColorFromHI(H) { const pct = Math.min(Math.max((H - 70) / 30, 0), 1); const r = 255; const g = Math.round(255 * (1 - pct)); return `rgba(${r},${g},0,0.8)`; } function createGrid() { const row = document.getElementById('dock-row'); doors.forEach(d => { const sq = document.createElement('div'); sq.className = 'dock-square'; sq.dataset.door = d; row.appendChild(sq); }); } // apply a new reading to its square function colorize(door, hi) { const sq = document.querySelector(`.dock-square[data-door="${door}"]`); if (!sq) return; sq.style.background = getColorFromHI(hi); } async function init() { createGrid(); // initial fill const all = await fetch('/api/readings').then(r=>r.json()); // pick latest per door const latest = {}; all.forEach(r => { latest[r.dockDoor] = r.heatIndex; }); Object.entries(latest).forEach(([door, hi]) => colorize(door, hi)); // subscribe SSE const es = new EventSource('/api/stream'); es.addEventListener('new-reading', e => { const { dockDoor, heatIndex } = JSON.parse(e.data); colorize(dockDoor, heatIndex); }); } document.addEventListener('DOMContentLoaded', init);