umanggarg Claude Sonnet 4.6 commited on
Commit
ba23b72
·
1 Parent(s): a6aaf1e

fix: zoom toward cursor in diagram and explore views

Browse files

Previously the canvas always scaled from origin (0,0), so zooming
drifted toward the top-left. Now the canvas point under the mouse
pointer stays pinned during zoom using the standard translate-adjust
formula: newTx = mx - (mx - tx) * (newScale / oldScale).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

ui/src/components/ExploreView.jsx CHANGED
@@ -293,9 +293,15 @@ export default function ExploreView({ repo, onAskAbout, onRegenerateRef }) {
293
  if (!el) return;
294
  function onWheel(e) {
295
  e.preventDefault();
296
- // Same proportional zoom as GraphDiagram — see comment there.
297
  const f = Math.exp(-e.deltaY * 0.001);
298
- setXform(t => ({ ...t, scale: Math.min(Math.max(t.scale * f, 0.3), 3) }));
 
 
 
 
 
 
 
299
  }
300
  el.addEventListener("wheel", onWheel, { passive: false });
301
  return () => el.removeEventListener("wheel", onWheel);
 
293
  if (!el) return;
294
  function onWheel(e) {
295
  e.preventDefault();
 
296
  const f = Math.exp(-e.deltaY * 0.001);
297
+ const rect = el.getBoundingClientRect();
298
+ const mx = e.clientX - rect.left;
299
+ const my = e.clientY - rect.top;
300
+ setXform(t => {
301
+ const newScale = Math.min(Math.max(t.scale * f, 0.3), 3);
302
+ const ratio = newScale / t.scale;
303
+ return { x: mx - (mx - t.x) * ratio, y: my - (my - t.y) * ratio, scale: newScale };
304
+ });
305
  }
306
  el.addEventListener("wheel", onWheel, { passive: false });
307
  return () => el.removeEventListener("wheel", onWheel);
ui/src/components/GraphDiagram.jsx CHANGED
@@ -286,12 +286,19 @@ export default function GraphDiagram({ data, onNodeSelect, onEdgeSelect, onAskAb
286
  if (!el) return;
287
  function onWheel(e) {
288
  e.preventDefault();
289
- // Proportional zoom: scale factor grows with deltaY magnitude so a light
290
- // trackpad flick (~3px) changes scale by ~0.3% while one mouse-wheel click
291
- // (~100px) changes it by ~9%. Binary factors (0.9 / 1.11) fire the same
292
- // large jump even for the tiniest scroll event, which feels too sensitive.
293
  const f = Math.exp(-e.deltaY * 0.001);
294
- setXform(t => ({ ...t, scale: Math.min(Math.max(t.scale * f, 0.2), 2.5) }));
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
  el.addEventListener("wheel", onWheel, { passive: false });
297
  return () => el.removeEventListener("wheel", onWheel);
 
286
  if (!el) return;
287
  function onWheel(e) {
288
  e.preventDefault();
 
 
 
 
289
  const f = Math.exp(-e.deltaY * 0.001);
290
+ const rect = el.getBoundingClientRect();
291
+ // Mouse position relative to the wrapper element
292
+ const mx = e.clientX - rect.left;
293
+ const my = e.clientY - rect.top;
294
+ setXform(t => {
295
+ const newScale = Math.min(Math.max(t.scale * f, 0.2), 2.5);
296
+ // Pin the canvas point under the cursor: the canvas coord under the mouse is
297
+ // (mx - tx) / scale. After scaling, translate so that same coord maps back
298
+ // to mx: newTx = mx - canvasX * newScale = mx - (mx - tx) * (newScale / scale)
299
+ const ratio = newScale / t.scale;
300
+ return { x: mx - (mx - t.x) * ratio, y: my - (my - t.y) * ratio, scale: newScale };
301
+ });
302
  }
303
  el.addEventListener("wheel", onWheel, { passive: false });
304
  return () => el.removeEventListener("wheel", onWheel);