async function fetchScoreboardData() { try { const res = await fetch('/scoreboard'); if (!res.ok) throw new Error(res.status); updateScoreboard(await res.json()); } catch (e) { console.error('Failed to fetch scoreboard data:', e); } } function updateScoreboard(data) { const sections = [ { sectionId: 'live-section', gridId: 'live-games-section', games: data.live_games, render: renderLiveGame }, { sectionId: 'pre-section', gridId: 'pre-games-section', games: data.pre_games, render: renderPreGame }, { sectionId: 'final-section', gridId: 'final-games-section', games: data.final_games, render: renderFinalGame }, ]; for (const { sectionId, gridId, games, render } of sections) { const section = document.getElementById(sectionId); const grid = document.getElementById(gridId); const hasGames = games && games.length > 0; section.classList.toggle('hidden', !hasGames); grid.innerHTML = hasGames ? games.map(render).join('') : ''; } updateGauges(); } // ── Renderers ──────────────────────────────────────── function renderLiveGame(game) { const intermission = game['Intermission']; const period = game['Period']; const time = game['Time Remaining']; const running = game['Time Running']; const periodLabel = intermission ? `${intermissionLabel(period)}` : `${ordinalPeriod(period)}`; const dot = running ? `` : ''; const shots = shotsBar(game['Away Shots'], game['Home Shots']); const hype = !intermission ? `
Hype Meter
` : ''; return `
${periodLabel} ${time}
${dot}
${teamRow(game, 'Away', 'live')} ${teamRow(game, 'Home', 'live')} ${shots} ${hype}
`; } function renderPreGame(game) { return `
${game['Start Time']}
${teamRow(game, 'Away', 'pre')} ${teamRow(game, 'Home', 'pre')}
`; } function renderFinalGame(game) { const labels = { REG: 'Final', OT: 'Final/OT', SO: 'Final/SO' }; const label = labels[game['Last Period Type']] ?? 'Final'; return `
${label}
${teamRow(game, 'Away', 'final')} ${teamRow(game, 'Home', 'final')}
`; } // ── Team Row ───────────────────────────────────────── function teamRow(game, side, state) { const name = game[`${side} Team`]; const logo = game[`${side} Logo`]; const score = game[`${side} Score`]; const sog = game[`${side} Shots`]; const pp = game[`${side} Power Play`]; const record = game[`${side} Record`]; const sogHtml = (state === 'final' && sog !== undefined) ? `${sog} SOG` : ''; const ppHtml = pp ? `${pp}` : ''; const right = state === 'pre' ? `${record}` : `${score}`; return `
${name} ${sogHtml}${ppHtml}
${right}
`; } // ── Shots Bar ──────────────────────────────────────── function shotsBar(away, home) { const total = (away || 0) + (home || 0); const awayPct = total > 0 ? (away / total) * 100 : 50; const homePct = total > 0 ? (home / total) * 100 : 50; return `
${away}
${home}
Shots on Goal
`; } // ── Gauge ──────────────────────────────────────────── function updateGauges() { document.querySelectorAll('.gauge').forEach(el => { const score = Math.min(700, Math.max(0, parseInt(el.dataset.score, 10))); el.style.width = `${(score / 700) * 100}%`; el.style.backgroundColor = score <= 300 ? '#4a90e2' : score <= 550 ? '#f97316' : '#ef4444'; }); } // ── Helpers ────────────────────────────────────────── function ordinalPeriod(period) { return ['1st', '2nd', '3rd', 'OT'][period - 1] ?? 'SO'; } function intermissionLabel(period) { return ['1st Int', '2nd Int', '3rd Int'][period - 1] ?? 'Int'; } // ── Init ───────────────────────────────────────────── function autoRefresh() { fetchScoreboardData(); setTimeout(autoRefresh, 5000); } window.addEventListener('load', autoRefresh);