diff --git a/public/assets/css/style.css b/public/assets/css/style.css index f81e833..4c946c8 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -13,6 +13,7 @@ body { display: flex; flex-direction: column; justify-content: flex-start; + table-layout: auto; } .header { @@ -58,6 +59,45 @@ body { 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 { border: 2px solid #AAAAAA; border-radius: 16px; @@ -69,11 +109,46 @@ body { justify-content: flex-start; text-justify: center; 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 { display: grid; - grid-template-columns: 50px, 50px; + grid-template-columns: 1fr 1fr; grid-template-rows: auto; grid-template-areas: "header header" @@ -287,12 +362,12 @@ a:focus { table { border-collapse: collapse; - border: 2px solid #CCCCCC; + border: 1px solid #CCCCCC; } thead { color: #FFFFFF; - border: 2px solid #CCCCCC; + /*border: 2px solid #CCCCCC;*/ } thead th { diff --git a/public/home.js b/public/home.js index 807c5fd..d9df785 100644 --- a/public/home.js +++ b/public/home.js @@ -24,7 +24,7 @@ async function updateOffense() { 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); if (resultObject.matches.length === 0) { @@ -38,6 +38,7 @@ async function updateOffense() { // headerRow.innerHTML += `${attribute}`; //}); headerRow.innerHTML = ` + Rank Position Name Team @@ -46,14 +47,17 @@ async function updateOffense() { offenseHeader.appendChild(headerRow); offenseBody.innerHTML = ""; + let i = 0; resultObject.matches.forEach(player => { + i++; const row = document.createElement("tr"); row.innerHTML = ` + ${i} ${player.Position} ${player.PlayerName} ${player.Team} - ${(player.OffenseScore + "000000").slice(0, 8)} + ${Math.floor(player.OffenseScore)} `; offenseBody.appendChild(row); }); @@ -67,7 +71,7 @@ async function updatePaydirt() { 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); if (resultObject.matches.length === 0) { @@ -81,6 +85,7 @@ async function updatePaydirt() { // headerRow.innerHTML += `${attribute}`; //}); headerRow.innerHTML = ` + Rank Position Name Team @@ -89,14 +94,17 @@ async function updatePaydirt() { paydirtHeader.appendChild(headerRow); paydirtBody.innerHTML = ""; + let i = 0; resultObject.matches.forEach(player => { + i++; const row = document.createElement("tr"); row.innerHTML = ` + ${i} ${player.Position} ${player.PlayerName} ${player.Team} - ${(player.PaydirtScore + "000000").slice(0, 8)} + ${Math.floor(player.PaydirtScore)} `; paydirtBody.appendChild(row); }); @@ -108,7 +116,7 @@ async function updateHighest() { const tableHeader = document.querySelector("#highest thead"); 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); if (resultObject.matches.length === 0) { @@ -122,25 +130,29 @@ async function updateHighest() { // headerRow.innerHTML += `${attribute}`; //}); headerRow.innerHTML = ` - Name - Contract - Team + Rank Position + Name + Team + Contract `; tableHeader.appendChild(headerRow); tableBody.innerHTML = ""; + let i = 0; resultObject.matches.forEach(player => { + i++; const row = document.createElement("tr"); //for (attribute in player) { // row.innerHTML += `${player}l`; //} row.innerHTML = ` - ${player.PlayerName} - ${formatSalary(player.TotalValue)} - ${player.Team} + ${i} ${player.Position} + ${player.PlayerName} + ${player.Team} + ${formatSalary(player.TotalValue)} `; tableBody.appendChild(row); }); @@ -160,22 +172,35 @@ async function updateFavorites() { // headerRow.innerHTML += `${attribute}`; //}); headerRow.innerHTML = ` + Rank + Position Name Team - Position + Remove `; tableHeader.appendChild(headerRow); tableBody.innerHTML = ""; console.log(resultObject.watchlist); + let i = 0; resultObject.watchlist.forEach(player => { + i++; const row = document.createElement("tr"); row.innerHTML = ` + ${i} + ${player.Position} ${player.PlayerName} ${player.Team} - ${player.Position} + Stop Watching `; tableBody.appendChild(row); }); + + document.querySelectorAll(".remove").forEach(element => { + element.addEventListener("click", async e => { + postData("/toggleWatched", { id: element.dataset.id }, token); + element.closest("tr").remove(); + }) + }); }; diff --git a/public/player.html b/public/player.html index 2c42a27..4f45a64 100644 --- a/public/player.html +++ b/public/player.html @@ -20,14 +20,29 @@

Height:

-

+

Weight:

-

+

+
+ +
+
+
+

PayDirt Score:

+ A player's PayDirt score is calculated by weighting their offense score by their APY. It is used to evaluate the worth of their contract. +
+

+
+
+
+

Offense Score:

+ A player's offense score is calculated by combining several of their offense stats into a weighted score. It is indicative of their overall performance. +
+

- diff --git a/public/player.js b/public/player.js index be71963..268f20a 100644 --- a/public/player.js +++ b/public/player.js @@ -62,8 +62,8 @@ async function populatePlayerData() { const playerStatsObject = resultObject.matches; - let playerObjectResult = await postData("/getPlayer", { - id: id + let playerObjectResult = await postData("/getPlayerScores", { + playerID: id }, token); if (playerObjectResult.success === false) { console.log("Invalid ID"); @@ -71,10 +71,23 @@ async function populatePlayerData() { } const playerObject = playerObjectResult.match; + console.log(playerObjectResult); for (const [attribute, value] of Object.entries(playerObject)) { console.log(`.attribute-${attribute}`); 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")) { element.textContent = formatSalary(value); return; @@ -82,7 +95,7 @@ async function populatePlayerData() { element.textContent = value; }) }; - + createStatsTable(playerStatsObject); createOverviewTable(playerObject); } @@ -158,9 +171,9 @@ async function createStatsTable(playerObject) { // row.innerHTML += `l`; //} rowElement.innerHTML = ` - + - + diff --git a/server.js b/server.js index e25aeec..5f28345 100644 --- a/server.js +++ b/server.js @@ -250,8 +250,8 @@ app.post("/getPlayerStats", authenticate, async (req, res) => { const result = await pool.request() .input("playerID", sql.Int, playerID) .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 -FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID +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 WHERE Player.PlayerID = @playerID ORDER BY Season, week; `); @@ -266,6 +266,7 @@ app.post("/getPlayerScores", authenticate, async (req, res) => { .input("playerID", sql.Int, playerID) .query(` 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(passing_yards) AS PassingYards, SUM(rushing_yards) AS RushingYards, @@ -306,13 +307,14 @@ AvgPerYear, - (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 -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; `); + 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() .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) { res.status(400).json({ success: false })
${player}${row.Season}${row.season} ${row.SeasonType === "REG" ? "Regular" : "Post"}${row.Week}${row.week} ${row.pass_attempts} ${row.complete_pass} ${row.total_yards}