diff --git a/modules/rflows/components/folk-flows-app.ts b/modules/rflows/components/folk-flows-app.ts index 442f202..54210d3 100644 --- a/modules/rflows/components/folk-flows-app.ts +++ b/modules/rflows/components/folk-flows-app.ts @@ -682,18 +682,26 @@ class FolkFlowsApp extends HTMLElement { const svg = this.shadow.getElementById("flow-canvas"); if (!svg) return; - // Wheel zoom + // Wheel: pan (default) or zoom (Ctrl/pinch) + // Trackpad two-finger scroll → pan; trackpad pinch / Ctrl+scroll → zoom svg.addEventListener("wheel", (e: WheelEvent) => { e.preventDefault(); - const delta = e.deltaY > 0 ? 0.9 : 1.1; - const rect = svg.getBoundingClientRect(); - const mx = e.clientX - rect.left; - const my = e.clientY - rect.top; - const newZoom = Math.max(0.1, Math.min(4, this.canvasZoom * delta)); - // Zoom toward pointer - this.canvasPanX = mx - (mx - this.canvasPanX) * (newZoom / this.canvasZoom); - this.canvasPanY = my - (my - this.canvasPanY) * (newZoom / this.canvasZoom); - this.canvasZoom = newZoom; + if (e.ctrlKey || e.metaKey) { + // Zoom — ctrlKey is set by trackpad pinch gestures and Ctrl+scroll + const zoomFactor = 1 - e.deltaY * 0.003; + const rect = svg.getBoundingClientRect(); + const mx = e.clientX - rect.left; + const my = e.clientY - rect.top; + const newZoom = Math.max(0.1, Math.min(4, this.canvasZoom * zoomFactor)); + // Zoom toward pointer + this.canvasPanX = mx - (mx - this.canvasPanX) * (newZoom / this.canvasZoom); + this.canvasPanY = my - (my - this.canvasPanY) * (newZoom / this.canvasZoom); + this.canvasZoom = newZoom; + } else { + // Pan — two-finger trackpad scroll or mouse wheel + this.canvasPanX -= e.deltaX; + this.canvasPanY -= e.deltaY; + } this.updateCanvasTransform(); }, { passive: false });