// ── Render table ─────────────────────────────────────────────
{
if (football_data == null || football_data.length === 0) {
return html`<p class="text-muted">Ratings data could not be loaded. Try refreshing the page.</p>`
}
const footballPosColors = window.footballMaps.posColors
const posBadge = (val) => window.posBadge(val, footballPosColors)
const isValue = statCategory === "Value"
const defs = window.footballStatDefs || {}
// Stat category view
if (!isValue) {
const data = statTableData
if (!data || data.length === 0) {
const failed = footballSkills === null
return html`<p class="text-muted">${failed ? "Rating data could not be loaded. Try refreshing." : "Loading rating data..."}</p>`
}
const catKey = Object.keys(defs).find(k => defs[k].label === statCategory)
const catDef = catKey ? defs[catKey] : null
if (!catDef) return html`<p class="text-muted">Category not found.</p>`
const statCols = catDef.columns.map(c => c + "_r").filter(c => data[0] && data[0][c] !== undefined)
const headerMap = {}; const heatmapMap = {}; const tooltipMap = {}
for (const col of catDef.columns) {
headerMap[col + "_r"] = catDef.header[col] || col
heatmapMap[col + "_r"] = catDef.heatmap?.[col] || "high-good"
if (catDef.tooltip?.[col]) tooltipMap[col + "_r"] = catDef.tooltip[col]
}
const mStatCols = (catDef.mobileCols || catDef.columns.slice(0, 3)).map(c => c + "_r").filter(c => statCols.includes(c))
const tableEl = statsTable(football_search, {
columns: ["player_name", "league", "position", ...statCols],
mobileCols: ["player_name", "position", ...mStatCols],
header: { player_name: "Player", league: "League", position: "Pos", ...headerMap },
groups: [{ label: "Player", span: 3 }, { label: statCategory + " (per 90 min)", span: statCols.length }],
format: Object.fromEntries(statCols.map(c => [c, x => x?.toFixed(2) ?? ""])),
tooltip: tooltipMap,
render: {
player_name: (v, row) => {
const pos = footballPosColors[row.position] || { a: String(row.position || "").substring(0, 3), c: "#9ca3af" }
const crest = window.footballMaps.teamCrest(row.team)
const badge = crest ? `<img src="${statsEsc(crest)}" alt="" style="width:14px;height:14px;object-fit:contain;vertical-align:middle;margin-right:2px">` : ""
return `<a href="player.html#name=${encodeURIComponent(v)}" class="player-link"><strong>${statsEsc(v)}</strong><span class="player-sub">${badge}<a href="team.html#team=${encodeURIComponent(row.team)}" class="team-link">${statsEsc(row.team)}</a> · ${statsEsc(pos.a)}</span></a>`
},
league: (v) => statsEsc(String(v || "").replace(/_/g, " ")),
position: posBadge
},
heatmap: heatmapMap,
heatmapData: data,
sort: statCols[0] || "player_name", reverse: true, rows: 25
})
const wrap = document.createElement("div")
wrap.className = "ratings-table-view"
wrap.style.display = window["_viewMode_" + window.location.pathname.replace(/[^a-z0-9]/gi, "_")] === "Table" ? "" : "none"
wrap.appendChild(tableEl)
return wrap
}
// Value view (original)
const valueEl = statsTable(football_search, {
columns: ["panna_rank", "player_name", "league", "position", "panna", "offense", "defense", "spm_overall", "total_minutes", "panna_percentile"],
mobileCols: ["panna_rank", "player_name", "position", "panna", "offense", "defense"],
header: {
panna_rank: "#",
player_name: "Player",
league: "League",
position: "Pos",
panna: "Panna",
offense: "Off",
defense: "Def",
spm_overall: "SPM",
total_minutes: "Mins",
panna_percentile: "Pctl"
},
groups: [
{ label: "", span: 1 },
{ label: "Player", span: 3 },
{ label: "Rating", span: 1 },
{ label: "Components", span: 3 },
{ label: "", span: 2 }
],
format: {
panna: x => x?.toFixed(3) ?? "",
offense: x => x?.toFixed(3) ?? "",
defense: x => x?.toFixed(3) ?? "",
spm_overall: x => x?.toFixed(3) ?? "",
total_minutes: x => x?.toLocaleString() ?? "",
panna_percentile: x => x != null ? x.toFixed(1) : ""
},
render: {
player_name: (v, row) => {
const pos = footballPosColors[row.position] || { a: String(row.position || "").substring(0, 3), c: "#9ca3af" }
const href = `player.html#name=${encodeURIComponent(v)}`
const crest = window.footballMaps.teamCrest(row.team)
const badge = crest ? `<img src="${statsEsc(crest)}" alt="" style="width:14px;height:14px;object-fit:contain;vertical-align:middle;margin-right:2px">` : ""
return `<a href="${href}" class="player-link"><strong>${statsEsc(v)}</strong><span class="player-sub">${badge}<a href="team.html#team=${encodeURIComponent(row.team)}" class="team-link">${statsEsc(row.team)}</a> · ${statsEsc(pos.a)}</span></a>`
},
panna_rank: (v) => `<span style="color:#8b929e">${statsEsc(String(v ?? ""))}</span>`,
league: (v) => statsEsc(String(v || "").replace(/_/g, " ")),
position: posBadge
},
heatmap: {
panna: "high-good",
offense: "high-good",
defense: "low-good",
spm_overall: "high-good",
panna_percentile: "high-good"
},
heatmapData: football_data,
filters: {
panna: "range",
total_minutes: "range",
panna_percentile: "range"
},
sort: "panna_rank",
rows: 25
})
const wrap = document.createElement("div")
wrap.className = "ratings-table-view"
wrap.appendChild(valueEl)
return wrap
}