diff options
Diffstat (limited to 'frontend/src/components/pages/maplist.js')
| -rw-r--r-- | frontend/src/components/pages/maplist.js | 844 |
1 files changed, 844 insertions, 0 deletions
diff --git a/frontend/src/components/pages/maplist.js b/frontend/src/components/pages/maplist.js new file mode 100644 index 0000000..dca76d6 --- /dev/null +++ b/frontend/src/components/pages/maplist.js | |||
| @@ -0,0 +1,844 @@ | |||
| 1 | import React, { useEffect, useRef, useState } from 'react'; | ||
| 2 | import { useLocation, Link } from "react-router-dom"; | ||
| 3 | import { BrowserRouter as Router, Route, Routes, useNavigate } from 'react-router-dom'; | ||
| 4 | |||
| 5 | import "./maplist.css" | ||
| 6 | import img5 from "../../imgs/5.png" | ||
| 7 | import img6 from "../../imgs/6.png" | ||
| 8 | |||
| 9 | export default function Maplist(prop) { | ||
| 10 | const {token,setToken} = prop | ||
| 11 | const scrollRef = useRef(null) | ||
| 12 | const [games, setGames] = React.useState(null); | ||
| 13 | const location = useLocation(); | ||
| 14 | |||
| 15 | let gameTitle; | ||
| 16 | let minPage; | ||
| 17 | let maxPage; | ||
| 18 | let currentPage; | ||
| 19 | let add = 0; | ||
| 20 | let gameState; | ||
| 21 | let catState = 0; | ||
| 22 | async function detectGame() { | ||
| 23 | const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { | ||
| 24 | headers: { | ||
| 25 | 'Authorization': token | ||
| 26 | } | ||
| 27 | }); | ||
| 28 | |||
| 29 | const data = await response.json(); | ||
| 30 | |||
| 31 | const url = new URL(window.location.href) | ||
| 32 | |||
| 33 | const params = new URLSearchParams(url.search) | ||
| 34 | gameState = parseFloat(params.get("game")) | ||
| 35 | |||
| 36 | document.querySelector("#catPortalCount").innerText = data.data[gameState - 1].category_portals[0].portal_count; | ||
| 37 | |||
| 38 | if (gameState == 1){ | ||
| 39 | gameTitle = data.data[0].name; | ||
| 40 | |||
| 41 | maxPage = 9; | ||
| 42 | minPage = 1; | ||
| 43 | createCategories(1); | ||
| 44 | } else if (gameState == 2){ | ||
| 45 | gameTitle = data.data[1].name; | ||
| 46 | |||
| 47 | maxPage = 16; | ||
| 48 | minPage = 10; | ||
| 49 | add = 10 | ||
| 50 | createCategories(2); | ||
| 51 | } | ||
| 52 | |||
| 53 | let chapterParam = params.get("chapter") | ||
| 54 | |||
| 55 | currentPage = minPage; | ||
| 56 | |||
| 57 | if (chapterParam) { | ||
| 58 | currentPage = +chapterParam + add | ||
| 59 | } | ||
| 60 | |||
| 61 | changePage(currentPage); | ||
| 62 | |||
| 63 | // if (chapterParam) { | ||
| 64 | // document.querySelector("#pageNumbers").innerText = `${chapterParam - minPage + 1}/${maxPage - minPage + 1}` | ||
| 65 | // } | ||
| 66 | } | ||
| 67 | |||
| 68 | function changeMaplistOrStatistics(index, name) { | ||
| 69 | const maplistBtns = document.querySelectorAll("#maplistBtn"); | ||
| 70 | maplistBtns.forEach((btn, i) => { | ||
| 71 | if (i == index) { | ||
| 72 | btn.className = "game-nav-btn selected" | ||
| 73 | |||
| 74 | if (name == "maplist") { | ||
| 75 | document.querySelector(".stats").style.display = "none"; | ||
| 76 | document.querySelector(".maplist").style.display = "block"; | ||
| 77 | document.querySelector(".maplist").setAttribute("currentTab", "maplist"); | ||
| 78 | } else { | ||
| 79 | document.querySelector(".stats").style.display = "block"; | ||
| 80 | document.querySelector(".maplist").style.display = "none"; | ||
| 81 | |||
| 82 | document.querySelector(".maplist-page").scrollTo({ top: 372, behavior: "smooth" }) | ||
| 83 | document.querySelector(".maplist").setAttribute("currentTab", "stats"); | ||
| 84 | } | ||
| 85 | } else { | ||
| 86 | btn.className = "game-nav-btn"; | ||
| 87 | } | ||
| 88 | }); | ||
| 89 | } | ||
| 90 | |||
| 91 | async function createCategories(gameID) { | ||
| 92 | const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { | ||
| 93 | headers: { | ||
| 94 | 'Authorization': token | ||
| 95 | } | ||
| 96 | }); | ||
| 97 | |||
| 98 | const data = await response.json(); | ||
| 99 | let categoriesArr = data.data[gameID - 1].category_portals; | ||
| 100 | |||
| 101 | const gameNav = document.querySelector(".game-nav"); | ||
| 102 | gameNav.innerHTML = ""; | ||
| 103 | categoriesArr.forEach((category) => { | ||
| 104 | createCategory(category); | ||
| 105 | }); | ||
| 106 | } | ||
| 107 | |||
| 108 | let categoryNum = 0; | ||
| 109 | function createCategory(category) { | ||
| 110 | const gameNav = document.querySelector(".game-nav"); | ||
| 111 | |||
| 112 | categoryNum++; | ||
| 113 | const gameNavBtn = document.createElement("button"); | ||
| 114 | if (categoryNum == 1) { | ||
| 115 | gameNavBtn.className = "game-nav-btn selected"; | ||
| 116 | } else { | ||
| 117 | gameNavBtn.className = "game-nav-btn"; | ||
| 118 | } | ||
| 119 | gameNavBtn.id = "catBtn" | ||
| 120 | gameNavBtn.innerText = category.category.name; | ||
| 121 | |||
| 122 | gameNavBtn.addEventListener("click", (e) => { | ||
| 123 | changeCategory(category, e); | ||
| 124 | changePage(currentPage); | ||
| 125 | }) | ||
| 126 | |||
| 127 | gameNav.appendChild(gameNavBtn); | ||
| 128 | } | ||
| 129 | |||
| 130 | async function changeCategory(category, btn) { | ||
| 131 | const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { | ||
| 132 | headers: { | ||
| 133 | 'Authorization': token | ||
| 134 | } | ||
| 135 | }); | ||
| 136 | |||
| 137 | const data = await response.json(); | ||
| 138 | catState = category.category.id - 1; | ||
| 139 | console.log(catState) | ||
| 140 | const navBtns = document.querySelectorAll("#catBtn"); | ||
| 141 | navBtns.forEach((btns) => { | ||
| 142 | btns.classList.remove("selected"); | ||
| 143 | }); | ||
| 144 | |||
| 145 | btn.srcElement.classList.add("selected"); | ||
| 146 | document.querySelector("#catPortalCount").innerText = category.portal_count; | ||
| 147 | } | ||
| 148 | |||
| 149 | async function changePage(page) { | ||
| 150 | |||
| 151 | const pageNumbers = document.querySelector("#pageNumbers"); | ||
| 152 | |||
| 153 | pageNumbers.innerText = `${currentPage - minPage + 1}/${maxPage - minPage + 1}`; | ||
| 154 | |||
| 155 | const maplistMaps = document.querySelector(".maplist-maps"); | ||
| 156 | maplistMaps.innerHTML = ""; | ||
| 157 | for (let index = 0; index < 8; index++) { | ||
| 158 | const loadingAnimation = document.createElement("div"); | ||
| 159 | loadingAnimation.classList.add("loader"); | ||
| 160 | loadingAnimation.classList.add("loader-map") | ||
| 161 | maplistMaps.appendChild(loadingAnimation); | ||
| 162 | } | ||
| 163 | const data = await fetchMaps(page); | ||
| 164 | const maps = data.data.maps; | ||
| 165 | const name = data.data.chapter.name; | ||
| 166 | |||
| 167 | let chapterName = "Chapter"; | ||
| 168 | const chapterNumberOld = name.split(" - ")[0]; | ||
| 169 | let chapterNumber1 = chapterNumberOld.split("Chapter ")[1]; | ||
| 170 | if (chapterNumber1 == undefined) { | ||
| 171 | chapterName = "Course" | ||
| 172 | chapterNumber1 = chapterNumberOld.split("Course ")[1]; | ||
| 173 | } | ||
| 174 | const chapterNumber = chapterNumber1.toString().padStart(2, "0"); | ||
| 175 | const chapterTitle = name.split(" - ")[1]; | ||
| 176 | |||
| 177 | const chapterNumberElement = document.querySelector(".chapter-num") | ||
| 178 | const chapterTitleElement = document.querySelector(".chapter-name") | ||
| 179 | chapterNumberElement.innerText = chapterName + " " + chapterNumber; | ||
| 180 | chapterTitleElement.innerText = chapterTitle; | ||
| 181 | |||
| 182 | maplistMaps.innerHTML = ""; | ||
| 183 | maps.forEach(map => { | ||
| 184 | let portalCount; | ||
| 185 | if (map.category_portals[catState] != undefined) { | ||
| 186 | portalCount = map.category_portals[catState].portal_count; | ||
| 187 | } else { | ||
| 188 | portalCount = map.category_portals[0].portal_count; | ||
| 189 | } | ||
| 190 | addMap(map.name, portalCount, map.image, map.difficulty + 1, map.id); | ||
| 191 | }); | ||
| 192 | |||
| 193 | const gameTitleElement = document.querySelector("#gameTitle"); | ||
| 194 | gameTitleElement.innerText = gameTitle; | ||
| 195 | |||
| 196 | const url = new URL(window.location.href) | ||
| 197 | |||
| 198 | const params = new URLSearchParams(url.search) | ||
| 199 | |||
| 200 | let chapterParam = params.get("chapter") | ||
| 201 | |||
| 202 | try { | ||
| 203 | const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { | ||
| 204 | headers: { | ||
| 205 | 'Authorization': token | ||
| 206 | } | ||
| 207 | }); | ||
| 208 | |||
| 209 | const data = await response.json(); | ||
| 210 | |||
| 211 | const gameImg = document.querySelector(".game-img"); | ||
| 212 | |||
| 213 | gameImg.style.backgroundImage = `url(${data.data[0].image})`; | ||
| 214 | |||
| 215 | // const mapImg = document.querySelectorAll(".maplist-img"); | ||
| 216 | // mapImg.forEach((map) => { | ||
| 217 | // map.style.backgroundImage = `url(${data.data[0].image})`; | ||
| 218 | // }); | ||
| 219 | |||
| 220 | } catch (error) { | ||
| 221 | console.log("error fetching games:", error); | ||
| 222 | } | ||
| 223 | |||
| 224 | asignDifficulties(); | ||
| 225 | } | ||
| 226 | |||
| 227 | async function addMap(mapName, mapPortalCount, mapImage, difficulty, mapID) { | ||
| 228 | // jesus christ | ||
| 229 | const maplistItem = document.createElement("div"); | ||
| 230 | const maplistTitle = document.createElement("span"); | ||
| 231 | const maplistImgDiv = document.createElement("div"); | ||
| 232 | const maplistImg = document.createElement("div"); | ||
| 233 | const maplistPortalcountDiv = document.createElement("div"); | ||
| 234 | const maplistPortalcount = document.createElement("span"); | ||
| 235 | const b = document.createElement("b"); | ||
| 236 | const maplistPortalcountPortals = document.createElement("span"); | ||
| 237 | const difficultyDiv = document.createElement("div"); | ||
| 238 | const difficultyLabel = document.createElement("span"); | ||
| 239 | const difficultyBar = document.createElement("div"); | ||
| 240 | const difficultyPoint1 = document.createElement("div"); | ||
| 241 | const difficultyPoint2 = document.createElement("div"); | ||
| 242 | const difficultyPoint3 = document.createElement("div"); | ||
| 243 | const difficultyPoint4 = document.createElement("div"); | ||
| 244 | const difficultyPoint5 = document.createElement("div"); | ||
| 245 | |||
| 246 | maplistItem.className = "maplist-item"; | ||
| 247 | maplistTitle.className = "maplist-title"; | ||
| 248 | maplistImgDiv.className = "maplist-img-div"; | ||
| 249 | maplistImg.className = "maplist-img"; | ||
| 250 | maplistPortalcountDiv.className = "maplist-portalcount-div"; | ||
| 251 | maplistPortalcount.className = "maplist-portalcount"; | ||
| 252 | maplistPortalcountPortals.className = "maplist-portals"; | ||
| 253 | difficultyDiv.className = "difficulty-div"; | ||
| 254 | difficultyLabel.className = "difficulty-label"; | ||
| 255 | difficultyBar.className = "difficulty-bar"; | ||
| 256 | difficultyPoint1.className = "difficulty-point"; | ||
| 257 | difficultyPoint2.className = "difficulty-point"; | ||
| 258 | difficultyPoint3.className = "difficulty-point"; | ||
| 259 | difficultyPoint4.className = "difficulty-point"; | ||
| 260 | difficultyPoint5.className = "difficulty-point"; | ||
| 261 | |||
| 262 | |||
| 263 | maplistTitle.innerText = mapName; | ||
| 264 | difficultyLabel.innerText = "Difficulty: " | ||
| 265 | maplistPortalcountPortals.innerText = "portals" | ||
| 266 | b.innerText = mapPortalCount; | ||
| 267 | maplistImg.style.backgroundImage = `url(${mapImage})`; | ||
| 268 | difficultyBar.setAttribute("difficulty", difficulty) | ||
| 269 | maplistItem.setAttribute("id", mapID) | ||
| 270 | maplistItem.addEventListener("click", () => { | ||
| 271 | console.log(mapID) | ||
| 272 | window.location.href = "/maps/" + mapID | ||
| 273 | }) | ||
| 274 | |||
| 275 | // appends | ||
| 276 | // maplist item | ||
| 277 | maplistItem.appendChild(maplistTitle); | ||
| 278 | maplistImgDiv.appendChild(maplistImg); | ||
| 279 | maplistImgDiv.appendChild(maplistPortalcountDiv); | ||
| 280 | maplistPortalcountDiv.appendChild(maplistPortalcount); | ||
| 281 | maplistPortalcount.appendChild(b); | ||
| 282 | maplistPortalcountDiv.appendChild(maplistPortalcountPortals); | ||
| 283 | maplistItem.appendChild(maplistImgDiv); | ||
| 284 | maplistItem.appendChild(difficultyDiv); | ||
| 285 | difficultyDiv.appendChild(difficultyLabel); | ||
| 286 | difficultyDiv.appendChild(difficultyBar); | ||
| 287 | difficultyBar.appendChild(difficultyPoint1); | ||
| 288 | difficultyBar.appendChild(difficultyPoint2); | ||
| 289 | difficultyBar.appendChild(difficultyPoint3); | ||
| 290 | difficultyBar.appendChild(difficultyPoint4); | ||
| 291 | difficultyBar.appendChild(difficultyPoint5); | ||
| 292 | |||
| 293 | // display in place | ||
| 294 | const maplistMaps = document.querySelector(".maplist-maps"); | ||
| 295 | maplistMaps.appendChild(maplistItem); | ||
| 296 | } | ||
| 297 | |||
| 298 | async function fetchMaps(chapterID) { | ||
| 299 | try{ | ||
| 300 | const response = await fetch(`https://lp.ardapektezol.com/api/v1/chapters/${chapterID}`, { | ||
| 301 | headers: { | ||
| 302 | 'Authorization': token | ||
| 303 | } | ||
| 304 | }); | ||
| 305 | |||
| 306 | const data = await response.json(); | ||
| 307 | return data; | ||
| 308 | } catch (err) { | ||
| 309 | console.log(err) | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | // difficulty stuff | ||
| 314 | function asignDifficulties() { | ||
| 315 | const difficulties = document.querySelectorAll(".difficulty-bar"); | ||
| 316 | difficulties.forEach((difficultyElement) => { | ||
| 317 | let difficulty = difficultyElement.getAttribute("difficulty"); | ||
| 318 | if (difficulty == "1") { | ||
| 319 | difficultyElement.childNodes[0].style.backgroundColor = "#51C355"; | ||
| 320 | } else if (difficulty == "2") { | ||
| 321 | difficultyElement.childNodes[0].style.backgroundColor = "#8AC93A"; | ||
| 322 | difficultyElement.childNodes[1].style.backgroundColor = "#8AC93A"; | ||
| 323 | } else if (difficulty == "3") { | ||
| 324 | difficultyElement.childNodes[0].style.backgroundColor = "#8AC93A"; | ||
| 325 | difficultyElement.childNodes[1].style.backgroundColor = "#8AC93A"; | ||
| 326 | difficultyElement.childNodes[2].style.backgroundColor = "#8AC93A"; | ||
| 327 | } else if (difficulty == "4") { | ||
| 328 | difficultyElement.childNodes[0].style.backgroundColor = "#C35F51"; | ||
| 329 | difficultyElement.childNodes[1].style.backgroundColor = "#C35F51"; | ||
| 330 | difficultyElement.childNodes[2].style.backgroundColor = "#C35F51"; | ||
| 331 | difficultyElement.childNodes[3].style.backgroundColor = "#C35F51"; | ||
| 332 | } else if (difficulty == "5") { | ||
| 333 | difficultyElement.childNodes[0].style.backgroundColor = "#C35F51"; | ||
| 334 | difficultyElement.childNodes[1].style.backgroundColor = "#C35F51"; | ||
| 335 | difficultyElement.childNodes[2].style.backgroundColor = "#C35F51"; | ||
| 336 | difficultyElement.childNodes[3].style.backgroundColor = "#C35F51"; | ||
| 337 | difficultyElement.childNodes[4].style.backgroundColor = "#C35F51"; | ||
| 338 | } | ||
| 339 | }); | ||
| 340 | } | ||
| 341 | |||
| 342 | const divRef = useRef(null); | ||
| 343 | |||
| 344 | React.useEffect(() => { | ||
| 345 | |||
| 346 | const lineChart = document.querySelector(".line-chart") | ||
| 347 | function createGraph() { | ||
| 348 | // max | ||
| 349 | let items = [ | ||
| 350 | { | ||
| 351 | record: "100", | ||
| 352 | date: new Date(2011, 4, 4), | ||
| 353 | map: "Container Ride", | ||
| 354 | first: "tiny zach" | ||
| 355 | }, | ||
| 356 | { | ||
| 357 | record: "98", | ||
| 358 | date: new Date(2012, 6, 4), | ||
| 359 | map: "Container Ride", | ||
| 360 | first: "tiny zach" | ||
| 361 | }, | ||
| 362 | { | ||
| 363 | record: "94", | ||
| 364 | date: new Date(2013, 0, 1), | ||
| 365 | map: "Container Ride", | ||
| 366 | first: "tiny zach" | ||
| 367 | }, | ||
| 368 | { | ||
| 369 | record: "90", | ||
| 370 | date: new Date(2014, 0, 1), | ||
| 371 | map: "Container Ride", | ||
| 372 | first: "tiny zach" | ||
| 373 | }, | ||
| 374 | { | ||
| 375 | record: "88", | ||
| 376 | date: new Date(2015, 6, 14), | ||
| 377 | map: "Container Ride", | ||
| 378 | first: "tiny zach" | ||
| 379 | }, | ||
| 380 | { | ||
| 381 | record: "84", | ||
| 382 | date: new Date(2016, 8, 19), | ||
| 383 | map: "Container Ride", | ||
| 384 | first: "tiny zach" | ||
| 385 | }, | ||
| 386 | { | ||
| 387 | record: "82", | ||
| 388 | date: new Date(2017, 3, 20), | ||
| 389 | map: "Container Ride", | ||
| 390 | first: "tiny zach" | ||
| 391 | }, | ||
| 392 | { | ||
| 393 | record: "81", | ||
| 394 | date: new Date(2018, 2, 25), | ||
| 395 | map: "Container Ride", | ||
| 396 | first: "tiny zach" | ||
| 397 | }, | ||
| 398 | { | ||
| 399 | record: "80", | ||
| 400 | date: new Date(2019, 3, 4), | ||
| 401 | map: "Container Ride", | ||
| 402 | first: "tiny zach" | ||
| 403 | }, | ||
| 404 | { | ||
| 405 | record: "78", | ||
| 406 | date: new Date(2020, 11, 21), | ||
| 407 | map: "Container Ride", | ||
| 408 | first: "tiny zach" | ||
| 409 | }, | ||
| 410 | { | ||
| 411 | record: "77", | ||
| 412 | date: new Date(2021, 10, 25), | ||
| 413 | map: "Container Ride", | ||
| 414 | first: "tiny zach" | ||
| 415 | }, | ||
| 416 | { | ||
| 417 | record: "76", | ||
| 418 | date: new Date(2022, 4, 17), | ||
| 419 | map: "Container Ride", | ||
| 420 | first: "tiny zach" | ||
| 421 | }, | ||
| 422 | { | ||
| 423 | record: "75", | ||
| 424 | date: new Date(2023, 9, 31), | ||
| 425 | map: "Container Ride", | ||
| 426 | first: "tiny zach" | ||
| 427 | }, | ||
| 428 | { | ||
| 429 | record: "74", | ||
| 430 | date: new Date(2024, 4, 4), | ||
| 431 | map: "Container Ride", | ||
| 432 | first: "tiny zach" | ||
| 433 | }, | ||
| 434 | ] | ||
| 435 | |||
| 436 | function calculatePosition(date, startDate, endDate, maxWidth) { | ||
| 437 | const totalMilliseconds = endDate - startDate + 10000000000; | ||
| 438 | const millisecondsFromStart = date - startDate + 5000000000; | ||
| 439 | return (millisecondsFromStart / totalMilliseconds) * maxWidth | ||
| 440 | } | ||
| 441 | |||
| 442 | const minDate = items.reduce((min, dp) => dp.date < min ? dp.date : min, items[0].date) | ||
| 443 | const maxDate = items.reduce((max, dp) => dp.date > max ? dp.date : max, items[0].date) | ||
| 444 | |||
| 445 | const graph_width = document.querySelector(".portalcount-over-time-div").clientWidth | ||
| 446 | // console.log(graph_width) | ||
| 447 | |||
| 448 | const uniqueYears = new Set() | ||
| 449 | items.forEach(dp => uniqueYears.add(dp.date.getFullYear())) | ||
| 450 | let minYear = Infinity; | ||
| 451 | let maxYear = -Infinity; | ||
| 452 | |||
| 453 | items.forEach(dp => { | ||
| 454 | const year = dp.date.getFullYear(); | ||
| 455 | minYear = Math.min(minYear, year); | ||
| 456 | maxYear = Math.max(maxYear, year); | ||
| 457 | }); | ||
| 458 | |||
| 459 | // Add missing years to the set | ||
| 460 | for (let year = minYear; year <= maxYear; year++) { | ||
| 461 | uniqueYears.add(year); | ||
| 462 | } | ||
| 463 | const uniqueYearsArr = Array.from(uniqueYears) | ||
| 464 | |||
| 465 | items = items.map(dp => ({ | ||
| 466 | record: dp.record, | ||
| 467 | date: dp.date, | ||
| 468 | x: calculatePosition(dp.date, minDate, maxDate, lineChart.clientWidth), | ||
| 469 | map: dp.map, | ||
| 470 | first: dp.first | ||
| 471 | })) | ||
| 472 | |||
| 473 | const yearInterval = lineChart.clientWidth / uniqueYears.size | ||
| 474 | for (let index = 1; index < (uniqueYears.size); index++) { | ||
| 475 | const placeholderlmao = document.createElement("div") | ||
| 476 | const yearSpan = document.createElement("span") | ||
| 477 | yearSpan.style.position = "absolute" | ||
| 478 | placeholderlmao.style.height = "100%" | ||
| 479 | placeholderlmao.style.width = "2px" | ||
| 480 | placeholderlmao.style.backgroundColor = "#00000080" | ||
| 481 | placeholderlmao.style.position = `absolute` | ||
| 482 | const thing = calculatePosition(new Date(uniqueYearsArr[index], 0, 0), minDate, maxDate, lineChart.clientWidth) | ||
| 483 | placeholderlmao.style.left = `${thing}px` | ||
| 484 | yearSpan.style.left = `${thing}px` | ||
| 485 | yearSpan.style.bottom = "-34px" | ||
| 486 | yearSpan.innerText = uniqueYearsArr[index] | ||
| 487 | yearSpan.style.fontFamily = "BarlowSemiCondensed-Regular" | ||
| 488 | yearSpan.style.fontSize = "22px" | ||
| 489 | yearSpan.style.opacity = "0.8" | ||
| 490 | lineChart.appendChild(yearSpan) | ||
| 491 | |||
| 492 | } | ||
| 493 | |||
| 494 | let maxPortals; | ||
| 495 | let minPortals; | ||
| 496 | let precision; | ||
| 497 | let multiplier = 1; | ||
| 498 | for (let index = 0; index < items.length; index++) { | ||
| 499 | precision = Math.floor((items[0].record - items[items.length - 1].record)) | ||
| 500 | if (precision > 20) { | ||
| 501 | precision = 20 | ||
| 502 | } | ||
| 503 | minPortals = Math.floor((items[items.length - 1].record) / 10) * 10 | ||
| 504 | if (index == 0) { | ||
| 505 | maxPortals = items[index].record - minPortals | ||
| 506 | } | ||
| 507 | } | ||
| 508 | function calculateMultiplier(value) { | ||
| 509 | while (value > precision) { | ||
| 510 | multiplier += 1; | ||
| 511 | value -= precision; | ||
| 512 | } | ||
| 513 | } | ||
| 514 | calculateMultiplier(items[0].record); | ||
| 515 | // if (items[0].record > 10) { | ||
| 516 | // multiplier = 2; | ||
| 517 | // } | ||
| 518 | |||
| 519 | // Original cubic bezier control points | ||
| 520 | const P0 = { x: 0, y: 0 }; | ||
| 521 | const P1 = { x: 0.26, y: 1 }; | ||
| 522 | const P2 = { x: 0.74, y: 1 }; | ||
| 523 | const P3 = { x: 1, y: 0 }; | ||
| 524 | |||
| 525 | function calculateIntermediateControlPoints(t, P0, P1, P2, P3) { | ||
| 526 | const x = (1 - t) ** 3 * P0.x + | ||
| 527 | 3 * (1 - t) ** 2 * t * P1.x + | ||
| 528 | 3 * (1 - t) * t ** 2 * P2.x + | ||
| 529 | t ** 3 * P3.x; | ||
| 530 | |||
| 531 | const y = (1 - t) ** 3 * P0.y + | ||
| 532 | 3 * (1 - t) ** 2 * t * P1.y + | ||
| 533 | 3 * (1 - t) * t ** 2 * P2.y + | ||
| 534 | t ** 3 * P3.y; | ||
| 535 | |||
| 536 | return { x, y }; | ||
| 537 | } | ||
| 538 | |||
| 539 | |||
| 540 | let delay = 0; | ||
| 541 | for (let index = 0; index < items.length; index++) { | ||
| 542 | let chart_height = 340; | ||
| 543 | const item = items[index]; | ||
| 544 | delay += 0.05; | ||
| 545 | // console.log(lineChart.clientWidth) | ||
| 546 | |||
| 547 | // maxPortals++; | ||
| 548 | // maxPortals++; | ||
| 549 | |||
| 550 | let point_height = (chart_height / maxPortals) | ||
| 551 | |||
| 552 | for (let index = 0; index < (maxPortals / multiplier); index++) { | ||
| 553 | // console.log((index + 1) * multiplier) | ||
| 554 | let current_portal_count = (index + 1); | ||
| 555 | |||
| 556 | const placeholderDiv = document.createElement("div") | ||
| 557 | const numPortalsText = document.createElement("span") | ||
| 558 | const numPortalsTextBottom = document.createElement("span") | ||
| 559 | numPortalsText.innerText = (current_portal_count * multiplier) + minPortals | ||
| 560 | numPortalsTextBottom.innerText = minPortals | ||
| 561 | placeholderDiv.style.position = "absolute" | ||
| 562 | numPortalsText.style.position = "absolute" | ||
| 563 | numPortalsTextBottom.style.position = "absolute" | ||
| 564 | numPortalsText.style.left = "-37px" | ||
| 565 | numPortalsText.style.opacity = "0.2" | ||
| 566 | numPortalsTextBottom.style.opacity = "0.2" | ||
| 567 | numPortalsText.style.fontFamily = "BarlowSemiCondensed-Regular" | ||
| 568 | numPortalsTextBottom.style.fontFamily = "BarlowSemiCondensed-Regular" | ||
| 569 | numPortalsText.style.fontSize = "22px" | ||
| 570 | numPortalsTextBottom.style.left = "-37px" | ||
| 571 | numPortalsTextBottom.style.fontSize = "22px" | ||
| 572 | numPortalsTextBottom.style.fontWeight = "400" | ||
| 573 | numPortalsText.style.color = "#CDCFDF" | ||
| 574 | numPortalsTextBottom.style.color = "#CDCFDF" | ||
| 575 | numPortalsText.style.fontFamily = "inherit" | ||
| 576 | numPortalsTextBottom.style.fontFamily = "inherit" | ||
| 577 | numPortalsText.style.textAlign = "right" | ||
| 578 | numPortalsTextBottom.style.textAlign = "right" | ||
| 579 | numPortalsText.style.width = "30px" | ||
| 580 | numPortalsTextBottom.style.width = "30px" | ||
| 581 | placeholderDiv.style.bottom = `${(point_height * current_portal_count * multiplier) - 2}px` | ||
| 582 | numPortalsText.style.bottom = `${(point_height * current_portal_count * multiplier) - 2 - 9}px` | ||
| 583 | numPortalsTextBottom.style.bottom = `${0 - 2 - 8}px` | ||
| 584 | placeholderDiv.id = placeholderDiv.style.bottom | ||
| 585 | placeholderDiv.style.width = "100%" | ||
| 586 | placeholderDiv.style.height = "2px" | ||
| 587 | placeholderDiv.style.backgroundColor = "#2B2E46" | ||
| 588 | placeholderDiv.style.zIndex = "0" | ||
| 589 | |||
| 590 | if (index == 0) { | ||
| 591 | lineChart.appendChild(numPortalsTextBottom) | ||
| 592 | } | ||
| 593 | lineChart.appendChild(numPortalsText) | ||
| 594 | lineChart.appendChild(placeholderDiv) | ||
| 595 | } | ||
| 596 | |||
| 597 | const li = document.createElement("li"); | ||
| 598 | const lineSeg = document.createElement("div"); | ||
| 599 | const dataPoint = document.createElement("div"); | ||
| 600 | |||
| 601 | li.style = `--y: ${point_height * (item.record - minPortals) - 3}px; --x: ${item.x}px`; | ||
| 602 | lineSeg.className = "line-segment"; | ||
| 603 | dataPoint.className = "data-point"; | ||
| 604 | |||
| 605 | if (items[index + 1] !== undefined) { | ||
| 606 | const hypotenuse = Math.sqrt( | ||
| 607 | Math.pow(items[index + 1].x - items[index].x, 2) + | ||
| 608 | Math.pow((point_height * items[index + 1].record) - point_height * item.record, 2) | ||
| 609 | ); | ||
| 610 | const angle = Math.asin( | ||
| 611 | ((point_height * item.record) - (point_height * items[index + 1].record)) / hypotenuse | ||
| 612 | ); | ||
| 613 | |||
| 614 | lineSeg.style = `--hypotenuse: ${hypotenuse}; --angle: ${angle * (-180 / Math.PI)}`; | ||
| 615 | const t0 = index / items.length; | ||
| 616 | const t1 = (index + 1) / items.length | ||
| 617 | |||
| 618 | const P0t0 = calculateIntermediateControlPoints(t0, P0, P1, P2, P3); | ||
| 619 | const P1t1 = calculateIntermediateControlPoints(t1, P0, P1, P2, P3); | ||
| 620 | const bezierStyle = `cubic-bezier(${P0t0.x.toFixed(3)}, ${P0t0.y.toFixed(3)}, ${P1t1.x.toFixed(3)}, ${P1t1.y.toFixed(3)})` | ||
| 621 | lineSeg.style.animationTimingFunction = bezierStyle | ||
| 622 | lineSeg.style.animationDelay = delay + "s" | ||
| 623 | } | ||
| 624 | dataPoint.style.animationDelay = delay + "s" | ||
| 625 | |||
| 626 | let isHoveringOverData = false; | ||
| 627 | let isDataActive = false; | ||
| 628 | document.querySelector("#dataPointInfo").style.left = item.x + "px"; | ||
| 629 | document.querySelector("#dataPointInfo").style.bottom = (point_height * item.record -3) + "px"; | ||
| 630 | dataPoint.addEventListener("mouseenter", (e) => { | ||
| 631 | isDataActive = true; | ||
| 632 | isHoveringOverData = true; | ||
| 633 | const dataPoints = document.querySelectorAll(".data-point") | ||
| 634 | dataPoints.forEach(point => { | ||
| 635 | point.classList.remove("data-point-active") | ||
| 636 | }); | ||
| 637 | dataPoint.classList.add("data-point-active") | ||
| 638 | document.querySelector("#dataPointRecord").innerText = item.record; | ||
| 639 | document.querySelector("#dataPointMap").innerText = item.map; | ||
| 640 | document.querySelector("#dataPointDate").innerText = item.date.toLocaleDateString("en-GB"); | ||
| 641 | document.querySelector("#dataPointFirst").innerText = item.first; | ||
| 642 | if ((lineChart.clientWidth - 400) < item.x) { | ||
| 643 | document.querySelector("#dataPointInfo").style.left = item.x - 400 + "px"; | ||
| 644 | } else { | ||
| 645 | document.querySelector("#dataPointInfo").style.left = item.x + "px"; | ||
| 646 | } | ||
| 647 | if ((lineChart.clientHeight - 115) < (point_height * (item.record - minPortals) -3)) { | ||
| 648 | document.querySelector("#dataPointInfo").style.bottom = (point_height * (item.record - minPortals) -3) - 115 + "px"; | ||
| 649 | } else { | ||
| 650 | document.querySelector("#dataPointInfo").style.bottom = (point_height * (item.record - minPortals) -3) + "px"; | ||
| 651 | } | ||
| 652 | document.querySelector("#dataPointInfo").style.opacity = "1"; | ||
| 653 | document.querySelector("#dataPointInfo").style.zIndex = "10"; | ||
| 654 | }); | ||
| 655 | document.querySelector("#dataPointInfo").addEventListener("mouseenter", (e) => { | ||
| 656 | isHoveringOverData = true; | ||
| 657 | }) | ||
| 658 | document.querySelector("#dataPointInfo").addEventListener("mouseleave", (e) => { | ||
| 659 | isHoveringOverData = false; | ||
| 660 | }) | ||
| 661 | document.addEventListener("mousedown", () => { | ||
| 662 | if (!isHoveringOverData) { | ||
| 663 | isDataActive = false | ||
| 664 | dataPoint.classList.remove("data-point-active") | ||
| 665 | document.querySelector("#dataPointInfo").style.opacity = "0"; | ||
| 666 | document.querySelector("#dataPointInfo").style.zIndex = "0"; | ||
| 667 | } | ||
| 668 | }) | ||
| 669 | dataPoint.addEventListener("mouseenter", (e) => { | ||
| 670 | isHoveringOverData = false; | ||
| 671 | }) | ||
| 672 | document.querySelector(".chart").addEventListener("mouseleave", () => { | ||
| 673 | isDataActive = false | ||
| 674 | dataPoint.classList.remove("data-point-active") | ||
| 675 | document.querySelector("#dataPointInfo").style.opacity = "0"; | ||
| 676 | document.querySelector("#dataPointInfo").style.zIndex = "0"; | ||
| 677 | }) | ||
| 678 | |||
| 679 | li.appendChild(lineSeg); | ||
| 680 | li.appendChild(dataPoint); | ||
| 681 | lineChart.appendChild(li); | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | createGraph() | ||
| 686 | |||
| 687 | async function fetchGames() { | ||
| 688 | try { | ||
| 689 | const response = await fetch("https://lp.ardapektezol.com/api/v1/games", { | ||
| 690 | headers: { | ||
| 691 | 'Authorization': token | ||
| 692 | } | ||
| 693 | }); | ||
| 694 | |||
| 695 | const data = await response.json(); | ||
| 696 | |||
| 697 | const gameImg = document.querySelector(".game-img"); | ||
| 698 | |||
| 699 | gameImg.style.backgroundImage = `url(${data.data[0].image})`; | ||
| 700 | |||
| 701 | // const mapImg = document.querySelectorAll(".maplist-img"); | ||
| 702 | // mapImg.forEach((map) => { | ||
| 703 | // map.style.backgroundImage = `url(${data.data[0].image})`; | ||
| 704 | // }); | ||
| 705 | |||
| 706 | } catch (error) { | ||
| 707 | console.log("error fetching games:", error); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | detectGame(); | ||
| 712 | |||
| 713 | const maplistImg = document.querySelector("#maplistImg"); | ||
| 714 | maplistImg.src = img5; | ||
| 715 | const statisticsImg = document.querySelector("#statisticsImg"); | ||
| 716 | statisticsImg.src = img6; | ||
| 717 | |||
| 718 | fetchGames(); | ||
| 719 | |||
| 720 | const handleResize = (entries) => { | ||
| 721 | for (let entry of entries) { | ||
| 722 | lineChart.innerHTML = "" | ||
| 723 | createGraph() | ||
| 724 | if (document.querySelector(".maplist").getAttribute("currentTab") == "stats") { | ||
| 725 | document.querySelector(".stats").style.display = "block" | ||
| 726 | } else { | ||
| 727 | document.querySelector(".stats").style.display = "none" | ||
| 728 | } | ||
| 729 | } | ||
| 730 | }; | ||
| 731 | |||
| 732 | const resizeObserver = new ResizeObserver(handleResize); | ||
| 733 | |||
| 734 | // if (scrollRef.current) { | ||
| 735 | // //hi | ||
| 736 | // if (new URLSearchParams(new URL(window.location.href).search).get("chapter")) { | ||
| 737 | // setTimeout(() => { | ||
| 738 | // scrollRef.current.scrollIntoView({ behavior: "smooth", block: "start" }) | ||
| 739 | // }, 200); | ||
| 740 | // } | ||
| 741 | |||
| 742 | // } | ||
| 743 | |||
| 744 | if (divRef.current) { | ||
| 745 | resizeObserver.observe(divRef.current); | ||
| 746 | } | ||
| 747 | |||
| 748 | return () => { | ||
| 749 | if (divRef.current) { | ||
| 750 | resizeObserver.unobserve(divRef.current); | ||
| 751 | } | ||
| 752 | resizeObserver.disconnect(); | ||
| 753 | }; | ||
| 754 | |||
| 755 | |||
| 756 | }) | ||
| 757 | return ( | ||
| 758 | <div ref={divRef} className='maplist-page'> | ||
| 759 | <div className='maplist-page-content'> | ||
| 760 | <section className='maplist-page-header'> | ||
| 761 | <Link to='/games'><button className='nav-btn'> | ||
| 762 | <i className='triangle'></i> | ||
| 763 | <span>Games list</span> | ||
| 764 | </button></Link> | ||
| 765 | <span><b id='gameTitle'> </b></span> | ||
| 766 | </section> | ||
| 767 | |||
| 768 | <div className='game'> | ||
| 769 | <div className='game-header'> | ||
| 770 | <div className='game-img'></div> | ||
| 771 | <div className='game-header-text'> | ||
| 772 | <span><b id='catPortalCount'>0</b></span> | ||
| 773 | <span>portals</span> | ||
| 774 | </div> | ||
| 775 | </div> | ||
| 776 | |||
| 777 | <div className='game-nav'> | ||
| 778 | </div> | ||
| 779 | </div> | ||
| 780 | |||
| 781 | <div className='gameview-nav'> | ||
| 782 | <button id='maplistBtn' onClick={() => {changeMaplistOrStatistics(0, "maplist")}} className='game-nav-btn selected'> | ||
| 783 | <img id='maplistImg'/> | ||
| 784 | <span>Map List</span> | ||
| 785 | </button> | ||
| 786 | <button id='maplistBtn' onClick={() => changeMaplistOrStatistics(1, "stats")} className='game-nav-btn'> | ||
| 787 | <img id='statisticsImg'/> | ||
| 788 | <span>Statistics</span> | ||
| 789 | </button> | ||
| 790 | </div> | ||
| 791 | |||
| 792 | <div ref={scrollRef} className='maplist'> | ||
| 793 | <div className='chapter'> | ||
| 794 | <span className='chapter-num'>undefined</span><br/> | ||
| 795 | <span className='chapter-name'>undefined</span> | ||
| 796 | |||
| 797 | <div className='chapter-page-div'> | ||
| 798 | <button id='pageChanger' onClick={() => { currentPage--; currentPage < minPage ? currentPage = minPage : changePage(currentPage); }}> | ||
| 799 | <i className='triangle'></i> | ||
| 800 | </button> | ||
| 801 | <span id='pageNumbers'>0/0</span> | ||
| 802 | <button id='pageChanger' onClick={() => { currentPage++; currentPage > maxPage ? currentPage = maxPage : changePage(currentPage); }}> | ||
| 803 | <i style={{ transform: "rotate(180deg)" }} className='triangle'></i> | ||
| 804 | </button> | ||
| 805 | </div> | ||
| 806 | |||
| 807 | <div className='maplist-maps'> | ||
| 808 | </div> | ||
| 809 | </div> | ||
| 810 | </div> | ||
| 811 | |||
| 812 | <div style={{display: "block"}} className='stats'> | ||
| 813 | <div className='portalcount-over-time-div'> | ||
| 814 | <span className='graph-title'>Portal count over time</span><br/> | ||
| 815 | |||
| 816 | <div className='portalcount-graph'> | ||
| 817 | <figure className='chart'> | ||
| 818 | <div style={{display: "block"}}></div> | ||
| 819 | <div id="dataPointInfo"> | ||
| 820 | <div className='section-header'> | ||
| 821 | <span className='header-title'>Date</span> | ||
| 822 | <span className='header-title'>Map</span> | ||
| 823 | <span className='header-title'>Record</span> | ||
| 824 | <span className='header-title'>First completion</span> | ||
| 825 | </div> | ||
| 826 | <div className='divider'></div> | ||
| 827 | <div className='section-data'> | ||
| 828 | <span id='dataPointDate'></span> | ||
| 829 | <span id='dataPointMap'></span> | ||
| 830 | <span id='dataPointRecord'></span> | ||
| 831 | <span id='dataPointFirst'>Hello</span> | ||
| 832 | </div> | ||
| 833 | </div> | ||
| 834 | <ul className='line-chart'> | ||
| 835 | |||
| 836 | </ul> | ||
| 837 | </figure> | ||
| 838 | </div> | ||
| 839 | </div> | ||
| 840 | </div> | ||
| 841 | </div> | ||
| 842 | </div> | ||
| 843 | ) | ||
| 844 | } \ No newline at end of file | ||