-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
16 lines (16 loc) · 4.54 KB
/
Copy pathscript.js
File metadata and controls
16 lines (16 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const CANDIDATES=["combine_rookie_defensive_prediction_data_2026_v2_full_model_inputs_20260516_034524_CT.csv","data/combine_rookie_defensive_prediction_data_2026_v2_full_model_inputs_20260516_034524_CT.csv"];
const FALLBACK=["Flory Bidunga","Reuben Chinyelu","Trevon Brazile","Karim Lopez","Tarris Reed Jr.","Baba Miller","Aaron Nkrumah","Zuby Ejiofor","Yaxel Lendeborg","Matthew Able"].map(Player=>({Player,Predicted_DBPM:null,Wingspan_in:null,Shuttle_Run:null,Hand_Width:null}));
const state={players:FALLBACK,search:"",mode:"top10"};
const els={count:document.querySelector("#complete-count"),status:document.querySelector("#load-status"),error:document.querySelector("#leaderboard-error"),body:document.querySelector("#leaderboard-body"),cards:document.querySelector("#leaderboard-cards"),search:document.querySelector("#player-search"),modes:document.querySelectorAll('input[name="row-mode"]')};
function parseCsv(text){const rows=[];let row=[],field="",q=false;for(let i=0;i<text.length;i++){const c=text[i],n=text[i+1];if(c==='"'&&q&&n==='"'){field+='"';i++}else if(c==='"'){q=!q}else if(c===','&&!q){row.push(field.trim());field=""}else if((c==='\n'||c==='\r')&&!q){if(c==='\r'&&n==='\n')i++;row.push(field.trim());if(row.some(v=>v!==""))rows.push(row);row=[];field=""}else{field+=c}}row.push(field.trim());if(row.some(v=>v!==""))rows.push(row);const headers=rows.shift()||[];return rows.map(values=>headers.reduce((r,h,i)=>{r[h]=values[i]??"";return r},{}))}
function number(value){if(value===null||value===undefined||value==="")return null;const n=Number(String(value).replace(/[%,$]/g,""));return Number.isFinite(n)?n:null}
function truth(value){return ["true","1","yes","y"].includes(String(value).trim().toLowerCase())}
function first(record,keys){const key=keys.find(k=>record[k]!==undefined&&record[k]!=="");return key?record[key]:""}
function normalize(record){return{Player:first(record,["Player","Name","player"]),Predicted_DBPM:number(first(record,["Predicted_DBPM","predicted_dbpm","Prediction"])),Wingspan_in:number(first(record,["Wingspan_in","wingspan_in"])),Shuttle_Run:number(first(record,["Shuttle_Run","shuttle_run"])),Hand_Width:number(first(record,["Hand_Width","hand_width"])),Has_Full_Prediction_Inputs:truth(first(record,["Has_Full_Prediction_Inputs","has_full_prediction_inputs"]))}}
function fmt(v,d){return Number.isFinite(v)?v.toFixed(d):"—"}
function visible(){let list=state.players.filter(p=>p.Player.toLowerCase().includes(state.search.trim().toLowerCase()));return state.mode==="top10"?list.slice(0,10):list}
function render(){const players=visible();if(!players.length){els.body.innerHTML='<tr><td colspan="6">No players match the current search.</td></tr>';els.cards.innerHTML='<div class="empty-state">No players match the current search.</div>';return}els.body.innerHTML=players.map((p,i)=>`<tr><th>${i+1}</th><td>${p.Player}</td><td>${fmt(p.Predicted_DBPM,3)}</td><td>${fmt(p.Wingspan_in,2)}</td><td>${fmt(p.Shuttle_Run,2)}</td><td>${fmt(p.Hand_Width,2)}</td></tr>`).join("");els.cards.innerHTML=players.map((p,i)=>`<article class="player-card"><div class="player-card-header"><span class="rank-badge">#${i+1}</span><span class="player-name">${p.Player}</span></div><div class="stat-grid"><span>Predicted DBPM <b>${fmt(p.Predicted_DBPM,3)}</b></span><span>Wingspan <b>${fmt(p.Wingspan_in,2)} in</b></span><span>Shuttle Run <b>${fmt(p.Shuttle_Run,2)} sec</b></span><span>Hand Width <b>${fmt(p.Hand_Width,2)} in</b></span></div></article>`).join("")}
function setStatus(text,cls){els.status.textContent=text;els.status.className=`status-pill ${cls}`.trim()}
async function load(){let lastError;for(const path of CANDIDATES){try{const response=await fetch(path);if(!response.ok)throw new Error(`${path} (${response.status})`);const rows=parseCsv(await response.text()).map(normalize).filter(p=>p.Has_Full_Prediction_Inputs&&p.Player).sort((a,b)=>(b.Predicted_DBPM??-Infinity)-(a.Predicted_DBPM??-Infinity));if(!rows.length)throw new Error("CSV loaded, but no complete prediction rows were found");state.players=rows;els.count.textContent=String(rows.length);setStatus("CSV loaded","is-loaded");render();return}catch(error){lastError=error}}state.players=FALLBACK;els.count.textContent="71";setStatus("CSV unavailable","is-error");els.error.hidden=false;els.error.textContent=`${lastError?.message||"Could not load CSV"}. Showing the expected top-10 player names as a static fallback.`;render()}
els.search.addEventListener("input",event=>{state.search=event.target.value;render()});els.modes.forEach(input=>input.addEventListener("change",event=>{state.mode=event.target.value;render()}));
render();load();