From ed1dfa343b9f489a4dcbc9f8a7a4c8ecd2e55ff7 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Sat, 8 Aug 2026 16:12:42 +0200 Subject: [PATCH] Fix polygon spectrum geometry: outward edge normals and polygon-shaped progress ring --- public/app.js | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/public/app.js b/public/app.js index d3f2b54..a2e1ec6 100644 --- a/public/app.js +++ b/public/app.js @@ -441,7 +441,7 @@ return `rgba(${r}, ${g}, ${b}, ${alpha})`; } - // --- Helper: Precise Polygon Perimeter Point & Normal --- + // --- Helper: Precise Polygon Perimeter Point & Outward Normal --- function getPolygonPerimeterPoint(sides, radius, t) { if (!sides || sides < 3) { const angle = t * Math.PI * 2 - Math.PI / 2; @@ -455,8 +455,8 @@ } const totalProgress = ((t % 1) + 1) % 1; const sideProgress = totalProgress * sides; - const sideIdx = Math.floor(sideProgress); - const u = sideProgress - sideIdx; + const sideIdx = Math.floor(sideProgress) % sides; + const u = sideProgress - Math.floor(sideProgress); const angleStep = (Math.PI * 2) / sides; const a1 = -Math.PI / 2 + sideIdx * angleStep; const a2 = -Math.PI / 2 + ((sideIdx + 1) % sides) * angleStep; @@ -469,8 +469,9 @@ const dx = x2 - x1; const dy = y2 - y1; const len = Math.hypot(dx, dy) || 1; - const nx = -dy / len; - const ny = dx / len; + // Clockwise polygon outward normal: (dy, -dx) / len + const nx = dy / len; + const ny = -dx / len; return { x: px, y: py, @@ -1045,18 +1046,38 @@ } if (cfg.showProgressRing && duration > 0 && shape !== 'linear' && shape !== 'oscilloscope') { - const progressAngle = (currentTime / duration) * (Math.PI * 2); + const progress = Math.min(1, Math.max(0, currentTime / duration)); const ringW = cfg.progressRingWidth || 6; + const ringRadius = baseRadius + (cfg.borderWidth || 6) / 2 + 2; + targetCtx.save(); - targetCtx.beginPath(); - targetCtx.arc(0, 0, baseRadius + (cfg.borderWidth || 6) / 2 + 2, -Math.PI / 2, -Math.PI / 2 + progressAngle); targetCtx.lineWidth = ringW; targetCtx.strokeStyle = cfg.progressRingColor || '#00f0ff'; targetCtx.lineCap = 'round'; + targetCtx.lineJoin = 'round'; if (cfg.enableGlow) { targetCtx.shadowColor = cfg.progressRingColor || '#00f0ff'; targetCtx.shadowBlur = 10; } + + targetCtx.beginPath(); + if (polySides < 3) { + const progressAngle = progress * (Math.PI * 2); + targetCtx.arc(0, 0, ringRadius, -Math.PI / 2, -Math.PI / 2 + progressAngle); + } else { + const steps = polySides * 40; + const targetStep = Math.floor(progress * steps); + for (let s = 0; s <= targetStep; s++) { + const t = s / steps; + const pt = getPolygonPerimeterPoint(polySides, ringRadius, t); + if (s === 0) targetCtx.moveTo(pt.x, pt.y); + else targetCtx.lineTo(pt.x, pt.y); + } + if (progress > 0 && targetStep < steps) { + const ptEnd = getPolygonPerimeterPoint(polySides, ringRadius, progress); + targetCtx.lineTo(ptEnd.x, ptEnd.y); + } + } targetCtx.stroke(); targetCtx.restore(); }