import { createDragHandler } from "../../helpers/createDragHandler"; import { getNodeTools } from "../../helpers/getNodeTools"; import { sendPostMessage } from "../../post-message/sendPostMessage"; import { getLabelPosition } from "./helpers/getLabelPosition"; import { getTransformValues } from "./helpers/getTransformValues"; import { getZoomValue } from "./helpers/getZoomValue"; import { selectFirstViewportNode } from "./helpers/selectFirstViewportNode"; import { setViewportDragging } from "./isViewportDragging"; export const setupViewportDrag = (labelElement: SVGTextElement, viewportElement: HTMLElement, viewportName: string): (() => void) => { // Get the parent group element that contains the label const labelGroup = labelElement.parentElement as unknown as SVGGElement; // Track initial positions for calculations let initialTransform = { x: 0, y: 0 }; let initialLabelPosition = { x: 0, y: 0 }; return createDragHandler(labelElement, { onStart: () => { setViewportDragging(true); initialTransform = getTransformValues(viewportElement); initialLabelPosition = getLabelPosition(labelGroup); selectFirstViewportNode(viewportElement); }, onDrag: (_event, { deltaX, deltaY }) => { const zoom = getZoomValue(); // Adjust delta for zoom level (viewport is in canvas space) const deltaXZoomed = deltaX / zoom; const deltaYZoomed = deltaY / zoom; // Calculate new positions const newX = initialTransform.x + deltaXZoomed; const newY = initialTransform.y + deltaYZoomed; // Update label position with raw delta (labels are in screen space) const newLabelX = initialLabelPosition.x + deltaX; const newLabelY = initialLabelPosition.y + deltaY; labelGroup.setAttribute("transform", `translate(${newLabelX}, ${newLabelY})`); // Update viewport position with zoom-adjusted delta viewportElement.style.transform = `translate3d(${newX}px, ${newY}px, 0)`; }, onStop: (_event, { hasDragged }) => { setViewportDragging(false); const finalTransform = getTransformValues(viewportElement); // If it was a drag, handle drag completion if (hasDragged) { // Trigger refresh after drag completes to update highlight frame and labels const nodeTools = getNodeTools(); if (nodeTools?.refreshHighlightFrame) { nodeTools.refreshHighlightFrame(); } } // Always notify parent about the new position on drag stop sendPostMessage("viewport-position-changed", { viewportName, x: finalTransform.x, y: finalTransform.y, }); }, onCancel: () => { setViewportDragging(false); }, onPreventClick: () => {}, }); };