From 0126397373eb69ca8b6ffa499a76d47d0874b4c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:26:51 +0000 Subject: [PATCH 1/2] Initial plan From 6e799254a9ad444d6eb60a5165220bca57645562 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:37:27 +0000 Subject: [PATCH 2/2] Implement edge scrolling during drag operations Co-authored-by: thekingofcity <3353040+thekingofcity@users.noreply.github.com> --- src/components/svg-canvas-graph.tsx | 58 ++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/components/svg-canvas-graph.tsx b/src/components/svg-canvas-graph.tsx index 762020443..ff60df9a8 100644 --- a/src/components/svg-canvas-graph.tsx +++ b/src/components/svg-canvas-graph.tsx @@ -7,7 +7,7 @@ import { LinePathType, LineStyleType } from '../constants/lines'; import { MiscNodeType } from '../constants/nodes'; import { StationType } from '../constants/stations'; import { useRootDispatch, useRootSelector } from '../redux'; -import { saveGraph } from '../redux/param/param-slice'; +import { saveGraph, setSvgViewBoxMin } from '../redux/param/param-slice'; import { addSelected, clearSelected, @@ -154,6 +154,34 @@ const SvgCanvas = () => { e.currentTarget.setPointerCapture(e.pointerId); if (mode === 'free' && active === node) { + // Edge scrolling during drag + const edgeThreshold = 50; // pixels from edge to trigger scrolling + const scrollSpeed = 2; // pixels to scroll per frame + + let shouldScrollX = 0; + let shouldScrollY = 0; + + // Check if pointer is near canvas edges + if (x < edgeThreshold) { + shouldScrollX = -scrollSpeed; + } else if (x > width - edgeThreshold) { + shouldScrollX = scrollSpeed; + } + + if (y < edgeThreshold) { + shouldScrollY = -scrollSpeed; + } else if (y > height - edgeThreshold) { + shouldScrollY = scrollSpeed; + } + + // Apply scrolling if needed + if (shouldScrollX !== 0 || shouldScrollY !== 0) { + dispatch(setSvgViewBoxMin({ + x: svgViewBoxMin.x + (shouldScrollX * svgViewBoxZoom) / 100, + y: svgViewBoxMin.y + (shouldScrollY * svgViewBoxZoom) / 100, + })); + } + if (!e.altKey && useSnapLines) { // node start position (fromX, fromY) const fromX = graph.current.getNodeAttribute(node, 'x'); @@ -269,6 +297,34 @@ const SvgCanvas = () => { } }); } else { + // Edge scrolling during drag (legacy mode) + const edgeThreshold = 50; // pixels from edge to trigger scrolling + const scrollSpeed = 2; // pixels to scroll per frame + + let shouldScrollX = 0; + let shouldScrollY = 0; + + // Check if pointer is near canvas edges + if (x < edgeThreshold) { + shouldScrollX = -scrollSpeed; + } else if (x > width - edgeThreshold) { + shouldScrollX = scrollSpeed; + } + + if (y < edgeThreshold) { + shouldScrollY = -scrollSpeed; + } else if (y > height - edgeThreshold) { + shouldScrollY = scrollSpeed; + } + + // Apply scrolling if needed + if (shouldScrollX !== 0 || shouldScrollY !== 0) { + dispatch(setSvgViewBoxMin({ + x: svgViewBoxMin.x + (shouldScrollX * svgViewBoxZoom) / 100, + y: svgViewBoxMin.y + (shouldScrollY * svgViewBoxZoom) / 100, + })); + } + // legacy round position to nearest 5 mode setActiveSnapLines([]); setActiveSnapPoint(undefined);