From c0ffb4d2f1278f0d8f165b328de3a3601d22ff80 Mon Sep 17 00:00:00 2001 From: eric <3024947@stud.hs-mannheim.de> Date: Sun, 10 Aug 2025 21:44:56 +0200 Subject: [PATCH] piechart wip --- src/main/resources/public/game.html | 37 ++++++------- src/main/resources/public/js/game.js | 82 ++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 44 deletions(-) diff --git a/src/main/resources/public/game.html b/src/main/resources/public/game.html index 5bbcb54..1681340 100644 --- a/src/main/resources/public/game.html +++ b/src/main/resources/public/game.html @@ -75,13 +75,12 @@ #roundArea[hidden]{display:none} #options{ position:relative; width:100%; max-width:520px; aspect-ratio:1; margin:14px 0 6px; - border-radius:50%; border:1px dashed var(--border); - background: radial-gradient(240px 240px at 50% 50%, rgba(29,185,84,.08), transparent 60%); + border-radius:50%; } .player-option{ position:absolute; - left:50%; /* neu */ - top:50%; /* neu */ + left:50%; + top:50%; transform-origin:center; background:#0f0f0f; color:var(--text); border:1px solid var(--border); @@ -124,7 +123,7 @@ padding:10px 14px; border-radius:999px; box-shadow:var(--shadow); z-index:50; display:none} .toast.show{display:block} - /* Slide-out Drawer für Songliste (wie im Beispiel) */ + /* Slide-out Drawer */ .drawer{position:fixed; top:0; right:0; height:100%; width:340px; background:#0f0f0f; border-left:1px solid var(--border); transform:translateX(100%); transition:transform .25s ease; z-index:60; display:flex; flex-direction:column} @@ -137,6 +136,15 @@ .drawer .meta{display:flex; flex-direction:column} .drawer .meta b{font-size:13px} .drawer .meta span{font-size:12px; color:var(--muted)} + + /* === Pie-Slices === */ + #options svg.options-svg { width:100%; height:auto; display:block; border-radius:50%; } + .wedge { fill:#181818; stroke:#2a2a2a; stroke-width:2; cursor:pointer; transition:filter .15s, fill .2s; } + .wedge:hover { filter:brightness(1.08); } + .wedge.selected { fill:#1db954; } + .wedge.correct { fill:#1db954; } + .wedge.disabled { pointer-events:none; opacity:.85; } + .wedge-label { fill:#fff; font-weight:700; font-size:14px; pointer-events:none; } @@ -166,17 +174,6 @@
- - - - - - - - - - -
-
+
- + - +
- + diff --git a/src/main/resources/public/js/game.js b/src/main/resources/public/js/game.js index d5c3ee1..b5bcd12 100644 --- a/src/main/resources/public/js/game.js +++ b/src/main/resources/public/js/game.js @@ -117,6 +117,22 @@ const optionsDiv = document.getElementById("options"); const resultP = document.getElementById("result"); const scoreboard = document.getElementById("scoreboard"); +// --- SVG helpers für Pie-Slices --- +const SVGNS = "http://www.w3.org/2000/svg"; +const VB = 1000; // viewBox 0..1000 +const CX = 500, CY = 500, R = 480; + +function polar(cx, cy, r, deg){ + const rad = (deg - 90) * Math.PI/180; // 0° oben + return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) }; +} +function wedgePath(cx, cy, r, a0, a1){ + const p0 = polar(cx, cy, r, a0); + const p1 = polar(cx, cy, r, a1); + const largeArc = ((a1 - a0 + 360) % 360) > 180 ? 1 : 0; + return `M ${cx} ${cy} L ${p0.x} ${p0.y} A ${r} ${r} 0 ${largeArc} 1 ${p1.x} ${p1.y} Z`; +} + // 6) Neue Runde anzeigen async function handleRoundStart({ ownerOptions, songUri, trackInfos }) { // UI zurücksetzen @@ -138,31 +154,45 @@ async function handleRoundStart({ ownerOptions, songUri, trackInfos }) { await window.playOnSpotify(songUri, username); } - // Buttons kreisförmig verteilen - requestAnimationFrame(() => { - const optsRect = optionsDiv.getBoundingClientRect(); - const radius = Math.min(optsRect.width, optsRect.height) / 2 - 40; // Abstand zum Rand - ownerOptions.forEach((user, i) => { - const btn = document.createElement("button"); - btn.textContent = user; - btn.classList.add("player-option"); - //const angle = 360 * i / ownerOptions.length; - //btn.style.transform = `rotate(${angle}deg) translateY(-${radius}px) rotate(${-angle}deg)`; + // Optionen als Tortenstücke (SVG) rendern + const svg = document.createElementNS(SVGNS, "svg"); + svg.setAttribute("viewBox", `0 0 ${VB} ${VB}`); + svg.setAttribute("class", "options-svg"); + optionsDiv.innerHTML = ""; + optionsDiv.appendChild(svg); - const angle = (360 / ownerOptions.length) * i; - // zentrieren -> dann drehen -> nach außen schieben -> Text aufrecht drehen - btn.style.transform = `translate(-50%, -50%) rotate(${angle}deg) translate(0, -${radius}px) rotate(${-angle}deg)`; + const n = ownerOptions.length; + ownerOptions.forEach((user, i) => { + const a0 = (360 / n) * i; + const a1 = (360 / n) * (i + 1); - btn.addEventListener("click", () => { - socket.send(JSON.stringify({ - type: "guess", - username: username, - guess: user - })); - optionsDiv.querySelectorAll("button").forEach(b => b.disabled = true); - }); - optionsDiv.appendChild(btn); + const path = document.createElementNS(SVGNS, "path"); + path.setAttribute("d", wedgePath(CX, CY, R, a0, a1)); + path.setAttribute("class", "wedge"); + path.setAttribute("data-user", user); + path.addEventListener("click", () => { + socket.send(JSON.stringify({ + type: "guess", + username: username, + guess: user + })); + svg.querySelectorAll(".wedge").forEach(w => w.classList.add("disabled")); + path.classList.add("selected"); }); + + // Label mittig im Segment + const mid = (a0 + a1) / 2; + const P = polar(CX, CY, R * 0.58, mid); + const text = document.createElementNS(SVGNS, "text"); + text.setAttribute("x", P.x); + text.setAttribute("y", P.y); + text.setAttribute("class", "wedge-label"); + text.setAttribute("text-anchor", "middle"); + text.setAttribute("dominant-baseline", "middle"); + text.textContent = user; + + svg.appendChild(path); + svg.appendChild(text); }); // Start-Button ausblenden + Rundensektion einblenden @@ -210,6 +240,12 @@ function renderScoreboard(scores) { function handleRoundResult({ scores, guesses, owner }) { renderScoreboard(scores); + // korrektes Segment hervorheben + try { + document.querySelectorAll("#options .wedge").forEach(w => { + if (w.getAttribute("data-user") === owner) w.classList.add("correct"); + }); + } catch(e) {} resultP.innerHTML = ""; Object.entries(guesses).forEach(([user, guess]) => { @@ -268,5 +304,3 @@ async function playOnSpotify(trackUri, username) { } } window.playOnSpotify = playOnSpotify; - -