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 hype = !intermission ? `
` : '';
return `
${teamRow(game, 'Away', 'live')}
${teamRow(game, 'Home', 'live')}
${hype}
`;
}
function renderPreGame(game) {
return `
${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 `
${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 === 'live' || state === 'final') && sog !== undefined
? `${sog} SOG` : '';
const ppHtml = pp ? `${pp}` : '';
const right = state === 'pre'
? `${record}`
: `${score}`;
return `
${name}
${sogHtml}${ppHtml}
${right}
`;
}
// ── 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);