@node-edit-utils/core 2.3.2 → 2.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/canvas/helpers/getCanvasContainerOrBody.d.ts +1 -0
- package/dist/lib/canvas/helpers/getCanvasWindowValue.d.ts +1 -1
- package/dist/lib/helpers/adjustForZoom.d.ts +1 -0
- package/dist/lib/helpers/createDragHandler.d.ts +69 -0
- package/dist/lib/helpers/getNodeProvider.d.ts +1 -0
- package/dist/lib/helpers/getNodeTools.d.ts +2 -0
- package/dist/lib/helpers/getViewportDimensions.d.ts +4 -0
- package/dist/lib/helpers/index.d.ts +9 -1
- package/dist/lib/helpers/parseTransform.d.ts +8 -0
- package/dist/lib/helpers/toggleClass.d.ts +1 -0
- package/dist/lib/viewport/label/helpers/selectFirstViewportNode.d.ts +5 -0
- package/dist/node-edit-utils.cjs.js +259 -235
- package/dist/node-edit-utils.esm.js +259 -235
- package/dist/node-edit-utils.umd.js +259 -235
- package/dist/node-edit-utils.umd.min.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/lib/canvas/createCanvasObserver.ts +2 -2
- package/src/lib/canvas/helpers/getCanvasContainerOrBody.ts +6 -0
- package/src/lib/canvas/helpers/getCanvasWindowValue.ts +2 -3
- package/src/lib/helpers/adjustForZoom.ts +4 -0
- package/src/lib/helpers/createDragHandler.ts +171 -0
- package/src/lib/helpers/getNodeProvider.ts +4 -0
- package/src/lib/helpers/getNodeTools.ts +6 -0
- package/src/lib/helpers/getViewportDimensions.ts +7 -0
- package/src/lib/helpers/index.ts +9 -1
- package/src/lib/helpers/parseTransform.ts +9 -0
- package/src/lib/helpers/toggleClass.ts +9 -0
- package/src/lib/node-tools/createNodeTools.ts +0 -1
- package/src/lib/node-tools/highlight/clearHighlightFrame.ts +2 -3
- package/src/lib/node-tools/highlight/createHighlightFrame.ts +5 -9
- package/src/lib/node-tools/highlight/createToolsContainer.ts +3 -6
- package/src/lib/node-tools/highlight/helpers/getElementBounds.ts +6 -5
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +2 -3
- package/src/lib/node-tools/highlight/highlightNode.ts +7 -15
- package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +12 -42
- package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.ts +2 -3
- package/src/lib/styles/styles.css +1 -1
- package/src/lib/viewport/createViewport.ts +44 -47
- package/src/lib/viewport/label/getViewportLabelsOverlay.ts +4 -5
- package/src/lib/viewport/label/helpers/getLabelPosition.ts +3 -5
- package/src/lib/viewport/label/helpers/getTransformValues.ts +3 -5
- package/src/lib/viewport/label/helpers/selectFirstViewportNode.ts +18 -0
- package/src/lib/viewport/label/refreshViewportLabels.ts +2 -2
- package/src/lib/viewport/label/setupViewportLabelDrag.ts +58 -86
- package/src/lib/window/bindToWindow.ts +1 -2
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCanvasContainerOrBody } from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
2
2
|
import { getCanvasWindowValue } from "@/lib/canvas/helpers/getCanvasWindowValue";
|
|
3
|
+
import { getViewportDimensions } from "@/lib/helpers/getViewportDimensions";
|
|
4
|
+
import { toggleClass } from "@/lib/helpers/toggleClass";
|
|
3
5
|
import { isComponentInstance } from "../select/helpers/isComponentInstance";
|
|
4
6
|
import { getHighlightFrameElement } from "./helpers/getHighlightFrameElement";
|
|
5
7
|
import { getScreenBounds } from "./helpers/getScreenBounds";
|
|
@@ -22,24 +24,15 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
22
24
|
|
|
23
25
|
// Update SVG dimensions to match current viewport (handles window resize and ensures coordinate system is correct)
|
|
24
26
|
// Use clientWidth/Height to match getBoundingClientRect() coordinate system (excludes scrollbars)
|
|
25
|
-
const viewportWidth
|
|
26
|
-
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
27
|
+
const { width: viewportWidth, height: viewportHeight } = getViewportDimensions();
|
|
27
28
|
frame.setAttribute("width", viewportWidth.toString());
|
|
28
29
|
frame.setAttribute("height", viewportHeight.toString());
|
|
29
30
|
|
|
30
31
|
// Update instance class
|
|
31
|
-
|
|
32
|
-
frame.classList.add("is-instance");
|
|
33
|
-
} else {
|
|
34
|
-
frame.classList.remove("is-instance");
|
|
35
|
-
}
|
|
32
|
+
toggleClass(frame, "is-instance", isInstance);
|
|
36
33
|
|
|
37
34
|
// Update text edit class
|
|
38
|
-
|
|
39
|
-
frame.classList.add("is-text-edit");
|
|
40
|
-
} else {
|
|
41
|
-
frame.classList.remove("is-text-edit");
|
|
42
|
-
}
|
|
35
|
+
toggleClass(frame, "is-text-edit", isTextEdit);
|
|
43
36
|
|
|
44
37
|
const group = frame.querySelector(".highlight-frame-group") as SVGGElement | null;
|
|
45
38
|
if (!group) return;
|
|
@@ -56,12 +49,11 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
56
49
|
rect.removeAttribute("stroke"); // Use CSS default
|
|
57
50
|
}
|
|
58
51
|
|
|
59
|
-
const
|
|
60
|
-
const container = canvasContainer || document.body;
|
|
52
|
+
const container = getCanvasContainerOrBody();
|
|
61
53
|
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper") as HTMLElement | null;
|
|
62
54
|
const nodeTools = toolsWrapper?.querySelector(".node-tools") as HTMLElement | null;
|
|
63
55
|
|
|
64
|
-
const zoom = getCanvasWindowValue(["zoom", "current"], canvasName) ?? 1;
|
|
56
|
+
const zoom = (getCanvasWindowValue(["zoom", "current"], canvasName) as number | undefined) ?? 1;
|
|
65
57
|
const bounds = getScreenBounds(node);
|
|
66
58
|
|
|
67
59
|
// Calculate all values before any DOM writes
|
|
@@ -71,32 +63,10 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
71
63
|
const bottomY = top + height;
|
|
72
64
|
|
|
73
65
|
// Update instance classes on tools wrapper and node tools
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
toolsWrapper.classList.remove("is-instance");
|
|
79
|
-
}
|
|
80
|
-
// Update text edit class
|
|
81
|
-
if (isTextEdit) {
|
|
82
|
-
toolsWrapper.classList.add("is-text-edit");
|
|
83
|
-
} else {
|
|
84
|
-
toolsWrapper.classList.remove("is-text-edit");
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (nodeTools) {
|
|
88
|
-
if (isInstance) {
|
|
89
|
-
nodeTools.classList.add("is-instance");
|
|
90
|
-
} else {
|
|
91
|
-
nodeTools.classList.remove("is-instance");
|
|
92
|
-
}
|
|
93
|
-
// Update text edit class
|
|
94
|
-
if (isTextEdit) {
|
|
95
|
-
nodeTools.classList.add("is-text-edit");
|
|
96
|
-
} else {
|
|
97
|
-
nodeTools.classList.remove("is-text-edit");
|
|
98
|
-
}
|
|
99
|
-
}
|
|
66
|
+
toggleClass(toolsWrapper, "is-instance", isInstance);
|
|
67
|
+
toggleClass(toolsWrapper, "is-text-edit", isTextEdit);
|
|
68
|
+
toggleClass(nodeTools, "is-instance", isInstance);
|
|
69
|
+
toggleClass(nodeTools, "is-text-edit", isTextEdit);
|
|
100
70
|
|
|
101
71
|
// Batch all DOM writes (single paint pass)
|
|
102
72
|
// Update group transform to move entire group (rect + handles) at once
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCanvasContainerOrBody } from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
2
2
|
import { getHighlightFrameElement } from "./helpers/getHighlightFrameElement";
|
|
3
3
|
|
|
4
4
|
export const updateHighlightFrameVisibility = (node: HTMLElement): void => {
|
|
@@ -12,8 +12,7 @@ export const updateHighlightFrameVisibility = (node: HTMLElement): void => {
|
|
|
12
12
|
// Batch DOM writes
|
|
13
13
|
frame.style.display = displayValue;
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
const container = canvasContainer || document.body;
|
|
15
|
+
const container = getCanvasContainerOrBody();
|
|
17
16
|
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper") as HTMLElement | null;
|
|
18
17
|
if (toolsWrapper) {
|
|
19
18
|
toolsWrapper.style.display = displayValue;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { getCanvasContainer } from "../canvas/helpers/getCanvasContainer";
|
|
2
|
+
import { createDragHandler } from "../helpers/createDragHandler";
|
|
3
|
+
import { getNodeProvider } from "../helpers/getNodeProvider";
|
|
4
|
+
import { getNodeTools } from "../helpers/getNodeTools";
|
|
2
5
|
import { refreshHighlightFrame } from "../node-tools/highlight/refreshHighlightFrame";
|
|
3
6
|
import { DEFAULT_WIDTH } from "./constants";
|
|
4
|
-
import { setupEventListener } from "./events/setupEventListener";
|
|
5
7
|
import { refreshViewportLabels } from "./label/refreshViewportLabels";
|
|
6
8
|
import { createResizeHandle } from "./resize/createResizeHandle";
|
|
7
9
|
import { createResizePresets } from "./resize/createResizePresets";
|
|
@@ -14,6 +16,7 @@ export const createViewport = (container: HTMLElement, initialWidth?: number): V
|
|
|
14
16
|
|
|
15
17
|
// Remove any existing resize handle to prevent duplicates
|
|
16
18
|
const existingHandle = container.querySelector(".resize-handle");
|
|
19
|
+
|
|
17
20
|
if (existingHandle) {
|
|
18
21
|
existingHandle.remove();
|
|
19
22
|
}
|
|
@@ -24,59 +27,55 @@ export const createViewport = (container: HTMLElement, initialWidth?: number): V
|
|
|
24
27
|
|
|
25
28
|
createResizePresets(resizeHandle, container, updateWidth);
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
let startX
|
|
29
|
-
let startWidth
|
|
30
|
-
|
|
31
|
-
const startResize = (event: MouseEvent): void => {
|
|
32
|
-
event.preventDefault();
|
|
33
|
-
event.stopPropagation();
|
|
34
|
-
|
|
35
|
-
isDragging = true;
|
|
36
|
-
startX = event.clientX;
|
|
37
|
-
startWidth = container.offsetWidth;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const handleResize = (event: MouseEvent): void => {
|
|
41
|
-
if (!isDragging) return;
|
|
42
|
-
|
|
43
|
-
if (canvas) {
|
|
44
|
-
canvas.style.cursor = "ew-resize";
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const width = calcWidth(event, startX, startWidth);
|
|
48
|
-
updateWidth(container, width);
|
|
49
|
-
};
|
|
30
|
+
// Track initial values for resize calculation
|
|
31
|
+
let startX = 0;
|
|
32
|
+
let startWidth = 0;
|
|
50
33
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
34
|
+
// Handle mouse leave for resize (specific to resize use case)
|
|
35
|
+
const handleMouseLeave = (event: MouseEvent): void => {
|
|
36
|
+
// Check if mouse is leaving the window/document
|
|
37
|
+
if (!event.relatedTarget && (event.target === document || event.target === document.documentElement)) {
|
|
38
|
+
if (canvas) {
|
|
39
|
+
canvas.style.cursor = "default";
|
|
40
|
+
}
|
|
57
41
|
}
|
|
58
|
-
|
|
59
|
-
isDragging = false;
|
|
60
42
|
};
|
|
61
43
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
const removeDragListeners = createDragHandler(resizeHandle, {
|
|
45
|
+
onStart: (_event, { startX: dragStartX }) => {
|
|
46
|
+
startX = dragStartX;
|
|
47
|
+
startWidth = container.offsetWidth;
|
|
48
|
+
},
|
|
49
|
+
onDrag: (event) => {
|
|
50
|
+
if (canvas) {
|
|
51
|
+
canvas.style.cursor = "ew-resize";
|
|
52
|
+
}
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
const width = calcWidth(event, startX, startWidth);
|
|
55
|
+
updateWidth(container, width);
|
|
56
|
+
},
|
|
57
|
+
onStop: () => {
|
|
58
|
+
if (canvas) {
|
|
59
|
+
canvas.style.cursor = "default";
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
onCancel: () => {
|
|
63
|
+
if (canvas) {
|
|
64
|
+
canvas.style.cursor = "default";
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
onPreventClick: () => {},
|
|
68
|
+
});
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
document.addEventListener("mouseleave", handleMouseLeave);
|
|
71
71
|
|
|
72
|
-
// Refresh viewport labels when viewport is created
|
|
73
72
|
refreshViewportLabels();
|
|
74
73
|
|
|
75
74
|
const cleanup = (): void => {
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
removeDragListeners();
|
|
76
|
+
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
78
77
|
resizeHandle.remove();
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
refreshViewportLabels();
|
|
81
80
|
};
|
|
82
81
|
|
|
@@ -85,11 +84,9 @@ export const createViewport = (container: HTMLElement, initialWidth?: number): V
|
|
|
85
84
|
updateWidth(container, width);
|
|
86
85
|
refreshViewportLabels();
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
90
|
-
const nodeTools = (window as any).nodeTools;
|
|
87
|
+
const nodeTools = getNodeTools();
|
|
91
88
|
const selectedNode = nodeTools?.getSelectedNode?.();
|
|
92
|
-
const nodeProvider =
|
|
89
|
+
const nodeProvider = getNodeProvider();
|
|
93
90
|
|
|
94
91
|
if (selectedNode && nodeProvider) {
|
|
95
92
|
refreshHighlightFrame(selectedNode, nodeProvider);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCanvasContainerOrBody } from "../../canvas/helpers/getCanvasContainerOrBody";
|
|
2
|
+
import { getViewportDimensions } from "../../helpers/getViewportDimensions";
|
|
2
3
|
|
|
3
4
|
export const getViewportLabelsOverlay = (): SVGSVGElement => {
|
|
4
|
-
const
|
|
5
|
-
const container = canvasContainer || document.body;
|
|
5
|
+
const container = getCanvasContainerOrBody();
|
|
6
6
|
|
|
7
7
|
// Check if overlay already exists
|
|
8
8
|
let overlay = container.querySelector(".viewport-labels-overlay") as SVGSVGElement | null;
|
|
@@ -21,8 +21,7 @@ export const getViewportLabelsOverlay = (): SVGSVGElement => {
|
|
|
21
21
|
overlay.style.pointerEvents = "none";
|
|
22
22
|
overlay.style.zIndex = "500";
|
|
23
23
|
|
|
24
|
-
const viewportWidth
|
|
25
|
-
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
24
|
+
const { width: viewportWidth, height: viewportHeight } = getViewportDimensions();
|
|
26
25
|
overlay.setAttribute("width", viewportWidth.toString());
|
|
27
26
|
overlay.setAttribute("height", viewportHeight.toString());
|
|
28
27
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import { parseTransform2d } from "../../../helpers/parseTransform";
|
|
2
|
+
|
|
1
3
|
export const getLabelPosition = (labelGroup: SVGGElement): { x: number; y: number } => {
|
|
2
4
|
const transform = labelGroup.getAttribute("transform");
|
|
3
|
-
|
|
4
|
-
if (match) {
|
|
5
|
-
return { x: parseFloat(match[1]), y: parseFloat(match[2]) };
|
|
6
|
-
}
|
|
7
|
-
return { x: 0, y: 0 };
|
|
5
|
+
return parseTransform2d(transform);
|
|
8
6
|
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import { parseTransform3d } from "../../../helpers/parseTransform";
|
|
2
|
+
|
|
1
3
|
export const getTransformValues = (element: HTMLElement): { x: number; y: number } => {
|
|
2
4
|
const style = element.style.transform;
|
|
3
|
-
|
|
4
|
-
if (match) {
|
|
5
|
-
return { x: parseFloat(match[1]), y: parseFloat(match[2]) };
|
|
6
|
-
}
|
|
7
|
-
return { x: 0, y: 0 };
|
|
5
|
+
return parseTransform3d(style);
|
|
8
6
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getNodeTools } from "../../../helpers/getNodeTools";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Selects the first child node inside a viewport element.
|
|
5
|
+
* Skips the resize-handle element if present.
|
|
6
|
+
*/
|
|
7
|
+
export const selectFirstViewportNode = (viewportElement: HTMLElement): void => {
|
|
8
|
+
const firstChild = Array.from(viewportElement.children).find((child) => !child.classList.contains("resize-handle")) as
|
|
9
|
+
| HTMLElement
|
|
10
|
+
| undefined;
|
|
11
|
+
|
|
12
|
+
if (firstChild) {
|
|
13
|
+
const nodeTools = getNodeTools();
|
|
14
|
+
if (nodeTools?.selectNode) {
|
|
15
|
+
nodeTools.selectNode(firstChild);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getViewportDimensions } from "../../helpers/getViewportDimensions";
|
|
1
2
|
import { getScreenBounds } from "../../node-tools/highlight/helpers/getScreenBounds";
|
|
2
3
|
import { getViewportLabelsOverlay } from "./getViewportLabelsOverlay";
|
|
3
4
|
import { isViewportLabelDragging } from "./isViewportLabelDragging";
|
|
@@ -15,8 +16,7 @@ export const refreshViewportLabels = (): void => {
|
|
|
15
16
|
const overlay = getViewportLabelsOverlay();
|
|
16
17
|
|
|
17
18
|
// Update SVG dimensions to match current viewport
|
|
18
|
-
const viewportWidth
|
|
19
|
-
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
19
|
+
const { width: viewportWidth, height: viewportHeight } = getViewportDimensions();
|
|
20
20
|
overlay.setAttribute("width", viewportWidth.toString());
|
|
21
21
|
overlay.setAttribute("height", viewportHeight.toString());
|
|
22
22
|
|
|
@@ -1,98 +1,70 @@
|
|
|
1
|
+
import { createDragHandler } from "../../helpers/createDragHandler";
|
|
2
|
+
import { getNodeTools } from "../../helpers/getNodeTools";
|
|
1
3
|
import { sendPostMessage } from "../../post-message/sendPostMessage";
|
|
2
4
|
import { getLabelPosition } from "./helpers/getLabelPosition";
|
|
3
5
|
import { getTransformValues } from "./helpers/getTransformValues";
|
|
4
6
|
import { getZoomValue } from "./helpers/getZoomValue";
|
|
7
|
+
import { selectFirstViewportNode } from "./helpers/selectFirstViewportNode";
|
|
5
8
|
import { setViewportLabelDragging } from "./isViewportLabelDragging";
|
|
6
9
|
|
|
7
10
|
export const setupViewportLabelDrag = (labelElement: SVGTextElement, viewportElement: HTMLElement, viewportName: string): (() => void) => {
|
|
8
|
-
let isDragging = false;
|
|
9
|
-
let startX = 0;
|
|
10
|
-
let startY = 0;
|
|
11
|
-
let initialTransform = { x: 0, y: 0 };
|
|
12
|
-
let initialLabelPosition = { x: 0, y: 0 };
|
|
13
|
-
|
|
14
11
|
// Get the parent group element that contains the label
|
|
15
12
|
const labelGroup = labelElement.parentElement as unknown as SVGGElement;
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
isDragging = true;
|
|
22
|
-
setViewportLabelDragging(true);
|
|
23
|
-
startX = event.clientX;
|
|
24
|
-
startY = event.clientY;
|
|
25
|
-
initialTransform = getTransformValues(viewportElement);
|
|
26
|
-
initialLabelPosition = getLabelPosition(labelGroup);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const handleDrag = (event: MouseEvent): void => {
|
|
30
|
-
if (!isDragging) return;
|
|
31
|
-
|
|
32
|
-
const zoom = getZoomValue();
|
|
33
|
-
|
|
34
|
-
// Calculate mouse delta
|
|
35
|
-
const rawDeltaX = event.clientX - startX;
|
|
36
|
-
const rawDeltaY = event.clientY - startY;
|
|
37
|
-
|
|
38
|
-
// Adjust delta for zoom level
|
|
39
|
-
const deltaX = rawDeltaX / zoom;
|
|
40
|
-
const deltaY = rawDeltaY / zoom;
|
|
41
|
-
|
|
42
|
-
const newX = initialTransform.x + deltaX;
|
|
43
|
-
const newY = initialTransform.y + deltaY;
|
|
44
|
-
|
|
45
|
-
// Update label position with raw delta (labels are in screen space)
|
|
46
|
-
const newLabelX = initialLabelPosition.x + rawDeltaX;
|
|
47
|
-
const newLabelY = initialLabelPosition.y + rawDeltaY;
|
|
48
|
-
labelGroup.setAttribute("transform", `translate(${newLabelX}, ${newLabelY})`);
|
|
49
|
-
|
|
50
|
-
// Update viewport position with zoom-adjusted delta
|
|
51
|
-
viewportElement.style.transform = `translate3d(${newX}px, ${newY}px, 0)`;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const stopDrag = (event: MouseEvent): void => {
|
|
55
|
-
if (!isDragging) return;
|
|
56
|
-
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
event.stopPropagation();
|
|
59
|
-
|
|
60
|
-
isDragging = false;
|
|
61
|
-
setViewportLabelDragging(false);
|
|
62
|
-
|
|
63
|
-
const finalTransform = getTransformValues(viewportElement);
|
|
64
|
-
|
|
65
|
-
// Trigger refresh after drag completes to update highlight frame and labels
|
|
66
|
-
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
67
|
-
const nodeTools = (window as any).nodeTools;
|
|
68
|
-
if (nodeTools?.refreshHighlightFrame) {
|
|
69
|
-
nodeTools.refreshHighlightFrame();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Notify parent about the new position
|
|
73
|
-
sendPostMessage("viewport-position-changed", {
|
|
74
|
-
viewportName,
|
|
75
|
-
x: finalTransform.x,
|
|
76
|
-
y: finalTransform.y,
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const cancelDrag = (): void => {
|
|
81
|
-
isDragging = false;
|
|
82
|
-
setViewportLabelDragging(false);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// Attach event listeners
|
|
86
|
-
labelElement.addEventListener("mousedown", startDrag);
|
|
87
|
-
document.addEventListener("mousemove", handleDrag);
|
|
88
|
-
document.addEventListener("mouseup", stopDrag);
|
|
89
|
-
window.addEventListener("blur", cancelDrag);
|
|
14
|
+
// Track initial positions for calculations
|
|
15
|
+
let initialTransform = { x: 0, y: 0 };
|
|
16
|
+
let initialLabelPosition = { x: 0, y: 0 };
|
|
90
17
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
18
|
+
return createDragHandler(labelElement, {
|
|
19
|
+
onStart: () => {
|
|
20
|
+
setViewportLabelDragging(true);
|
|
21
|
+
initialTransform = getTransformValues(viewportElement);
|
|
22
|
+
initialLabelPosition = getLabelPosition(labelGroup);
|
|
23
|
+
selectFirstViewportNode(viewportElement);
|
|
24
|
+
},
|
|
25
|
+
onDrag: (_event, { deltaX, deltaY }) => {
|
|
26
|
+
const zoom = getZoomValue();
|
|
27
|
+
|
|
28
|
+
// Adjust delta for zoom level (viewport is in canvas space)
|
|
29
|
+
const deltaXZoomed = deltaX / zoom;
|
|
30
|
+
const deltaYZoomed = deltaY / zoom;
|
|
31
|
+
|
|
32
|
+
// Calculate new positions
|
|
33
|
+
const newX = initialTransform.x + deltaXZoomed;
|
|
34
|
+
const newY = initialTransform.y + deltaYZoomed;
|
|
35
|
+
|
|
36
|
+
// Update label position with raw delta (labels are in screen space)
|
|
37
|
+
const newLabelX = initialLabelPosition.x + deltaX;
|
|
38
|
+
const newLabelY = initialLabelPosition.y + deltaY;
|
|
39
|
+
labelGroup.setAttribute("transform", `translate(${newLabelX}, ${newLabelY})`);
|
|
40
|
+
|
|
41
|
+
// Update viewport position with zoom-adjusted delta
|
|
42
|
+
viewportElement.style.transform = `translate3d(${newX}px, ${newY}px, 0)`;
|
|
43
|
+
},
|
|
44
|
+
onStop: (_event, { hasDragged }) => {
|
|
45
|
+
setViewportLabelDragging(false);
|
|
46
|
+
|
|
47
|
+
// If it was a drag, handle drag completion
|
|
48
|
+
if (hasDragged) {
|
|
49
|
+
const finalTransform = getTransformValues(viewportElement);
|
|
50
|
+
|
|
51
|
+
// Trigger refresh after drag completes to update highlight frame and labels
|
|
52
|
+
const nodeTools = getNodeTools();
|
|
53
|
+
if (nodeTools?.refreshHighlightFrame) {
|
|
54
|
+
nodeTools.refreshHighlightFrame();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Notify parent about the new position
|
|
58
|
+
sendPostMessage("viewport-position-changed", {
|
|
59
|
+
viewportName,
|
|
60
|
+
x: finalTransform.x,
|
|
61
|
+
y: finalTransform.y,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
onCancel: () => {
|
|
66
|
+
setViewportLabelDragging(false);
|
|
67
|
+
},
|
|
68
|
+
onPreventClick: () => {},
|
|
69
|
+
});
|
|
98
70
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export const bindToWindow = <T>(key: string, value: T): void => {
|
|
2
2
|
if (typeof window !== "undefined") {
|
|
3
|
-
|
|
4
|
-
(window as any)[key] = value;
|
|
3
|
+
(window as unknown as Record<string, unknown>)[key] = value;
|
|
5
4
|
}
|
|
6
5
|
};
|