Spaces:
Running
Running
fix: zoom toward cursor in diagram and explore views
Browse filesPreviously 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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);
|