| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
export const watching = (snap) => Boolean(snap) && (snap.spectator === true || !snap.me); |
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
const WHY = { |
| 19 |
address: "Somebody at this address is already playing — that tab holds the seat, and this one watches.", |
| 20 |
cookie: "This browser did not send the session cookie the page sets, so there is no seat to give it.", |
| 21 |
}; |
| 22 |
const WHY_UNSAID = "This connection has no seat, so it is watching the match."; |
| 23 |
|
| 24 |
const PHASE = { buy: "buy phase", live: "live", end: "round over" }; |
| 25 |
|
| 26 |
|
| 27 |
export function watchLines(snap) { |
| 28 |
const score = snap.score ?? { red: 0, blue: 0 }; |
| 29 |
return { |
| 30 |
title: "watching", |
| 31 |
why: WHY[snap.why] ?? WHY_UNSAID, |
| 32 |
phase: `round ${snap.round ?? 1} · ${PHASE[snap.phase] ?? "match over"} · ${snap.attackers ?? "—"} attacking${snap.result ? " · " + snap.result : ""}`, |
| 33 |
score: `red ${score.red ?? 0} — ${score.blue ?? 0} blue`, |
| 34 |
clock: `${Math.ceil(Math.max(0, Number(snap.clock) || 0))}s`, |
| 35 |
note: "No map and no bodies: a watching connection is never told where anybody is.", |
| 36 |
}; |
| 37 |
} |
| 38 |
|
| 39 |
|
| 40 |
export function wrap(ctx, text, maxWidth) { |
| 41 |
const lines = []; |
| 42 |
let line = ""; |
| 43 |
for (const word of String(text).split(" ")) { |
| 44 |
const tried = line ? `${line} ${word}` : word; |
| 45 |
if (line && ctx.measureText(tried).width > maxWidth) { |
| 46 |
lines.push(line); |
| 47 |
line = word; |
| 48 |
} else line = tried; |
| 49 |
} |
| 50 |
if (line) lines.push(line); |
| 51 |
return lines; |
| 52 |
} |
| 53 |
|
| 54 |
|
| 55 |
|
| 56 |
|
| 57 |
|
| 58 |
|
| 59 |
export function drawWatching(ctx, snap, width, height) { |
| 60 |
const lines = watchLines(snap); |
| 61 |
const mid = width / 2; |
| 62 |
const unit = Math.min(width / 900, height / 570); |
| 63 |
ctx.fillStyle = "#0b0d11"; |
| 64 |
ctx.fillRect(0, 0, width, height); |
| 65 |
ctx.textAlign = "center"; |
| 66 |
|
| 67 |
ctx.fillStyle = "#8b93a5"; |
| 68 |
ctx.font = `${Math.round(22 * unit)}px system-ui, sans-serif`; |
| 69 |
ctx.fillText(lines.title, mid, height * 0.3); |
| 70 |
|
| 71 |
ctx.fillStyle = "#e7e9ee"; |
| 72 |
ctx.font = `${Math.round(54 * unit)}px system-ui, sans-serif`; |
| 73 |
ctx.fillText(lines.score, mid, height * 0.42); |
| 74 |
|
| 75 |
ctx.font = `${Math.round(30 * unit)}px system-ui, sans-serif`; |
| 76 |
ctx.fillText(lines.clock, mid, height * 0.52); |
| 77 |
|
| 78 |
ctx.fillStyle = "#b9c0cf"; |
| 79 |
ctx.font = `${Math.round(19 * unit)}px system-ui, sans-serif`; |
| 80 |
ctx.fillText(lines.phase, mid, height * 0.6); |
| 81 |
|
| 82 |
ctx.fillStyle = "#8b93a5"; |
| 83 |
ctx.font = `${Math.round(17 * unit)}px system-ui, sans-serif`; |
| 84 |
let y = height * 0.7; |
| 85 |
for (const line of [...wrap(ctx, lines.why, width * 0.8), ...wrap(ctx, lines.note, width * 0.8)]) { |
| 86 |
ctx.fillText(line, mid, y); |
| 87 |
y += 24 * unit; |
| 88 |
} |
| 89 |
ctx.textAlign = "left"; |
| 90 |
return lines; |
| 91 |
} |