diff --git a/frontend/src/GraphView.jsx b/frontend/src/GraphView.jsx index 18a765f..f7170c1 100644 --- a/frontend/src/GraphView.jsx +++ b/frontend/src/GraphView.jsx @@ -74,8 +74,9 @@ function GraphView({ servers, connections }) { useEffect(() => { const svg = d3.select(svgRef.current); const g = d3.select(gRef.current); - const width = svgRef.current?.clientWidth || 900; - const height = svgRef.current?.clientHeight || 600; + const vb = svgRef.current?.viewBox?.baseVal; + const width = (vb && vb.width) ? vb.width : (svgRef.current?.clientWidth || 900); + const height = (vb && vb.height) ? vb.height : (svgRef.current?.clientHeight || 600); zoomRef.current = d3 .zoom() .scaleExtent([0.3, 3]) @@ -95,7 +96,18 @@ function GraphView({ servers, connections }) { event.preventDefault(); const delta = Math.sign(event.deltaY); const factor = delta > 0 ? 1 / 1.2 : 1.2; - zoomBy(factor); + const svgEl = svgRef.current; + const center = d3.pointer(event, svgEl); + const svgSel = d3.select(svgEl); + svgSel.interrupt(); + svgSel + .transition() + .duration(220) + .call(zoomRef.current.scaleBy, factor, center) + .on('end', () => { + const nt = d3.zoomTransform(svgEl); + dbg('zoomBy end', { next: { k: nt.k, x: nt.x, y: nt.y } }); + }); }, { passive: false }); }, []); @@ -103,8 +115,9 @@ function GraphView({ servers, connections }) { const zoomBy = (factor) => { if (!zoomRef.current || !svgRef.current) return; const svgEl = svgRef.current; - const cx = svgEl.clientWidth / 2; - const cy = svgEl.clientHeight / 2; + const vb = svgEl.viewBox?.baseVal; + const cx = (vb && vb.width) ? vb.width / 2 : svgEl.clientWidth / 2; + const cy = (vb && vb.height) ? vb.height / 2 : svgEl.clientHeight / 2; const current = d3.zoomTransform(svgEl); dbg('zoomBy click', { factor, current: { k: current.k, x: current.x, y: current.y }, center: { cx, cy } }); const svgSel = d3.select(svgEl);