153 lines
5.4 KiB
JavaScript
153 lines
5.4 KiB
JavaScript
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
|
|
? `<span class="badge">${intermissionLabel(period)}</span>`
|
|
: `<span class="badge badge-live">${ordinalPeriod(period)}</span>`;
|
|
|
|
const dot = running ? `<span class="live-dot"></span>` : '';
|
|
|
|
const hype = !intermission ? `
|
|
<div class="hype-meter">
|
|
<span class="hype-label">Hype Meter</span>
|
|
<div class="gauge-track">
|
|
<div class="gauge" data-score="${game['Priority']}"></div>
|
|
</div>
|
|
</div>` : '';
|
|
|
|
return `
|
|
<div class="game-box">
|
|
<div class="card-header">
|
|
<div class="badges">
|
|
${periodLabel}
|
|
<span class="badge">${time}</span>
|
|
</div>
|
|
${dot}
|
|
</div>
|
|
${teamRow(game, 'Away', 'live')}
|
|
${teamRow(game, 'Home', 'live')}
|
|
${hype}
|
|
</div>`;
|
|
}
|
|
|
|
function renderPreGame(game) {
|
|
return `
|
|
<div class="game-box">
|
|
<div class="card-header">
|
|
<div class="badges">
|
|
<span class="badge">${game['Start Time']}</span>
|
|
</div>
|
|
</div>
|
|
${teamRow(game, 'Away', 'pre')}
|
|
${teamRow(game, 'Home', 'pre')}
|
|
</div>`;
|
|
}
|
|
|
|
function renderFinalGame(game) {
|
|
const labels = { REG: 'Final', OT: 'Final/OT', SO: 'Final/SO' };
|
|
const label = labels[game['Last Period Type']] ?? 'Final';
|
|
return `
|
|
<div class="game-box">
|
|
<div class="card-header">
|
|
<div class="badges">
|
|
<span class="badge badge-muted">${label}</span>
|
|
</div>
|
|
</div>
|
|
${teamRow(game, 'Away', 'final')}
|
|
${teamRow(game, 'Home', 'final')}
|
|
</div>`;
|
|
}
|
|
|
|
// ── 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
|
|
? `<span class="team-sog">${sog} SOG</span>` : '';
|
|
const ppHtml = pp ? `<span class="team-pp">${pp}</span>` : '';
|
|
|
|
const right = state === 'pre'
|
|
? `<span class="team-record">${record}</span>`
|
|
: `<span class="team-score">${score}</span>`;
|
|
|
|
return `
|
|
<div class="team-row">
|
|
<img src="${logo}" alt="${name} logo" class="team-logo">
|
|
<div class="team-meta">
|
|
<span class="team-name">${name}</span>
|
|
${sogHtml}${ppHtml}
|
|
</div>
|
|
${right}
|
|
</div>`;
|
|
}
|
|
|
|
// ── 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);
|