X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ultimate.js;h=32dd2493d539260fd12a2df4e77600e3cdd53bf1;hb=5ccdfdea87f84fcc4d6c981a88dacd1127ab7106;hp=0100f6a3b59ed2f1fdda858c5c4ee8efa16be388;hpb=7a960fbf75a145f30e34f5f803062d91afb81165;p=pkanalytics diff --git a/ultimate.js b/ultimate.js index 0100f6a..32dd249 100644 --- a/ultimate.js +++ b/ultimate.js @@ -49,7 +49,17 @@ function add_cell(tr, element_type, text) { } function add_th(tr, text, colspan) { - let element = add_cell(tr, 'th', text); + let element = document.createElement('th'); + let link = document.createElement('a'); + link.style.cursor = 'pointer'; + link.addEventListener('click', (e) => { + sort_by(element); + process_matches(global_json, global_filters); + }); + link.textContent = text; + element.appendChild(link); + tr.appendChild(element); + if (colspan > 0) { element.setAttribute('colspan', colspan); } else { @@ -729,19 +739,20 @@ function make_table_general(players) { rows.push(header); } - for (const [q,p] of Object.entries(players)) { + for (const [q,p] of get_sorted_players(players)) { if (q === 'globals') continue; let row = document.createElement('tr'); let pm = p.goals + p.assists + p.hockey_assists + p.defenses - p.throwaways - p.drops - p.was_ds; let soft_pm = p.offensive_soft_plus + p.defensive_soft_plus - p.offensive_soft_minus - p.defensive_soft_minus; let o_efficiency = make_efficiency_ci(p.offensive_points_won, p.offensive_points_completed, z); let d_efficiency = make_efficiency_ci(p.defensive_points_won, p.defensive_points_completed, z); - add_3cell(row, p.name, 'name'); // TODO: number? + let name = add_3cell(row, p.name, 'name'); // TODO: number? add_3cell(row, pm > 0 ? ('+' + pm) : pm); add_3cell(row, soft_pm > 0 ? ('+' + soft_pm) : soft_pm); add_3cell_ci(row, o_efficiency); add_3cell_ci(row, d_efficiency); add_3cell(row, p.points_played); + row.dataset.player = q; rows.push(row); } @@ -785,7 +796,7 @@ function make_table_offense(players) { let catches = 0; let drops = 0; let was_ds = 0; - for (const [q,p] of Object.entries(players)) { + for (const [q,p] of get_sorted_players(players)) { if (q === 'globals') continue; let throw_ok = make_binomial_ci(p.num_throws - p.throwaways, p.num_throws, z); let catch_ok = make_binomial_ci(p.catches, p.catches + p.drops + p.was_ds, z); @@ -811,6 +822,7 @@ function make_table_offense(players) { add_3cell_ci(row, catch_ok); add_3cell(row, '+' + p.offensive_soft_plus); add_3cell(row, '-' + p.offensive_soft_minus); + row.dataset.player = q; rows.push(row); num_throws += p.num_throws; @@ -860,7 +872,7 @@ function make_table_defense(players) { add_th(header, 'Soft +/-', 6); rows.push(header); } - for (const [q,p] of Object.entries(players)) { + for (const [q,p] of get_sorted_players(players)) { if (q === 'globals') continue; let sum_time = 0; for (const t of p.pull_times) { @@ -887,6 +899,7 @@ function make_table_defense(players) { } add_3cell(row, '+' + p.defensive_soft_plus); add_3cell(row, '-' + p.defensive_soft_minus); + row.dataset.player = q; rows.push(row); } return rows; @@ -907,7 +920,7 @@ function make_table_playing_time(players) { rows.push(header); } - for (const [q,p] of Object.entries(players)) { + for (const [q,p] of get_sorted_players(players)) { if (q === 'globals') continue; let row = document.createElement('tr'); add_3cell(row, p.name, 'name'); // TODO: number? @@ -918,6 +931,7 @@ function make_table_playing_time(players) { add_3cell(row, Math.floor(p.field_time_ms / 60000) + ' min'); add_3cell(row, p.offensive_points_completed); add_3cell(row, p.defensive_points_completed); + row.dataset.player = q; rows.push(row); } @@ -947,7 +961,7 @@ function make_table_per_point(players) { add_th(header, 'Hockey assists'); add_th(header, 'Ds'); add_th(header, 'Throwaways'); - add_th(header, 'Drops'); + add_th(header, 'Recv. errors'); add_th(header, 'Touches'); rows.push(header); } @@ -957,9 +971,9 @@ function make_table_per_point(players) { let hockey_assists = 0; let defenses = 0; let throwaways = 0; - let drops = 0; + let receiver_errors = 0; let touches = 0; - for (const [q,p] of Object.entries(players)) { + for (const [q,p] of get_sorted_players(players)) { if (q === 'globals') continue; // Can only happen once per point, so these are binomials. @@ -978,12 +992,13 @@ function make_table_per_point(players) { add_3cell_ci(row, ci_hockey_assists); add_3cell_ci(row, make_poisson_ci(p.defenses, p.points_played, z)); add_3cell_ci(row, make_poisson_ci(p.throwaways, p.points_played, z, true)); - add_3cell_ci(row, make_poisson_ci(p.drops, p.points_played, z, true)); + add_3cell_ci(row, make_poisson_ci(p.drops + p.was_ds, p.points_played, z, true)); if (p.points_played > 0) { add_3cell(row, p.touches == 0 ? 0 : (p.touches / p.points_played).toFixed(2)); } else { add_3cell(row, 'N/A'); } + row.dataset.player = q; rows.push(row); goals += p.goals; @@ -991,7 +1006,7 @@ function make_table_per_point(players) { hockey_assists += p.hockey_assists; defenses += p.defenses; throwaways += p.throwaways; - drops += p.drops; + receiver_errors += p.drops + p.was_ds; touches += p.touches; } @@ -1005,7 +1020,7 @@ function make_table_per_point(players) { add_3cell_with_filler_ci(row, hockey_assists == 0 ? 0 : (hockey_assists / globals.points_played).toFixed(2)); add_3cell_with_filler_ci(row, defenses == 0 ? 0 : (defenses / globals.points_played).toFixed(2)); add_3cell_with_filler_ci(row, throwaways == 0 ? 0 : (throwaways / globals.points_played).toFixed(2)); - add_3cell_with_filler_ci(row, drops == 0 ? 0 : (drops / globals.points_played).toFixed(2)); + add_3cell_with_filler_ci(row, receiver_errors == 0 ? 0 : (receiver_errors / globals.points_played).toFixed(2)); add_3cell(row, touches == 0 ? 0 : (touches / globals.points_played).toFixed(2)); } else { add_3cell_with_filler_ci(row, 'N/A'); @@ -1450,3 +1465,52 @@ function possibly_close_menu(e) { add_submenu.style.display = 'none'; } } + +let global_sort = {}; + +function sort_by(th) { + let tr = th.parentElement; + let child_idx = 0; + for (let column_idx = 0; column_idx < tr.children.length; ++column_idx) { + let element = tr.children[column_idx]; + if (element === th) { + ++child_idx; // Pad. + break; + } + if (element.hasAttribute('colspan')) { + child_idx += parseInt(element.getAttribute('colspan')); + } else { + ++child_idx; + } + } + + global_sort = {}; + let table = tr.parentElement; + for (let row_idx = 1; row_idx < table.children.length - 1; ++row_idx) { // Skip header and globals. + let row = table.children[row_idx]; + let player = parseInt(row.dataset.player); + let value = row.children[child_idx].textContent; + global_sort[player] = value; + } +} + +function get_sorted_players(players) +{ + let p = Object.entries(players); + if (global_sort.length !== 0) { + p.sort((a,b) => { + let ai = parseFloat(global_sort[a[0]]); + let bi = parseFloat(global_sort[b[0]]); + if (ai == ai && bi == bi) { + return bi - ai; // Reverse numeric. + } else if (global_sort[a[0]] < global_sort[b[0]]) { + return -1; + } else if (global_sort[a[0]] > global_sort[b[0]]) { + return 1; + } else { + return 0; + } + }); + } + return p; +}