fix: volume slider click position using element getBoundingClientRect

- Rewrote applyVolumeAtMouse to use hitarea element's screen rect directly
- Works correctly regardless of zoom/pan level
- Made hitarea taller (18px) for easier grabbing
This commit is contained in:
joren
2026-03-30 01:22:30 +02:00
parent 91329471e2
commit 3609a50dd2

View File

@@ -236,12 +236,14 @@
function applyVolumeAtMouse(e: MouseEvent, nodeId: number) {
const nd = graphNodes.find(n => n.id === nodeId);
if (!nd || !svgEl) return;
const volX = nd.x + 8;
const volW = nd.width - 36;
const svgRect = svgEl.getBoundingClientRect();
// Convert mouse X to SVG coordinate
const mouseSvgX = viewBox.x + (e.clientX - svgRect.left) * viewBox.w / svgRect.width;
const ratio = (mouseSvgX - volX) / volW;
// Get the hitarea SVG element's screen rect directly
const hitarea = svgEl.querySelector(`.node-group[data-node-id="${nodeId}"] .vol-hitarea`);
if (!hitarea) return;
const rect = (hitarea as SVGElement).getBoundingClientRect();
// Ratio from left edge of hitarea
const ratio = (e.clientX - rect.left) / rect.width;
const clamped = Math.max(0, Math.min(1, ratio));
setNodeVolume(nodeId, clamped);
}
@@ -656,7 +658,7 @@
<!-- Volume bar fill (visual only, clamped to 1.0) -->
<rect x={nd.x + 8} y={nd.y + nd.height - 12} width={(nd.width - 36) * Math.max(0, Math.min(1, nd.volume))} height="4" rx="2" fill={nd.mute ? '#666' : '#4a9'} />
<!-- Volume click/drag hit area (tall transparent rect over the whole slider) -->
<rect class="vol-hitarea" x={nd.x + 8} y={nd.y + nd.height - 18} width={nd.width - 36} height="14" fill="transparent" />
<rect class="vol-hitarea" x={nd.x + 8} y={nd.y + nd.height - 20} width={nd.width - 36} height="18" fill="transparent" />
<!-- Volume handle circle -->
<circle class="vol-handle" cx={nd.x + 8 + (nd.width - 36) * Math.max(0, Math.min(1, nd.volume))} cy={nd.y + nd.height - 10} r="3.5" fill={nd.mute ? '#888' : '#6cb'} stroke="#fff" stroke-width="1" />
<!-- Volume % label -->