Player Better

This commit is contained in:
RochesterX
2025-11-28 19:25:31 -05:00
parent ec77c0b268
commit 43c7068724
5 changed files with 160 additions and 30 deletions

View File

@@ -13,6 +13,7 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
table-layout: auto;
} }
.header { .header {
@@ -58,6 +59,45 @@ body {
grid-area: sw; grid-area: sw;
} }
.cursor-question {
cursor: help;
position: relative;
display: inline-block;
}
.cursor-question .tooltip-text {
visibility: hidden;
font: 16px tahoma, sans-serif;
width: 200px;
background-color: #0C0C0C;
border: 2px solid #EEEEEE;
color: #EEEEEE;
text-align: left;
border-radius: 6px;
padding: 5px;
padding-left: 8px;
padding-right: 8px;
z-index: 1;
position: absolute;
top: 110%;
left: 50%;
transform: translate(-50%, 20px);
opacity: 0;
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
font-size: 14px;
}
.cursor-question:hover {
text-decoration: underline;
}
.cursor-question:hover .tooltip-text {
visibility: visible;
transform: translate(-50%, 0px);
opacity: 1;
}
.box { .box {
border: 2px solid #AAAAAA; border: 2px solid #AAAAAA;
border-radius: 16px; border-radius: 16px;
@@ -69,11 +109,46 @@ body {
justify-content: flex-start; justify-content: flex-start;
text-justify: center; text-justify: center;
gap: 5px; gap: 5px;
overflow: hidden;
}
.box table {
width: 100%;
}
.box tbody {
display: block;
overflow-y: auto;
overflow-x: hidden;
max-height: calc((100vh - 100px) / 2 - 100px);
}
.box thead,
.box tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
.box table td:first-child,
.box table th:first-child {
width: 35px;
white-space: nowrap;
}
.box table thead td {
font-weight: bold;
}
.box table td:nth-child(2),
.box table th:nth-child(2) {
width: 50px;
white-space: nowrap;
} }
.grid-container { .grid-container {
display: grid; display: grid;
grid-template-columns: 50px, 50px; grid-template-columns: 1fr 1fr;
grid-template-rows: auto; grid-template-rows: auto;
grid-template-areas: grid-template-areas:
"header header" "header header"
@@ -287,12 +362,12 @@ a:focus {
table { table {
border-collapse: collapse; border-collapse: collapse;
border: 2px solid #CCCCCC; border: 1px solid #CCCCCC;
} }
thead { thead {
color: #FFFFFF; color: #FFFFFF;
border: 2px solid #CCCCCC; /*border: 2px solid #CCCCCC;*/
} }
thead th { thead th {

View File

@@ -24,7 +24,7 @@ async function updateOffense() {
const offenseBody = document.querySelector("#offense tbody"); const offenseBody = document.querySelector("#offense tbody");
let resultObject = await postData("/getHighestOffense", { amount: 10 }, token); let resultObject = await postData("/getHighestOffense", { amount: 100 }, token);
console.log(resultObject); console.log(resultObject);
if (resultObject.matches.length === 0) { if (resultObject.matches.length === 0) {
@@ -38,6 +38,7 @@ async function updateOffense() {
// headerRow.innerHTML += `<td>${attribute}</td>`; // headerRow.innerHTML += `<td>${attribute}</td>`;
//}); //});
headerRow.innerHTML = ` headerRow.innerHTML = `
<td>Rank</td>
<td>Position</td> <td>Position</td>
<td>Name</td> <td>Name</td>
<td>Team</td> <td>Team</td>
@@ -46,14 +47,17 @@ async function updateOffense() {
offenseHeader.appendChild(headerRow); offenseHeader.appendChild(headerRow);
offenseBody.innerHTML = ""; offenseBody.innerHTML = "";
let i = 0;
resultObject.matches.forEach(player => { resultObject.matches.forEach(player => {
i++;
const row = document.createElement("tr"); const row = document.createElement("tr");
row.innerHTML = ` row.innerHTML = `
<td>${i}</td>
<td>${player.Position}</td> <td>${player.Position}</td>
<td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td> <td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td>
<td>${player.Team}</td> <td>${player.Team}</td>
<td>${(player.OffenseScore + "000000").slice(0, 8)}</td> <td>${Math.floor(player.OffenseScore)}</td>
`; `;
offenseBody.appendChild(row); offenseBody.appendChild(row);
}); });
@@ -67,7 +71,7 @@ async function updatePaydirt() {
const paydirtBody = document.querySelector("#paydirt tbody"); const paydirtBody = document.querySelector("#paydirt tbody");
let resultObject = await postData("/getHighestPaydirt", { amount: 10 }, token); let resultObject = await postData("/getHighestPaydirt", { amount: 100 }, token);
console.log(resultObject); console.log(resultObject);
if (resultObject.matches.length === 0) { if (resultObject.matches.length === 0) {
@@ -81,6 +85,7 @@ async function updatePaydirt() {
// headerRow.innerHTML += `<td>${attribute}</td>`; // headerRow.innerHTML += `<td>${attribute}</td>`;
//}); //});
headerRow.innerHTML = ` headerRow.innerHTML = `
<td>Rank</td>
<td>Position</td> <td>Position</td>
<td>Name</td> <td>Name</td>
<td>Team</td> <td>Team</td>
@@ -89,14 +94,17 @@ async function updatePaydirt() {
paydirtHeader.appendChild(headerRow); paydirtHeader.appendChild(headerRow);
paydirtBody.innerHTML = ""; paydirtBody.innerHTML = "";
let i = 0;
resultObject.matches.forEach(player => { resultObject.matches.forEach(player => {
i++;
const row = document.createElement("tr"); const row = document.createElement("tr");
row.innerHTML = ` row.innerHTML = `
<td>${i}</td>
<td>${player.Position}</td> <td>${player.Position}</td>
<td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td> <td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td>
<td>${player.Team}</td> <td>${player.Team}</td>
<td>${(player.PaydirtScore + "000000").slice(0, 8)}</td> <td>${Math.floor(player.PaydirtScore)}</td>
`; `;
paydirtBody.appendChild(row); paydirtBody.appendChild(row);
}); });
@@ -108,7 +116,7 @@ async function updateHighest() {
const tableHeader = document.querySelector("#highest thead"); const tableHeader = document.querySelector("#highest thead");
const tableBody = document.querySelector("#highest tbody"); const tableBody = document.querySelector("#highest tbody");
let resultObject = await postData("/getHighest", { amount: 10 }, token); let resultObject = await postData("/getHighest", { amount: 100 }, token);
console.log(resultObject); console.log(resultObject);
if (resultObject.matches.length === 0) { if (resultObject.matches.length === 0) {
@@ -122,25 +130,29 @@ async function updateHighest() {
// headerRow.innerHTML += `<td>${attribute}</td>`; // headerRow.innerHTML += `<td>${attribute}</td>`;
//}); //});
headerRow.innerHTML = ` headerRow.innerHTML = `
<td>Name</td> <td>Rank</td>
<td>Contract</td>
<td>Team</td>
<td>Position</td> <td>Position</td>
<td>Name</td>
<td>Team</td>
<td>Contract</td>
`; `;
tableHeader.appendChild(headerRow); tableHeader.appendChild(headerRow);
tableBody.innerHTML = ""; tableBody.innerHTML = "";
let i = 0;
resultObject.matches.forEach(player => { resultObject.matches.forEach(player => {
i++;
const row = document.createElement("tr"); const row = document.createElement("tr");
//for (attribute in player) { //for (attribute in player) {
// row.innerHTML += `<td>${player}</td>l`; // row.innerHTML += `<td>${player}</td>l`;
//} //}
row.innerHTML = ` row.innerHTML = `
<td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td> <td>${i}</td>
<td>${formatSalary(player.TotalValue)}</td>
<td>${player.Team}</td>
<td>${player.Position}</td> <td>${player.Position}</td>
<td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td>
<td>${player.Team}</td>
<td>${formatSalary(player.TotalValue)}</td>
`; `;
tableBody.appendChild(row); tableBody.appendChild(row);
}); });
@@ -160,22 +172,35 @@ async function updateFavorites() {
// headerRow.innerHTML += `<td>${attribute}</td>`; // headerRow.innerHTML += `<td>${attribute}</td>`;
//}); //});
headerRow.innerHTML = ` headerRow.innerHTML = `
<td>Rank</td>
<td>Position</td>
<td>Name</td> <td>Name</td>
<td>Team</td> <td>Team</td>
<td>Position</td> <td>Remove</td>
`; `;
tableHeader.appendChild(headerRow); tableHeader.appendChild(headerRow);
tableBody.innerHTML = ""; tableBody.innerHTML = "";
console.log(resultObject.watchlist); console.log(resultObject.watchlist);
let i = 0;
resultObject.watchlist.forEach(player => { resultObject.watchlist.forEach(player => {
i++;
const row = document.createElement("tr"); const row = document.createElement("tr");
row.innerHTML = ` row.innerHTML = `
<td>${i}</td>
<td>${player.Position}</td>
<td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td> <td><a href="/player/${player.PlayerID}">${player.PlayerName}</a></td>
<td>${player.Team}</td> <td>${player.Team}</td>
<td>${player.Position}</td> <td><a href="#" class="remove" data-id="${player.PlayerID}">Stop Watching</a></td>
`; `;
tableBody.appendChild(row); tableBody.appendChild(row);
}); });
document.querySelectorAll(".remove").forEach(element => {
element.addEventListener("click", async e => {
postData("/toggleWatched", { id: element.dataset.id }, token);
element.closest("tr").remove();
})
});
}; };

View File

@@ -20,14 +20,29 @@
</div> </div>
<div class="info"> <div class="info">
<p><b>Height:</b></p> <p><b>Height:</b></p>
<p class="attribute-Height"></p> <p class="attribute-Height format-height"></p>
</div> </div>
<div class="info"> <div class="info">
<p><b>Weight:</b></p> <p><b>Weight:</b></p>
<p class="attribute-Weight"></p> <p class="attribute-Weight format-weight"></p>
</div>
</div>
<div class="info-container">
<div class="info">
<div class="cursor-question">
<p><b>PayDirt Score:</b></p>
<span class="tooltip-text">A player's <b>PayDirt score</b> is calculated by weighting their offense score by their APY. It is used to evaluate the worth of their contract.</span>
</div>
<p class="attribute-PaydirtScore format-integer"></p>
</div>
<div class="info">
<div class="cursor-question">
<p><b>Offense Score:</b></p>
<span class="tooltip-text">A player's <b>offense score</b> is calculated by combining several of their offense stats into a weighted score. It is indicative of their overall performance.</span>
</div>
<p class="attribute-OffenseScore format-integer"></p>
</div> </div>
</div> </div>
<table id="overview"> <table id="overview">
<thead></thead> <thead></thead>
<tbody></tbody> <tbody></tbody>

View File

@@ -62,8 +62,8 @@ async function populatePlayerData() {
const playerStatsObject = resultObject.matches; const playerStatsObject = resultObject.matches;
let playerObjectResult = await postData("/getPlayer", { let playerObjectResult = await postData("/getPlayerScores", {
id: id playerID: id
}, token); }, token);
if (playerObjectResult.success === false) { if (playerObjectResult.success === false) {
console.log("Invalid ID"); console.log("Invalid ID");
@@ -71,10 +71,23 @@ async function populatePlayerData() {
} }
const playerObject = playerObjectResult.match; const playerObject = playerObjectResult.match;
console.log(playerObjectResult);
for (const [attribute, value] of Object.entries(playerObject)) { for (const [attribute, value] of Object.entries(playerObject)) {
console.log(`.attribute-${attribute}`); console.log(`.attribute-${attribute}`);
document.querySelectorAll(`.attribute-${attribute}`).forEach(element => { document.querySelectorAll(`.attribute-${attribute}`).forEach(element => {
if (element.classList.contains("format-weight")) {
element.textContent = value + " lbs";
return;
}
if (element.classList.contains("format-height")) {
element.textContent = `${value.split("-")[0]}' ${value.split("-")[1]}"`;
return;
}
if (element.classList.contains("format-integer")) {
element.textContent = Math.floor(value);
return;
}
if (element.classList.contains("format-salary")) { if (element.classList.contains("format-salary")) {
element.textContent = formatSalary(value); element.textContent = formatSalary(value);
return; return;
@@ -82,7 +95,7 @@ async function populatePlayerData() {
element.textContent = value; element.textContent = value;
}) })
}; };
createStatsTable(playerStatsObject); createStatsTable(playerStatsObject);
createOverviewTable(playerObject); createOverviewTable(playerObject);
} }
@@ -158,9 +171,9 @@ async function createStatsTable(playerObject) {
// row.innerHTML += `<td>${player}</td>l`; // row.innerHTML += `<td>${player}</td>l`;
//} //}
rowElement.innerHTML = ` rowElement.innerHTML = `
<td>${row.Season}</td> <td>${row.season}</td>
<td>${row.SeasonType === "REG" ? "Regular" : "Post"}</td> <td>${row.SeasonType === "REG" ? "Regular" : "Post"}</td>
<td>${row.Week}</td> <td>${row.week}</td>
<td>${row.pass_attempts}</td> <td>${row.pass_attempts}</td>
<td>${row.complete_pass}</td> <td>${row.complete_pass}</td>
<td>${row.total_yards}</td> <td>${row.total_yards}</td>

View File

@@ -250,8 +250,8 @@ app.post("/getPlayerStats", authenticate, async (req, res) => {
const result = await pool.request() const result = await pool.request()
.input("playerID", sql.Int, playerID) .input("playerID", sql.Int, playerID)
.query(` .query(`
SELECT Player.PlayerID, Player.PlayerName, Season, SeasonType, Week, pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble SELECT player.playerid, player.playername, season, seasontype, week, pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble
FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID fROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID
WHERE Player.PlayerID = @playerID WHERE Player.PlayerID = @playerID
ORDER BY Season, week; ORDER BY Season, week;
`); `);
@@ -266,6 +266,7 @@ app.post("/getPlayerScores", authenticate, async (req, res) => {
.input("playerID", sql.Int, playerID) .input("playerID", sql.Int, playerID)
.query(` .query(`
SELECT Player.PlayerID, Player.[Position], Player.PlayerName, Player.Team, SELECT Player.PlayerID, Player.[Position], Player.PlayerName, Player.Team,
c.TotalValue, c.TrueAvgPerYear, c.Years, c.StartYear, c.EndYear, Player.Height, Player.Weight,
SUM(total_yards) AS TotalYards, SUM(total_yards) AS TotalYards,
SUM(passing_yards) AS PassingYards, SUM(passing_yards) AS PassingYards,
SUM(rushing_yards) AS RushingYards, SUM(rushing_yards) AS RushingYards,
@@ -306,13 +307,14 @@ AvgPerYear,
- (SUM(safety) * 100.0)) / AvgPerYear * 1000000 AS PaydirtScore - (SUM(safety) * 100.0)) / AvgPerYear * 1000000 AS PaydirtScore
FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID JOIN Contract ON Player.PlayerID = Contract.PlayerID FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID JOIN Contract AS c ON Player.PlayerID = c.PlayerID
WHERE season = 2024 AND SeasonType = 'REG' AND Player.PlayerID = @playerID WHERE season = 2024 AND SeasonType = 'REG' AND Player.PlayerID = @playerID
GROUP BY Player.PlayerID, Player.PlayerName, Player.Team, Player.[Position], Contract.AvgPerYear GROUP BY c.TotalValue, c.TrueAvgPerYear, c.Years, c.StartYear, Player.Height, Player.Weight, c.EndYear, Player.PlayerID, Player.PlayerName, Player.Team, Player.[Position], c.AvgPerYear
ORDER BY PaydirtScore DESC; ORDER BY PaydirtScore DESC;
`); `);
console.log(result.recordset);
res.status(200).json({ matches: result.recordset }); res.status(200).json({ match: result.recordset[0] });
}); });
@@ -378,7 +380,7 @@ app.post("/getPlayer", authenticate, async (req, res) => {
const result = await pool.request() const result = await pool.request()
.input("query", sql.VarChar, id) .input("query", sql.VarChar, id)
.query(`SELECT p.PlayerName, p.PlayerID, c.TotalValue, c.TrueAvgPerYear, c.Years, c.StartYear, c.EndYear, p.Team, p.Position, p.Height, p.Weight FROM Player AS p JOIN Contract AS c ON p.PlayerID = c.PlayerID WHERE p.PlayerID = @query`); .query(`SELECT p.PlayerName, p.PlayerID, c.TotalValue, c.TrueAvgPerYear, c.Years, c.StartYear, c.EndYear, p.Team, p.Position FROM Player AS p JOIN Contract AS c ON p.PlayerID = c.PlayerID WHERE p.PlayerID = @query`);
if (result.recordset.length !== 1) { if (result.recordset.length !== 1) {
res.status(400).json({ success: false }) res.status(400).json({ success: false })