From a17146fee9503a88266176567c535340509ee51d Mon Sep 17 00:00:00 2001 From: Wizzard <rich@bandaholics.cash> Date: Mon, 17 Mar 2025 17:48:25 -0400 Subject: [PATCH] Add: Slider customization & fix black spots showing up on map --- webradar/index.html | 23 ++- webradar/script.js | 415 +++++++++++++++++++++++++++++--------------- webradar/styles.css | 147 +++++++++++++--- 3 files changed, 420 insertions(+), 165 deletions(-) diff --git a/webradar/index.html b/webradar/index.html index 0978c50..2583c52 100644 --- a/webradar/index.html +++ b/webradar/index.html @@ -50,6 +50,12 @@ <div> <input type="checkbox" onclick="toggleCentered()" id="centerCheck" name="center" checked /> <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 class="player-focus"> <label for="playerSelect">Focus Player:</label> @@ -57,6 +63,21 @@ <option value="local">YOU</option> </select> </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> <div class="dangerous-options" id="dangerousOptions"> <div> @@ -71,6 +92,6 @@ </div> <script src="script.js"></script> <script src="webstuff.js"></script> - </body> + </html> \ No newline at end of file diff --git a/webradar/script.js b/webradar/script.js index e522725..167c906 100644 --- a/webradar/script.js +++ b/webradar/script.js @@ -17,10 +17,23 @@ let drawNames = true; let drawGuns = 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 = { useInterpolation: true, interpolationAmount: 0.6, - pingInterval: 3000 + pingInterval: 3000, + maxRetries: 5, + requestTimeout: 5000, + reconnectDelay: 1000 }; let connectionHealthy = true; @@ -40,7 +53,6 @@ let lastKnownPositions = {}; let entityInterpolationData = {}; let lastUpdateTime = 0; let networkLatencyHistory = []; -let lastPingSent = 0; let focusedPlayerYaw = 0; let focusedPlayerName = "YOU"; @@ -231,6 +243,7 @@ function render() { renderFrame(); } + function sendRequest() { isRequestPending = true; pingTracker.startRequest(); @@ -280,7 +293,8 @@ function renderFrame() { drawBombTimer(); } else if (!loaded) { - ctx.font = "40px Arial"; + const fontSize = Math.max(40 * canvasScale, 16); + ctx.font = `${fontSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = textColor; @@ -288,14 +302,15 @@ function renderFrame() { } if (drawStats) { - ctx.font = "16px Arial"; + const fontSize = Math.max(16 * canvasScale, 12); + ctx.font = `${fontSize}px Arial`; ctx.textAlign = "left"; ctx.fillStyle = "#00FF00"; let rotationStatus = "Active"; if (temporarilyDisableRotation) rotationStatus = "Manually Disabled"; 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(); - 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 && !temporarilyDisableRotation && - !rotationDisabledUntilRespawn; - - if (shouldRotate) { + !rotationDisabledUntilRespawn) { ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(degreesToRadians(focusedPlayerYaw + 270)); ctx.translate(-canvas.width / 2, -canvas.height / 2); } - if (playerCentered && focusedPlayerPos) { - const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale; - const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale; - - 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.drawImage( + image, + 0, 0, image.width, image.height, + 0, 0, canvas.width, canvas.height + ); ctx.restore(); } @@ -408,12 +427,119 @@ function toggleHealth() { 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) { if (!map) return; const transformed = mapAndTransformCoordinates(pos); const mapPos = transformed.pos; - const textSize = transformed.textSize * 0.8; + const textSize = transformed.textSize; let extraOffset = 0; if (drawNames) extraOffset += 15; @@ -432,8 +558,9 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) { healthColor = "#FF0000"; } - const barWidth = 40; - const barHeight = 5; + const barWidth = Math.max(60, 40 * textSizeMultiplier); + const barHeight = Math.max(8, 5 * textSizeMultiplier); + ctx.fillStyle = "#444444"; ctx.fillRect(mapPos.x - barWidth / 2, textY, barWidth, barHeight); @@ -441,15 +568,15 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) { const healthWidth = (health / 100) * barWidth; ctx.fillRect(mapPos.x - barWidth / 2, textY, healthWidth, barHeight); - ctx.font = `${textSize}px Arial`; + ctx.font = `bold ${textSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "top"; - ctx.lineWidth = 2; + ctx.lineWidth = 3; 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.fillText(`${health}HP`, mapPos.x, textY + barHeight + 1); + ctx.fillText(`${health}HP`, mapPos.x, textY + barHeight + 2); } function drawEntities() { @@ -577,8 +704,12 @@ function drawBombTimer() { const maxWidth = 1024 - 128 - 128; 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.fillRect(128, 16, maxWidth, 16); + ctx.fillRect(128, timerY, maxWidth, timerHeight); if (radarData.bombBeingDefused) { ctx.fillStyle = radarData.bombCanDefuse ? teamColor : enemyColor; @@ -586,32 +717,32 @@ function drawBombTimer() { 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.textBaseline = "middle"; 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.lineWidth = 2; ctx.beginPath(); - ctx.moveTo(128 + (maxWidth * (5 / 40)), 16); - ctx.lineTo(128 + (maxWidth * (5 / 40)), 32); + ctx.moveTo(128 + (maxWidth * (5 / 40)), timerY); + ctx.lineTo(128 + (maxWidth * (5 / 40)), timerY + timerHeight); ctx.stroke(); ctx.beginPath(); - ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), 16); - ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), 32); + ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), timerY); + ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), timerY + timerHeight); ctx.stroke(); if (radarData.bombCanDefuse) { ctx.strokeStyle = "green"; ctx.beginPath(); - ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 16); - ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 32); + ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY); + ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY + timerHeight); ctx.stroke(); } } @@ -670,79 +801,6 @@ function mapCoordinates(coordinates) { 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) { if (!map) return; @@ -766,11 +824,11 @@ function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped) displayName += " [SCOPED]"; } - ctx.font = `${textSize}px Arial`; + ctx.font = `bold ${textSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "top"; - ctx.lineWidth = 2; + ctx.lineWidth = 3; ctx.strokeStyle = "black"; ctx.strokeText(displayName, mapPos.x, textY); ctx.fillText(displayName, mapPos.x, textY); @@ -800,11 +858,11 @@ function drawPlayerMoney(pos, playerType, money, hasBomb) { ctx.fillStyle = "#FF4500"; } - ctx.font = `${textSize}px Arial`; + ctx.font = `bold ${textSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "top"; - ctx.lineWidth = 2; + ctx.lineWidth = 3; ctx.strokeStyle = "black"; ctx.strokeText(formattedMoney, mapPos.x, textY); ctx.fillText(formattedMoney, mapPos.x, textY); @@ -827,11 +885,11 @@ function drawPlayerWeapon(pos, playerType, weaponId) { ctx.fillStyle = textColor; } - ctx.font = `${textSize}px Arial`; + ctx.font = `bold ${textSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "top"; - ctx.lineWidth = 2; + ctx.lineWidth = 3; ctx.strokeStyle = "black"; ctx.strokeText(`[${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)); ctx.fillStyle = bombColor; - ctx.font = `${textSize}px Arial`; + ctx.font = `bold ${textSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "top"; - ctx.lineWidth = 2; + ctx.lineWidth = 3; ctx.strokeStyle = "black"; ctx.strokeText("[C4]", mapPos.x, textY); ctx.fillText("[C4]", mapPos.x, textY); @@ -862,18 +920,18 @@ function drawBomb(pos, planted) { const transformed = mapAndTransformCoordinates(pos); const mapPos = transformed.pos; - const size = transformed.textSize * 0.7; + const size = minEntitySize * entitySizeMultiplier; ctx.beginPath(); ctx.arc(mapPos.x, mapPos.y, size, 0, 2 * Math.PI); ctx.fillStyle = bombColor; ctx.fill(); - ctx.lineWidth = 2; + ctx.lineWidth = 3; ctx.strokeStyle = "black"; ctx.stroke(); - ctx.font = size * 1.2 + "px Arial"; + ctx.font = `bold ${Math.max(size * 1.2, minTextSize)}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "white"; @@ -895,7 +953,8 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i const transformed = mapAndTransformCoordinates(pos); const mapPos = transformed.pos; - let circleRadius = transformed.textSize * 0.6; + + let circleRadius = minEntitySize * entitySizeMultiplier; const distance = circleRadius + 2; const radius = distance + 5; const arrowWidth = 35; @@ -918,7 +977,7 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i } if (dormant) { - ctx.font = "20px Arial"; + ctx.font = `bold ${transformed.textSize}px Arial`; ctx.textAlign = "center"; ctx.fillStyle = fillStyle; 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.strokeStyle = playerType == "Enemy" ? enemyColor : teamColor; - ctx.lineWidth = 1; + ctx.lineWidth = 2; 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() { shouldZoom = !shouldZoom; } @@ -1218,10 +1305,6 @@ function toggleRotate() { rotateMap = !rotateMap; } -function toggleCentered() { - playerCentered = !playerCentered; -} - function toggleMoneyReveal() { if (websocket && websocket.readyState === WebSocket.OPEN) { 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", () => { const savedDrawHealth = localStorage.getItem('drawHealth'); drawHealth = savedDrawHealth !== null ? savedDrawHealth === 'true' : true; + const savedDrawMoney = localStorage.getItem('drawMoney'); 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 = { "zoomCheck": false, "statsCheck": true, @@ -1278,7 +1375,8 @@ addEventListener("DOMContentLoaded", () => { "moneyDisplay": drawMoney, "moneyReveal": false, "rotateCheck": true, - "centerCheck": true + "centerCheck": true, + "healthCheck": drawHealth }; Object.entries(checkboxes).forEach(([id, state]) => { @@ -1286,12 +1384,41 @@ addEventListener("DOMContentLoaded", () => { 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'); if (canvas) { canvas.width = 1024; canvas.height = 1024; ctx = canvas.getContext('2d'); + const canvasRect = canvas.getBoundingClientRect(); + canvasScale = Math.min(canvasRect.width, canvasRect.height) / 1024; + connect(); } else { console.error("[radarflow] Canvas element not found"); diff --git a/webradar/styles.css b/webradar/styles.css index 971277c..592844d 100644 --- a/webradar/styles.css +++ b/webradar/styles.css @@ -23,6 +23,8 @@ body { canvas { width: 100%; height: 100%; + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; } #settingsHolder { @@ -47,6 +49,25 @@ canvas { background-color: rgba(25, 25, 25, 0.7); border-radius: 5px; 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 { @@ -92,31 +113,67 @@ canvas { 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), (max-height: 600px) { #settingsHolder { display: none; } + + #showMenuBtn { + display: block !important; + font-size: 16px !important; + padding: 8px 12px !important; + } } @media (max-width: 400px), (max-height: 400px) { #canvasContainer::before { - content: 'settings'; - position: fixed; - top: 10px; - left: 10px; - background-color: rgba(25, 25, 25, 0.7); - color: white; - width: 30px; - height: 30px; - border-radius: 15px; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - cursor: pointer; - z-index: 101; + content: ''; + display: none; + } + + #showMenuBtn { + padding: 6px 10px !important; + font-size: 14px !important; } } @@ -129,6 +186,7 @@ canvas { margin-left: 5px; cursor: pointer; min-width: 150px; + font-size: inherit; } #playerSelect:hover { @@ -147,19 +205,23 @@ canvas { .player-focus { margin-top: 10px; + display: flex; + align-items: center; + flex-wrap: wrap; } #hideMenuBtn { background-color: #333; color: white; border: none; - padding: 5px 10px; + padding: 8px 10px; margin-top: 10px; border-radius: 3px; cursor: pointer; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; transition: background-color 0.3s; width: 100%; + font-size: inherit; } #hideMenuBtn:hover { @@ -170,19 +232,64 @@ canvas { position: fixed; top: 10px; left: 10px; - background-color: rgba(25, 25, 25, 0.7); + background-color: rgba(25, 25, 25, 0.9); color: white; border: none; - padding: 5px 10px; + padding: 8px 12px; border-radius: 15px; - font-size: 14px; + font-size: 16px; cursor: pointer; z-index: 101; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; transition: opacity 0.3s; - opacity: 0.6; + opacity: 0.8; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); } #showMenuBtn:hover { 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); + } } \ No newline at end of file