Add: Slider customization & fix black spots showing up on map
This commit is contained in:
		| @@ -50,6 +50,12 @@ | |||||||
|                 <div> |                 <div> | ||||||
|                     <input type="checkbox" onclick="toggleCentered()" id="centerCheck" name="center" checked /> |                     <input type="checkbox" onclick="toggleCentered()" id="centerCheck" name="center" checked /> | ||||||
|                     <label for="centerCheck">Player Centered</label> |                     <label for="centerCheck">Player Centered</label> | ||||||
|  |                     <div id="zoomLevelContainer" style="margin-top: 5px; margin-left: 20px; display: none;"> | ||||||
|  |                         <label for="zoomLevelSlider">Zoom Level: </label> | ||||||
|  |                         <span id="zoomLevelValue">1.0</span><br> | ||||||
|  |                         <input type="range" id="zoomLevelSlider" min="1.0" max="5.0" step="0.1" value="1.0" | ||||||
|  |                             style="width: 100%; margin: 5px 0;" oninput="updateZoomLevel(this.value)"> | ||||||
|  |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="player-focus"> |                 <div class="player-focus"> | ||||||
|                     <label for="playerSelect">Focus Player:</label> |                     <label for="playerSelect">Focus Player:</label> | ||||||
| @@ -57,6 +63,21 @@ | |||||||
|                         <option value="local">YOU</option> |                         <option value="local">YOU</option> | ||||||
|                     </select> |                     </select> | ||||||
|                 </div> |                 </div> | ||||||
|  |                 <div id="sizeControlsContainer" | ||||||
|  |                     style="margin-top: 10px; padding: 5px; border-top: 1px solid rgba(255, 255, 255, 0.2);"> | ||||||
|  |                     <div class="size-control" style="margin-bottom: 8px;"> | ||||||
|  |                         <label for="textSizeSlider">Text Size: </label> | ||||||
|  |                         <span id="textSizeValue">1.0</span><br> | ||||||
|  |                         <input type="range" id="textSizeSlider" min="0.1" max="2.0" step="0.1" value="1.0" | ||||||
|  |                             style="width: 100%; margin: 5px 0;" oninput="updateTextSize(this.value)"> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="size-control"> | ||||||
|  |                         <label for="entitySizeSlider">Player Size: </label> | ||||||
|  |                         <span id="entitySizeValue">1.0</span><br> | ||||||
|  |                         <input type="range" id="entitySizeSlider" min="0.5" max="2.0" step="0.1" value="1.0" | ||||||
|  |                             style="width: 100%; margin: 5px 0;" oninput="updateEntitySize(this.value)"> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|                 <button id="showDangerousBtn" onclick="toggleDangerousOptions()">Show Dangerous Options</button> |                 <button id="showDangerousBtn" onclick="toggleDangerousOptions()">Show Dangerous Options</button> | ||||||
|                 <div class="dangerous-options" id="dangerousOptions"> |                 <div class="dangerous-options" id="dangerousOptions"> | ||||||
|                     <div> |                     <div> | ||||||
| @@ -71,6 +92,6 @@ | |||||||
|     </div> |     </div> | ||||||
|     <script src="script.js"></script> |     <script src="script.js"></script> | ||||||
|     <script src="webstuff.js"></script> |     <script src="webstuff.js"></script> | ||||||
|  |  | ||||||
| </body> | </body> | ||||||
|  |  | ||||||
| </html> | </html> | ||||||
| @@ -17,10 +17,23 @@ let drawNames = true; | |||||||
| let drawGuns = true; | let drawGuns = true; | ||||||
| let drawMoney = true; | let drawMoney = true; | ||||||
|  |  | ||||||
|  | let canvasScale = 1; | ||||||
|  | let minTextSize = 16; | ||||||
|  | let minEntitySize = 10; | ||||||
|  | let textSizeMultiplier = 1.0; | ||||||
|  | let entitySizeMultiplier = 1.0; | ||||||
|  |  | ||||||
|  | const DEFAULT_TEXT_SIZE = 0.4; | ||||||
|  | const DEFAULT_ENTITY_SIZE = 1.2; | ||||||
|  | const DEFAULT_ZOOM_LEVEL = 2.4; | ||||||
|  |  | ||||||
| const NETWORK_SETTINGS = { | const NETWORK_SETTINGS = { | ||||||
|     useInterpolation: true, |     useInterpolation: true, | ||||||
|     interpolationAmount: 0.6, |     interpolationAmount: 0.6, | ||||||
|     pingInterval: 3000 |     pingInterval: 3000, | ||||||
|  |     maxRetries: 5, | ||||||
|  |     requestTimeout: 5000, | ||||||
|  |     reconnectDelay: 1000 | ||||||
| }; | }; | ||||||
|  |  | ||||||
| let connectionHealthy = true; | let connectionHealthy = true; | ||||||
| @@ -40,7 +53,6 @@ let lastKnownPositions = {}; | |||||||
| let entityInterpolationData = {}; | let entityInterpolationData = {}; | ||||||
| let lastUpdateTime = 0; | let lastUpdateTime = 0; | ||||||
| let networkLatencyHistory = []; | let networkLatencyHistory = []; | ||||||
| let lastPingSent = 0; |  | ||||||
|  |  | ||||||
| let focusedPlayerYaw = 0; | let focusedPlayerYaw = 0; | ||||||
| let focusedPlayerName = "YOU"; | let focusedPlayerName = "YOU"; | ||||||
| @@ -231,6 +243,7 @@ function render() { | |||||||
|  |  | ||||||
|     renderFrame(); |     renderFrame(); | ||||||
| } | } | ||||||
|  |  | ||||||
| function sendRequest() { | function sendRequest() { | ||||||
|     isRequestPending = true; |     isRequestPending = true; | ||||||
|     pingTracker.startRequest(); |     pingTracker.startRequest(); | ||||||
| @@ -280,7 +293,8 @@ function renderFrame() { | |||||||
|  |  | ||||||
|         drawBombTimer(); |         drawBombTimer(); | ||||||
|     } else if (!loaded) { |     } else if (!loaded) { | ||||||
|         ctx.font = "40px Arial"; |         const fontSize = Math.max(40 * canvasScale, 16); | ||||||
|  |         ctx.font = `${fontSize}px Arial`; | ||||||
|         ctx.textAlign = "center"; |         ctx.textAlign = "center"; | ||||||
|         ctx.textBaseline = "middle"; |         ctx.textBaseline = "middle"; | ||||||
|         ctx.fillStyle = textColor; |         ctx.fillStyle = textColor; | ||||||
| @@ -288,14 +302,15 @@ function renderFrame() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (drawStats) { |     if (drawStats) { | ||||||
|         ctx.font = "16px Arial"; |         const fontSize = Math.max(16 * canvasScale, 12); | ||||||
|  |         ctx.font = `${fontSize}px Arial`; | ||||||
|         ctx.textAlign = "left"; |         ctx.textAlign = "left"; | ||||||
|         ctx.fillStyle = "#00FF00"; |         ctx.fillStyle = "#00FF00"; | ||||||
|         let rotationStatus = "Active"; |         let rotationStatus = "Active"; | ||||||
|         if (temporarilyDisableRotation) rotationStatus = "Manually Disabled"; |         if (temporarilyDisableRotation) rotationStatus = "Manually Disabled"; | ||||||
|         else if (rotationDisabledUntilRespawn) rotationStatus = "Disabled (Death)"; |         else if (rotationDisabledUntilRespawn) rotationStatus = "Disabled (Death)"; | ||||||
|  |  | ||||||
|         ctx.fillText(`${currentFps} FPS | ${freq} Hz | Ping: ${Math.round(pingTracker.getAveragePing())}ms | Rotation: ${rotationStatus}`, 10, 20); |         ctx.fillText(`${currentFps} FPS | ${freq} Hz | Ping: ${Math.round(pingTracker.getAveragePing())}ms | Rotation: ${rotationStatus}`, 10, fontSize + 4); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -361,43 +376,47 @@ function drawImage() { | |||||||
|  |  | ||||||
|     ctx.save(); |     ctx.save(); | ||||||
|  |  | ||||||
|     const shouldRotate = rotateMap && |     if (playerCentered && focusedPlayerPos) { | ||||||
|  |         if (playerCenteredZoom !== 1.0) { | ||||||
|  |             ctx.translate(canvas.width / 2, canvas.height / 2); | ||||||
|  |             ctx.scale(playerCenteredZoom, playerCenteredZoom); | ||||||
|  |             ctx.translate(-canvas.width / 2, -canvas.height / 2); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (rotateMap && | ||||||
|  |             focusedPlayerPos && | ||||||
|  |             !temporarilyDisableRotation && | ||||||
|  |             !rotationDisabledUntilRespawn) { | ||||||
|  |  | ||||||
|  |             ctx.translate(canvas.width / 2, canvas.height / 2); | ||||||
|  |             ctx.rotate(degreesToRadians(focusedPlayerYaw + 270)); | ||||||
|  |             ctx.translate(-canvas.width / 2, -canvas.height / 2); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale; | ||||||
|  |         const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale; | ||||||
|  |  | ||||||
|  |         const playerCanvasX = (playerX / image.width) * canvas.width; | ||||||
|  |         const playerCanvasY = (playerY / image.height) * canvas.height; | ||||||
|  |  | ||||||
|  |         const translateX = (canvas.width / 2) - playerCanvasX; | ||||||
|  |         const translateY = (canvas.height / 2) - playerCanvasY; | ||||||
|  |  | ||||||
|  |         ctx.translate(translateX, translateY); | ||||||
|  |     } else if (rotateMap && | ||||||
|         focusedPlayerPos && |         focusedPlayerPos && | ||||||
|         !temporarilyDisableRotation && |         !temporarilyDisableRotation && | ||||||
|         !rotationDisabledUntilRespawn; |         !rotationDisabledUntilRespawn) { | ||||||
|  |  | ||||||
|     if (shouldRotate) { |  | ||||||
|         ctx.translate(canvas.width / 2, canvas.height / 2); |         ctx.translate(canvas.width / 2, canvas.height / 2); | ||||||
|         ctx.rotate(degreesToRadians(focusedPlayerYaw + 270)); |         ctx.rotate(degreesToRadians(focusedPlayerYaw + 270)); | ||||||
|         ctx.translate(-canvas.width / 2, -canvas.height / 2); |         ctx.translate(-canvas.width / 2, -canvas.height / 2); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (playerCentered && focusedPlayerPos) { |     ctx.drawImage( | ||||||
|         const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale; |         image, | ||||||
|         const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale; |         0, 0, image.width, image.height, | ||||||
|  |         0, 0, canvas.width, canvas.height | ||||||
|         const zoomLevel = 0.5; |     ); | ||||||
|         const viewWidth = image.width * zoomLevel; |  | ||||||
|         const viewHeight = image.height * zoomLevel; |  | ||||||
|  |  | ||||||
|         ctx.drawImage( |  | ||||||
|             image, |  | ||||||
|             playerX - (viewWidth / 2), playerY - (viewHeight / 2), viewWidth, viewHeight, |  | ||||||
|             0, 0, canvas.width, canvas.height |  | ||||||
|         ); |  | ||||||
|     } else if (zoomSet && boundingRect?.x != null) { |  | ||||||
|         ctx.drawImage( |  | ||||||
|             image, |  | ||||||
|             boundingRect.x, boundingRect.y, boundingRect.width, boundingRect.height, |  | ||||||
|             0, 0, canvas.width, canvas.height |  | ||||||
|         ); |  | ||||||
|     } else { |  | ||||||
|         ctx.drawImage( |  | ||||||
|             image, |  | ||||||
|             0, 0, image.width, image.height, |  | ||||||
|             0, 0, canvas.width, canvas.height |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ctx.restore(); |     ctx.restore(); | ||||||
| } | } | ||||||
| @@ -408,12 +427,119 @@ function toggleHealth() { | |||||||
|     localStorage.setItem('drawHealth', drawHealth ? 'true' : 'false'); |     localStorage.setItem('drawHealth', drawHealth ? 'true' : 'false'); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function mapAndTransformCoordinates(pos) { | ||||||
|  |     const canvasWidth = canvas.width; | ||||||
|  |     const canvasHeight = canvas.height; | ||||||
|  |     const imageWidth = image ? image.width : 1; | ||||||
|  |     const imageHeight = image ? image.height : 1; | ||||||
|  |  | ||||||
|  |     if (!map || !pos) return { | ||||||
|  |         pos: { x: 0, y: 0 }, | ||||||
|  |         textSize: minTextSize * textSizeMultiplier | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const posX = (pos.x - map.pos_x) / map.scale; | ||||||
|  |     const posY = (pos.y - map.pos_y) / -map.scale; | ||||||
|  |  | ||||||
|  |     let screenX = (posX / imageWidth) * canvasWidth; | ||||||
|  |     let screenY = (posY / imageHeight) * canvasHeight; | ||||||
|  |  | ||||||
|  |     if (playerCentered && focusedPlayerPos) { | ||||||
|  |         const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale; | ||||||
|  |         const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale; | ||||||
|  |  | ||||||
|  |         const playerRelX = playerX / imageWidth; | ||||||
|  |         const playerRelY = playerY / imageHeight; | ||||||
|  |  | ||||||
|  |         const centerX = canvasWidth / 2; | ||||||
|  |         const centerY = canvasHeight / 2; | ||||||
|  |  | ||||||
|  |         const playerScreenX = (playerX / imageWidth) * canvasWidth; | ||||||
|  |         const playerScreenY = (playerY / imageHeight) * canvasHeight; | ||||||
|  |  | ||||||
|  |         const deltaX = screenX - playerScreenX; | ||||||
|  |         const deltaY = screenY - playerScreenY; | ||||||
|  |  | ||||||
|  |         const zoomedDeltaX = deltaX * playerCenteredZoom; | ||||||
|  |         const zoomedDeltaY = deltaY * playerCenteredZoom; | ||||||
|  |  | ||||||
|  |         screenX = centerX + zoomedDeltaX; | ||||||
|  |         screenY = centerY + zoomedDeltaY; | ||||||
|  |  | ||||||
|  |         if (rotateMap && | ||||||
|  |             !temporarilyDisableRotation && | ||||||
|  |             !rotationDisabledUntilRespawn) { | ||||||
|  |  | ||||||
|  |             const relX = screenX - centerX; | ||||||
|  |             const relY = screenY - centerY; | ||||||
|  |  | ||||||
|  |             const angle = degreesToRadians(focusedPlayerYaw + 270); | ||||||
|  |             const cos = Math.cos(angle); | ||||||
|  |             const sin = Math.sin(angle); | ||||||
|  |  | ||||||
|  |             const rotX = relX * cos - relY * sin; | ||||||
|  |             const rotY = relX * sin + relY * cos; | ||||||
|  |  | ||||||
|  |             screenX = rotX + centerX; | ||||||
|  |             screenY = rotY + centerY; | ||||||
|  |         } | ||||||
|  |     } else if (rotateMap && | ||||||
|  |         focusedPlayerPos && | ||||||
|  |         !temporarilyDisableRotation && | ||||||
|  |         !rotationDisabledUntilRespawn) { | ||||||
|  |  | ||||||
|  |         const centerX = canvasWidth / 2; | ||||||
|  |         const centerY = canvasHeight / 2; | ||||||
|  |  | ||||||
|  |         const relX = screenX - centerX; | ||||||
|  |         const relY = screenY - centerY; | ||||||
|  |  | ||||||
|  |         const angle = degreesToRadians(focusedPlayerYaw + 270); | ||||||
|  |         const cos = Math.cos(angle); | ||||||
|  |         const sin = Math.sin(angle); | ||||||
|  |  | ||||||
|  |         const rotX = relX * cos - relY * sin; | ||||||
|  |         const rotY = relX * sin + relY * cos; | ||||||
|  |  | ||||||
|  |         screenX = rotX + centerX; | ||||||
|  |         screenY = rotY + centerY; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const finalTextSize = playerCentered ? | ||||||
|  |         minTextSize * textSizeMultiplier * playerCenteredZoom : | ||||||
|  |         minTextSize * textSizeMultiplier; | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         pos: { x: screenX, y: screenY }, | ||||||
|  |         textSize: finalTextSize | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateZoomLevel(value) { | ||||||
|  |     playerCenteredZoom = parseFloat(value); | ||||||
|  |     const valueDisplay = document.getElementById('zoomLevelValue'); | ||||||
|  |     if (valueDisplay) valueDisplay.textContent = value; | ||||||
|  |     localStorage.setItem('playerCenteredZoom', value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function toggleCentered() { | ||||||
|  |     playerCentered = !playerCentered; | ||||||
|  |     updateZoomSliderVisibility(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateZoomSliderVisibility() { | ||||||
|  |     const zoomSliderContainer = document.getElementById('zoomLevelContainer'); | ||||||
|  |     if (zoomSliderContainer) { | ||||||
|  |         zoomSliderContainer.style.display = playerCentered ? 'block' : 'none'; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function drawPlayerHealth(pos, playerType, health, hasBomb) { | function drawPlayerHealth(pos, playerType, health, hasBomb) { | ||||||
|     if (!map) return; |     if (!map) return; | ||||||
|  |  | ||||||
|     const transformed = mapAndTransformCoordinates(pos); |     const transformed = mapAndTransformCoordinates(pos); | ||||||
|     const mapPos = transformed.pos; |     const mapPos = transformed.pos; | ||||||
|     const textSize = transformed.textSize * 0.8; |     const textSize = transformed.textSize; | ||||||
|  |  | ||||||
|     let extraOffset = 0; |     let extraOffset = 0; | ||||||
|     if (drawNames) extraOffset += 15; |     if (drawNames) extraOffset += 15; | ||||||
| @@ -432,8 +558,9 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) { | |||||||
|         healthColor = "#FF0000"; |         healthColor = "#FF0000"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const barWidth = 40; |     const barWidth = Math.max(60, 40 * textSizeMultiplier); | ||||||
|     const barHeight = 5; |     const barHeight = Math.max(8, 5 * textSizeMultiplier); | ||||||
|  |  | ||||||
|     ctx.fillStyle = "#444444"; |     ctx.fillStyle = "#444444"; | ||||||
|     ctx.fillRect(mapPos.x - barWidth / 2, textY, barWidth, barHeight); |     ctx.fillRect(mapPos.x - barWidth / 2, textY, barWidth, barHeight); | ||||||
|  |  | ||||||
| @@ -441,15 +568,15 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) { | |||||||
|     const healthWidth = (health / 100) * barWidth; |     const healthWidth = (health / 100) * barWidth; | ||||||
|     ctx.fillRect(mapPos.x - barWidth / 2, textY, healthWidth, barHeight); |     ctx.fillRect(mapPos.x - barWidth / 2, textY, healthWidth, barHeight); | ||||||
|  |  | ||||||
|     ctx.font = `${textSize}px Arial`; |     ctx.font = `bold ${textSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "top"; |     ctx.textBaseline = "top"; | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.strokeText(`${health}HP`, mapPos.x, textY + barHeight + 1); |     ctx.strokeText(`${health}HP`, mapPos.x, textY + barHeight + 2); | ||||||
|     ctx.fillStyle = healthColor; |     ctx.fillStyle = healthColor; | ||||||
|     ctx.fillText(`${health}HP`, mapPos.x, textY + barHeight + 1); |     ctx.fillText(`${health}HP`, mapPos.x, textY + barHeight + 2); | ||||||
| } | } | ||||||
|  |  | ||||||
| function drawEntities() { | function drawEntities() { | ||||||
| @@ -577,8 +704,12 @@ function drawBombTimer() { | |||||||
|     const maxWidth = 1024 - 128 - 128; |     const maxWidth = 1024 - 128 - 128; | ||||||
|     const timeleft = radarData.bombDefuseTimeleft; |     const timeleft = radarData.bombDefuseTimeleft; | ||||||
|  |  | ||||||
|  |     const timerHeight = Math.max(16, 10 * canvasScale); | ||||||
|  |     const timerY = Math.max(16, 10 * canvasScale); | ||||||
|  |     const fontSize = Math.max(24, 18 * canvasScale); | ||||||
|  |  | ||||||
|     ctx.fillStyle = "black"; |     ctx.fillStyle = "black"; | ||||||
|     ctx.fillRect(128, 16, maxWidth, 16); |     ctx.fillRect(128, timerY, maxWidth, timerHeight); | ||||||
|  |  | ||||||
|     if (radarData.bombBeingDefused) { |     if (radarData.bombBeingDefused) { | ||||||
|         ctx.fillStyle = radarData.bombCanDefuse ? teamColor : enemyColor; |         ctx.fillStyle = radarData.bombCanDefuse ? teamColor : enemyColor; | ||||||
| @@ -586,32 +717,32 @@ function drawBombTimer() { | |||||||
|         ctx.fillStyle = bombColor; |         ctx.fillStyle = bombColor; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.fillRect(130, 18, (maxWidth - 2) * (timeleft / 40), 12); |     ctx.fillRect(130, timerY + 2, (maxWidth - 2) * (timeleft / 40), timerHeight - 4); | ||||||
|  |  | ||||||
|     ctx.font = "24px Arial"; |     ctx.font = `bold ${fontSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "middle"; |     ctx.textBaseline = "middle"; | ||||||
|     ctx.fillStyle = textColor; |     ctx.fillStyle = textColor; | ||||||
|     ctx.fillText(`${timeleft.toFixed(1)}s`, 1024 / 2, 28 + 24); |     ctx.fillText(`${timeleft.toFixed(1)}s`, 1024 / 2, timerY + timerHeight + fontSize / 2 + 4); | ||||||
|  |  | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 2; | ||||||
|  |  | ||||||
|     ctx.beginPath(); |     ctx.beginPath(); | ||||||
|     ctx.moveTo(128 + (maxWidth * (5 / 40)), 16); |     ctx.moveTo(128 + (maxWidth * (5 / 40)), timerY); | ||||||
|     ctx.lineTo(128 + (maxWidth * (5 / 40)), 32); |     ctx.lineTo(128 + (maxWidth * (5 / 40)), timerY + timerHeight); | ||||||
|     ctx.stroke(); |     ctx.stroke(); | ||||||
|  |  | ||||||
|     ctx.beginPath(); |     ctx.beginPath(); | ||||||
|     ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), 16); |     ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), timerY); | ||||||
|     ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), 32); |     ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), timerY + timerHeight); | ||||||
|     ctx.stroke(); |     ctx.stroke(); | ||||||
|  |  | ||||||
|     if (radarData.bombCanDefuse) { |     if (radarData.bombCanDefuse) { | ||||||
|         ctx.strokeStyle = "green"; |         ctx.strokeStyle = "green"; | ||||||
|         ctx.beginPath(); |         ctx.beginPath(); | ||||||
|         ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 16); |         ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY); | ||||||
|         ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 32); |         ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY + timerHeight); | ||||||
|         ctx.stroke(); |         ctx.stroke(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -670,79 +801,6 @@ function mapCoordinates(coordinates) { | |||||||
|     return { x: offset_x, y: offset_y }; |     return { x: offset_x, y: offset_y }; | ||||||
| } | } | ||||||
|  |  | ||||||
| function mapAndTransformCoordinates(pos) { |  | ||||||
|     const canvasWidth = canvas.width; |  | ||||||
|     const canvasHeight = canvas.height; |  | ||||||
|     const imageWidth = image ? image.width : 1; |  | ||||||
|     const imageHeight = image ? image.height : 1; |  | ||||||
|  |  | ||||||
|     if (!map || !pos) return { pos: { x: 0, y: 0 }, textSize: 12 }; |  | ||||||
|  |  | ||||||
|     const offset_x = (pos.x - map.pos_x) / map.scale; |  | ||||||
|     const offset_y = (pos.y - map.pos_y) / -map.scale; |  | ||||||
|  |  | ||||||
|     let mapPos = { x: offset_x, y: offset_y }; |  | ||||||
|     let textSize = 12; |  | ||||||
|  |  | ||||||
|     if (zoomSet && boundingRect && boundingRect.x != null) { |  | ||||||
|         const xScale = boundingRect.width / imageWidth; |  | ||||||
|         const yScale = boundingRect.height / imageHeight; |  | ||||||
|         mapPos = { |  | ||||||
|             x: (mapPos.x - boundingRect.x) / xScale, |  | ||||||
|             y: (mapPos.y - boundingRect.y) / yScale |  | ||||||
|         }; |  | ||||||
|         textSize = (imageWidth / boundingRect.width) * 12; |  | ||||||
|     } |  | ||||||
|     else if (playerCentered && focusedPlayerPos) { |  | ||||||
|         const zoomLevel = 0.5; |  | ||||||
|         const viewWidth = imageWidth * zoomLevel; |  | ||||||
|         const viewHeight = imageHeight * zoomLevel; |  | ||||||
|  |  | ||||||
|         let playerMapPos; |  | ||||||
|         if (focusedPlayerName === "YOU" && localPlayerPos) { |  | ||||||
|             const lpx = (localPlayerPos.x - map.pos_x) / map.scale; |  | ||||||
|             const lpy = (localPlayerPos.y - map.pos_y) / -map.scale; |  | ||||||
|             playerMapPos = { x: lpx, y: lpy }; |  | ||||||
|         } else if (focusedPlayerPos) { |  | ||||||
|             const fpx = (focusedPlayerPos.x - map.pos_x) / map.scale; |  | ||||||
|             const fpy = (focusedPlayerPos.y - map.pos_y) / -map.scale; |  | ||||||
|             playerMapPos = { x: fpx, y: fpy }; |  | ||||||
|         } else { |  | ||||||
|             playerMapPos = { x: 0, y: 0 }; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         mapPos.x = (mapPos.x - (playerMapPos.x - viewWidth / 2)) * canvasWidth / viewWidth; |  | ||||||
|         mapPos.y = (mapPos.y - (playerMapPos.y - viewHeight / 2)) * canvasHeight / viewHeight; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         mapPos.x = mapPos.x * canvasWidth / imageWidth; |  | ||||||
|         mapPos.y = mapPos.y * canvasHeight / imageHeight; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const shouldRotate = rotateMap && |  | ||||||
|         typeof focusedPlayerYaw === 'number' && |  | ||||||
|         !temporarilyDisableRotation && |  | ||||||
|         !rotationDisabledUntilRespawn; |  | ||||||
|  |  | ||||||
|     if (shouldRotate) { |  | ||||||
|         const canvasCenter = { x: canvasWidth / 2, y: canvasHeight / 2 }; |  | ||||||
|         const rotationYaw = focusedPlayerName === "YOU" ? localYaw : focusedPlayerYaw; |  | ||||||
|         const angle = rotationYaw + 270; |  | ||||||
|  |  | ||||||
|         const radians = angle * (Math.PI / 180); |  | ||||||
|         const cos = Math.cos(radians); |  | ||||||
|         const sin = Math.sin(radians); |  | ||||||
|  |  | ||||||
|         const nx = mapPos.x - canvasCenter.x; |  | ||||||
|         const ny = mapPos.y - canvasCenter.y; |  | ||||||
|  |  | ||||||
|         mapPos.x = nx * cos - ny * sin + canvasCenter.x; |  | ||||||
|         mapPos.y = nx * sin + ny * cos + canvasCenter.y; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return { pos: mapPos, textSize: textSize }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped) { | function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped) { | ||||||
|     if (!map) return; |     if (!map) return; | ||||||
|  |  | ||||||
| @@ -766,11 +824,11 @@ function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped) | |||||||
|         displayName += " [SCOPED]"; |         displayName += " [SCOPED]"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.font = `${textSize}px Arial`; |     ctx.font = `bold ${textSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "top"; |     ctx.textBaseline = "top"; | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.strokeText(displayName, mapPos.x, textY); |     ctx.strokeText(displayName, mapPos.x, textY); | ||||||
|     ctx.fillText(displayName, mapPos.x, textY); |     ctx.fillText(displayName, mapPos.x, textY); | ||||||
| @@ -800,11 +858,11 @@ function drawPlayerMoney(pos, playerType, money, hasBomb) { | |||||||
|         ctx.fillStyle = "#FF4500"; |         ctx.fillStyle = "#FF4500"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.font = `${textSize}px Arial`; |     ctx.font = `bold ${textSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "top"; |     ctx.textBaseline = "top"; | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.strokeText(formattedMoney, mapPos.x, textY); |     ctx.strokeText(formattedMoney, mapPos.x, textY); | ||||||
|     ctx.fillText(formattedMoney, mapPos.x, textY); |     ctx.fillText(formattedMoney, mapPos.x, textY); | ||||||
| @@ -827,11 +885,11 @@ function drawPlayerWeapon(pos, playerType, weaponId) { | |||||||
|         ctx.fillStyle = textColor; |         ctx.fillStyle = textColor; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.font = `${textSize}px Arial`; |     ctx.font = `bold ${textSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "top"; |     ctx.textBaseline = "top"; | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.strokeText(`[${weaponName}]`, mapPos.x, textY); |     ctx.strokeText(`[${weaponName}]`, mapPos.x, textY); | ||||||
|     ctx.fillText(`[${weaponName}]`, mapPos.x, textY); |     ctx.fillText(`[${weaponName}]`, mapPos.x, textY); | ||||||
| @@ -847,11 +905,11 @@ function drawPlayerBomb(pos, playerType) { | |||||||
|     const textY = mapPos.y + (drawNames ? (drawGuns ? 50 : 35) : (drawGuns ? 35 : 20)); |     const textY = mapPos.y + (drawNames ? (drawGuns ? 50 : 35) : (drawGuns ? 35 : 20)); | ||||||
|  |  | ||||||
|     ctx.fillStyle = bombColor; |     ctx.fillStyle = bombColor; | ||||||
|     ctx.font = `${textSize}px Arial`; |     ctx.font = `bold ${textSize}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "top"; |     ctx.textBaseline = "top"; | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.strokeText("[C4]", mapPos.x, textY); |     ctx.strokeText("[C4]", mapPos.x, textY); | ||||||
|     ctx.fillText("[C4]", mapPos.x, textY); |     ctx.fillText("[C4]", mapPos.x, textY); | ||||||
| @@ -862,18 +920,18 @@ function drawBomb(pos, planted) { | |||||||
|  |  | ||||||
|     const transformed = mapAndTransformCoordinates(pos); |     const transformed = mapAndTransformCoordinates(pos); | ||||||
|     const mapPos = transformed.pos; |     const mapPos = transformed.pos; | ||||||
|     const size = transformed.textSize * 0.7; |     const size = minEntitySize * entitySizeMultiplier; | ||||||
|  |  | ||||||
|     ctx.beginPath(); |     ctx.beginPath(); | ||||||
|     ctx.arc(mapPos.x, mapPos.y, size, 0, 2 * Math.PI); |     ctx.arc(mapPos.x, mapPos.y, size, 0, 2 * Math.PI); | ||||||
|     ctx.fillStyle = bombColor; |     ctx.fillStyle = bombColor; | ||||||
|     ctx.fill(); |     ctx.fill(); | ||||||
|  |  | ||||||
|     ctx.lineWidth = 2; |     ctx.lineWidth = 3; | ||||||
|     ctx.strokeStyle = "black"; |     ctx.strokeStyle = "black"; | ||||||
|     ctx.stroke(); |     ctx.stroke(); | ||||||
|  |  | ||||||
|     ctx.font = size * 1.2 + "px Arial"; |     ctx.font = `bold ${Math.max(size * 1.2, minTextSize)}px Arial`; | ||||||
|     ctx.textAlign = "center"; |     ctx.textAlign = "center"; | ||||||
|     ctx.textBaseline = "middle"; |     ctx.textBaseline = "middle"; | ||||||
|     ctx.fillStyle = "white"; |     ctx.fillStyle = "white"; | ||||||
| @@ -895,7 +953,8 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i | |||||||
|  |  | ||||||
|     const transformed = mapAndTransformCoordinates(pos); |     const transformed = mapAndTransformCoordinates(pos); | ||||||
|     const mapPos = transformed.pos; |     const mapPos = transformed.pos; | ||||||
|     let circleRadius = transformed.textSize * 0.6; |  | ||||||
|  |     let circleRadius = minEntitySize * entitySizeMultiplier; | ||||||
|     const distance = circleRadius + 2; |     const distance = circleRadius + 2; | ||||||
|     const radius = distance + 5; |     const radius = distance + 5; | ||||||
|     const arrowWidth = 35; |     const arrowWidth = 35; | ||||||
| @@ -918,7 +977,7 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (dormant) { |     if (dormant) { | ||||||
|         ctx.font = "20px Arial"; |         ctx.font = `bold ${transformed.textSize}px Arial`; | ||||||
|         ctx.textAlign = "center"; |         ctx.textAlign = "center"; | ||||||
|         ctx.fillStyle = fillStyle; |         ctx.fillStyle = fillStyle; | ||||||
|         ctx.fillText("?", mapPos.x, mapPos.y); |         ctx.fillText("?", mapPos.x, mapPos.y); | ||||||
| @@ -977,7 +1036,7 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i | |||||||
|             ctx.lineTo(lineOfSightX, lineOfSightY); |             ctx.lineTo(lineOfSightX, lineOfSightY); | ||||||
|  |  | ||||||
|             ctx.strokeStyle = playerType == "Enemy" ? enemyColor : teamColor; |             ctx.strokeStyle = playerType == "Enemy" ? enemyColor : teamColor; | ||||||
|             ctx.lineWidth = 1; |             ctx.lineWidth = 2; | ||||||
|             ctx.stroke(); |             ctx.stroke(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -1198,6 +1257,34 @@ function connect() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function updateTextSize(value) { | ||||||
|  |     textSizeMultiplier = parseFloat(value); | ||||||
|  |     const valueDisplay = document.getElementById('textSizeValue'); | ||||||
|  |     if (valueDisplay) valueDisplay.textContent = value; | ||||||
|  |     localStorage.setItem('textSizeMultiplier', value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateEntitySize(value) { | ||||||
|  |     entitySizeMultiplier = parseFloat(value); | ||||||
|  |     const valueDisplay = document.getElementById('entitySizeValue'); | ||||||
|  |     if (valueDisplay) valueDisplay.textContent = value; | ||||||
|  |     localStorage.setItem('entitySizeMultiplier', value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function resetSizes() { | ||||||
|  |     const textSlider = document.getElementById('textSizeSlider'); | ||||||
|  |     const entitySlider = document.getElementById('entitySizeSlider'); | ||||||
|  |     const zoomSlider = document.getElementById('zoomLevelSlider'); | ||||||
|  |  | ||||||
|  |     if (textSlider) textSlider.value = DEFAULT_TEXT_SIZE.toString(); | ||||||
|  |     if (entitySlider) entitySlider.value = DEFAULT_ENTITY_SIZE.toString(); | ||||||
|  |     if (zoomSlider) zoomSlider.value = DEFAULT_ZOOM_LEVEL.toString(); | ||||||
|  |  | ||||||
|  |     updateTextSize(DEFAULT_TEXT_SIZE.toString()); | ||||||
|  |     updateEntitySize(DEFAULT_ENTITY_SIZE.toString()); | ||||||
|  |     updateZoomLevel(DEFAULT_ZOOM_LEVEL.toString()); | ||||||
|  | } | ||||||
|  |  | ||||||
| function toggleZoom() { | function toggleZoom() { | ||||||
|     shouldZoom = !shouldZoom; |     shouldZoom = !shouldZoom; | ||||||
| } | } | ||||||
| @@ -1218,10 +1305,6 @@ function toggleRotate() { | |||||||
|     rotateMap = !rotateMap; |     rotateMap = !rotateMap; | ||||||
| } | } | ||||||
|  |  | ||||||
| function toggleCentered() { |  | ||||||
|     playerCentered = !playerCentered; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function toggleMoneyReveal() { | function toggleMoneyReveal() { | ||||||
|     if (websocket && websocket.readyState === WebSocket.OPEN) { |     if (websocket && websocket.readyState === WebSocket.OPEN) { | ||||||
|         console.log("[radarflow] Sending toggleMoneyReveal command"); |         console.log("[radarflow] Sending toggleMoneyReveal command"); | ||||||
| @@ -1264,12 +1347,26 @@ function togglePerformanceMode() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | window.addEventListener('resize', () => { | ||||||
|  |     if (canvas) { | ||||||
|  |         const canvasRect = canvas.getBoundingClientRect(); | ||||||
|  |         canvasScale = Math.min(canvasRect.width, canvasRect.height) / 1024; | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
| addEventListener("DOMContentLoaded", () => { | addEventListener("DOMContentLoaded", () => { | ||||||
|     const savedDrawHealth = localStorage.getItem('drawHealth'); |     const savedDrawHealth = localStorage.getItem('drawHealth'); | ||||||
|     drawHealth = savedDrawHealth !== null ? savedDrawHealth === 'true' : true; |     drawHealth = savedDrawHealth !== null ? savedDrawHealth === 'true' : true; | ||||||
|  |  | ||||||
|     const savedDrawMoney = localStorage.getItem('drawMoney'); |     const savedDrawMoney = localStorage.getItem('drawMoney'); | ||||||
|     drawMoney = savedDrawMoney !== null ? savedDrawMoney === 'true' : true; |     drawMoney = savedDrawMoney !== null ? savedDrawMoney === 'true' : true; | ||||||
|  |  | ||||||
|  |     const savedTextSize = localStorage.getItem('textSizeMultiplier'); | ||||||
|  |     textSizeMultiplier = savedTextSize !== null ? parseFloat(savedTextSize) : DEFAULT_TEXT_SIZE; | ||||||
|  |  | ||||||
|  |     const savedEntitySize = localStorage.getItem('entitySizeMultiplier'); | ||||||
|  |     entitySizeMultiplier = savedEntitySize !== null ? parseFloat(savedEntitySize) : DEFAULT_ENTITY_SIZE; | ||||||
|  |  | ||||||
|     const checkboxes = { |     const checkboxes = { | ||||||
|         "zoomCheck": false, |         "zoomCheck": false, | ||||||
|         "statsCheck": true, |         "statsCheck": true, | ||||||
| @@ -1278,7 +1375,8 @@ addEventListener("DOMContentLoaded", () => { | |||||||
|         "moneyDisplay": drawMoney, |         "moneyDisplay": drawMoney, | ||||||
|         "moneyReveal": false, |         "moneyReveal": false, | ||||||
|         "rotateCheck": true, |         "rotateCheck": true, | ||||||
|         "centerCheck": true |         "centerCheck": true, | ||||||
|  |         "healthCheck": drawHealth | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     Object.entries(checkboxes).forEach(([id, state]) => { |     Object.entries(checkboxes).forEach(([id, state]) => { | ||||||
| @@ -1286,12 +1384,41 @@ addEventListener("DOMContentLoaded", () => { | |||||||
|         if (checkbox) checkbox.checked = state; |         if (checkbox) checkbox.checked = state; | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     const textSizeSlider = document.getElementById('textSizeSlider'); | ||||||
|  |     if (textSizeSlider) { | ||||||
|  |         textSizeSlider.value = textSizeMultiplier; | ||||||
|  |         const textSizeValue = document.getElementById('textSizeValue'); | ||||||
|  |         if (textSizeValue) textSizeValue.textContent = textSizeMultiplier; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const entitySizeSlider = document.getElementById('entitySizeSlider'); | ||||||
|  |     if (entitySizeSlider) { | ||||||
|  |         entitySizeSlider.value = entitySizeMultiplier; | ||||||
|  |         const entitySizeValue = document.getElementById('entitySizeValue'); | ||||||
|  |         if (entitySizeValue) entitySizeValue.textContent = entitySizeMultiplier; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const savedZoom = localStorage.getItem('playerCenteredZoom'); | ||||||
|  |     playerCenteredZoom = savedZoom !== null ? parseFloat(savedZoom) : DEFAULT_ZOOM_LEVEL; | ||||||
|  |  | ||||||
|  |     const zoomSlider = document.getElementById('zoomLevelSlider'); | ||||||
|  |     if (zoomSlider) { | ||||||
|  |         zoomSlider.value = playerCenteredZoom; | ||||||
|  |         const zoomValue = document.getElementById('zoomLevelValue'); | ||||||
|  |         if (zoomValue) zoomValue.textContent = playerCenteredZoom; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     updateZoomSliderVisibility(); | ||||||
|  |  | ||||||
|     canvas = document.getElementById('canvas'); |     canvas = document.getElementById('canvas'); | ||||||
|     if (canvas) { |     if (canvas) { | ||||||
|         canvas.width = 1024; |         canvas.width = 1024; | ||||||
|         canvas.height = 1024; |         canvas.height = 1024; | ||||||
|         ctx = canvas.getContext('2d'); |         ctx = canvas.getContext('2d'); | ||||||
|  |  | ||||||
|  |         const canvasRect = canvas.getBoundingClientRect(); | ||||||
|  |         canvasScale = Math.min(canvasRect.width, canvasRect.height) / 1024; | ||||||
|  |  | ||||||
|         connect(); |         connect(); | ||||||
|     } else { |     } else { | ||||||
|         console.error("[radarflow] Canvas element not found"); |         console.error("[radarflow] Canvas element not found"); | ||||||
|   | |||||||
| @@ -23,6 +23,8 @@ body { | |||||||
| canvas { | canvas { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     height: 100%; |     height: 100%; | ||||||
|  |     image-rendering: -webkit-optimize-contrast; | ||||||
|  |     image-rendering: crisp-edges; | ||||||
| } | } | ||||||
|  |  | ||||||
| #settingsHolder { | #settingsHolder { | ||||||
| @@ -47,6 +49,25 @@ canvas { | |||||||
|     background-color: rgba(25, 25, 25, 0.7); |     background-color: rgba(25, 25, 25, 0.7); | ||||||
|     border-radius: 5px; |     border-radius: 5px; | ||||||
|     transition: opacity 0.3s ease; |     transition: opacity 0.3s ease; | ||||||
|  |     font-size: 14px; | ||||||
|  |     max-height: 90vh; | ||||||
|  |     overflow-y: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |     #settingsHolder .settings { | ||||||
|  |         font-size: 16px; | ||||||
|  |         padding: 12px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #settingsHolder .settings input[type="checkbox"] { | ||||||
|  |         transform: scale(1.2); | ||||||
|  |         margin-right: 8px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #settingsHolder .settings>div { | ||||||
|  |         padding: 6px 0; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #settingsHolder:hover .settings { | #settingsHolder:hover .settings { | ||||||
| @@ -92,31 +113,67 @@ canvas { | |||||||
|     background-color: #8a0000; |     background-color: #8a0000; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .size-control { | ||||||
|  |     margin-bottom: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .size-control label { | ||||||
|  |     display: inline-block; | ||||||
|  |     margin-bottom: 3px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input[type="range"] { | ||||||
|  |     width: 100%; | ||||||
|  |     margin: 5px 0; | ||||||
|  |     -webkit-appearance: none; | ||||||
|  |     height: 6px; | ||||||
|  |     background: #555; | ||||||
|  |     border-radius: 3px; | ||||||
|  |     outline: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input[type="range"]::-webkit-slider-thumb { | ||||||
|  |     -webkit-appearance: none; | ||||||
|  |     appearance: none; | ||||||
|  |     width: 16px; | ||||||
|  |     height: 16px; | ||||||
|  |     border-radius: 50%; | ||||||
|  |     background: #68a3e5; | ||||||
|  |     cursor: pointer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input[type="range"]::-moz-range-thumb { | ||||||
|  |     width: 16px; | ||||||
|  |     height: 16px; | ||||||
|  |     border-radius: 50%; | ||||||
|  |     background: #68a3e5; | ||||||
|  |     cursor: pointer; | ||||||
|  |     border: none; | ||||||
|  | } | ||||||
|  |  | ||||||
| @media (max-width: 600px), | @media (max-width: 600px), | ||||||
| (max-height: 600px) { | (max-height: 600px) { | ||||||
|     #settingsHolder { |     #settingsHolder { | ||||||
|         display: none; |         display: none; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #showMenuBtn { | ||||||
|  |         display: block !important; | ||||||
|  |         font-size: 16px !important; | ||||||
|  |         padding: 8px 12px !important; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (max-width: 400px), | @media (max-width: 400px), | ||||||
| (max-height: 400px) { | (max-height: 400px) { | ||||||
|     #canvasContainer::before { |     #canvasContainer::before { | ||||||
|         content: 'settings'; |         content: ''; | ||||||
|         position: fixed; |         display: none; | ||||||
|         top: 10px; |     } | ||||||
|         left: 10px; |  | ||||||
|         background-color: rgba(25, 25, 25, 0.7); |     #showMenuBtn { | ||||||
|         color: white; |         padding: 6px 10px !important; | ||||||
|         width: 30px; |         font-size: 14px !important; | ||||||
|         height: 30px; |  | ||||||
|         border-radius: 15px; |  | ||||||
|         display: flex; |  | ||||||
|         align-items: center; |  | ||||||
|         justify-content: center; |  | ||||||
|         font-size: 16px; |  | ||||||
|         cursor: pointer; |  | ||||||
|         z-index: 101; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -129,6 +186,7 @@ canvas { | |||||||
|     margin-left: 5px; |     margin-left: 5px; | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     min-width: 150px; |     min-width: 150px; | ||||||
|  |     font-size: inherit; | ||||||
| } | } | ||||||
|  |  | ||||||
| #playerSelect:hover { | #playerSelect:hover { | ||||||
| @@ -147,19 +205,23 @@ canvas { | |||||||
|  |  | ||||||
| .player-focus { | .player-focus { | ||||||
|     margin-top: 10px; |     margin-top: 10px; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     flex-wrap: wrap; | ||||||
| } | } | ||||||
|  |  | ||||||
| #hideMenuBtn { | #hideMenuBtn { | ||||||
|     background-color: #333; |     background-color: #333; | ||||||
|     color: white; |     color: white; | ||||||
|     border: none; |     border: none; | ||||||
|     padding: 5px 10px; |     padding: 8px 10px; | ||||||
|     margin-top: 10px; |     margin-top: 10px; | ||||||
|     border-radius: 3px; |     border-radius: 3px; | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | ||||||
|     transition: background-color 0.3s; |     transition: background-color 0.3s; | ||||||
|     width: 100%; |     width: 100%; | ||||||
|  |     font-size: inherit; | ||||||
| } | } | ||||||
|  |  | ||||||
| #hideMenuBtn:hover { | #hideMenuBtn:hover { | ||||||
| @@ -170,19 +232,64 @@ canvas { | |||||||
|     position: fixed; |     position: fixed; | ||||||
|     top: 10px; |     top: 10px; | ||||||
|     left: 10px; |     left: 10px; | ||||||
|     background-color: rgba(25, 25, 25, 0.7); |     background-color: rgba(25, 25, 25, 0.9); | ||||||
|     color: white; |     color: white; | ||||||
|     border: none; |     border: none; | ||||||
|     padding: 5px 10px; |     padding: 8px 12px; | ||||||
|     border-radius: 15px; |     border-radius: 15px; | ||||||
|     font-size: 14px; |     font-size: 16px; | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     z-index: 101; |     z-index: 101; | ||||||
|     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | ||||||
|     transition: opacity 0.3s; |     transition: opacity 0.3s; | ||||||
|     opacity: 0.6; |     opacity: 0.8; | ||||||
|  |     box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); | ||||||
| } | } | ||||||
|  |  | ||||||
| #showMenuBtn:hover { | #showMenuBtn:hover { | ||||||
|     opacity: 1; |     opacity: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input[type="checkbox"] { | ||||||
|  |     margin-right: 8px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | label { | ||||||
|  |     cursor: pointer; | ||||||
|  |     user-select: none; | ||||||
|  |     margin-bottom: 2px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .settings>div { | ||||||
|  |     margin-bottom: 5px; | ||||||
|  |     padding: 3px 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .touch-device input[type="checkbox"] { | ||||||
|  |     transform: scale(1.3); | ||||||
|  |     margin: 2px 10px 2px 2px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .touch-device input[type="range"]::-webkit-slider-thumb { | ||||||
|  |     width: 20px; | ||||||
|  |     height: 20px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .touch-device input[type="range"]::-moz-range-thumb { | ||||||
|  |     width: 20px; | ||||||
|  |     height: 20px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .touch-device .settings>div { | ||||||
|  |     padding: 6px 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (prefers-color-scheme: dark) { | ||||||
|  |     #settingsHolder .settings { | ||||||
|  |         background-color: rgba(15, 15, 15, 0.85); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #showMenuBtn { | ||||||
|  |         background-color: rgba(15, 15, 15, 0.9); | ||||||
|  |     } | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user