@almadar/ui 5.58.0 → 5.60.0
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/avl/index.cjs +153 -23
- package/dist/avl/index.js +153 -23
- package/dist/components/core/molecules/GraphCanvas.d.ts +6 -0
- package/dist/components/index.cjs +153 -23
- package/dist/components/index.js +153 -23
- package/dist/providers/index.cjs +153 -23
- package/dist/providers/index.js +153 -23
- package/dist/runtime/index.cjs +153 -23
- package/dist/runtime/index.js +153 -23
- package/package.json +1 -1
|
@@ -38389,6 +38389,12 @@ function getGroupColor(group, groups) {
|
|
|
38389
38389
|
const idx = groups.indexOf(group);
|
|
38390
38390
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
38391
38391
|
}
|
|
38392
|
+
function resolveColor2(color, el) {
|
|
38393
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
38394
|
+
if (!m) return color;
|
|
38395
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
38396
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
38397
|
+
}
|
|
38392
38398
|
var GROUP_COLORS2; exports.GraphCanvas = void 0;
|
|
38393
38399
|
var init_GraphCanvas = __esm({
|
|
38394
38400
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -38419,6 +38425,9 @@ var init_GraphCanvas = __esm({
|
|
|
38419
38425
|
actions,
|
|
38420
38426
|
onNodeClick,
|
|
38421
38427
|
nodeClickEvent,
|
|
38428
|
+
selectedNodeId,
|
|
38429
|
+
repulsion = 800,
|
|
38430
|
+
linkDistance = 100,
|
|
38422
38431
|
layout = "force",
|
|
38423
38432
|
entity,
|
|
38424
38433
|
isLoading = false,
|
|
@@ -38434,6 +38443,37 @@ var init_GraphCanvas = __esm({
|
|
|
38434
38443
|
const [hoveredNode, setHoveredNode] = React76.useState(null);
|
|
38435
38444
|
const nodesRef = React76.useRef([]);
|
|
38436
38445
|
const [, forceUpdate] = React76.useState(0);
|
|
38446
|
+
const interactionRef = React76.useRef({
|
|
38447
|
+
mode: "none",
|
|
38448
|
+
dragNodeId: null,
|
|
38449
|
+
startMouse: { x: 0, y: 0 },
|
|
38450
|
+
startOffset: { x: 0, y: 0 },
|
|
38451
|
+
downPos: { x: 0, y: 0 }
|
|
38452
|
+
});
|
|
38453
|
+
const toCoords = React76.useCallback(
|
|
38454
|
+
(e) => {
|
|
38455
|
+
const canvas = canvasRef.current;
|
|
38456
|
+
if (!canvas) return null;
|
|
38457
|
+
const rect = canvas.getBoundingClientRect();
|
|
38458
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
38459
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
38460
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
38461
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
38462
|
+
return {
|
|
38463
|
+
screenX,
|
|
38464
|
+
screenY,
|
|
38465
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38466
|
+
graphY: (screenY - offset.y) / zoom
|
|
38467
|
+
};
|
|
38468
|
+
},
|
|
38469
|
+
[offset, zoom]
|
|
38470
|
+
);
|
|
38471
|
+
const nodeAt = React76.useCallback((graphX, graphY) => {
|
|
38472
|
+
return nodesRef.current.find((n) => {
|
|
38473
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38474
|
+
return dist < (n.size || 8) + 4;
|
|
38475
|
+
});
|
|
38476
|
+
}, []);
|
|
38437
38477
|
const handleAction = React76.useCallback(
|
|
38438
38478
|
(action) => {
|
|
38439
38479
|
if (action.event) {
|
|
@@ -38499,7 +38539,7 @@ var init_GraphCanvas = __esm({
|
|
|
38499
38539
|
const dx = nodes[j].x - nodes[i].x;
|
|
38500
38540
|
const dy = nodes[j].y - nodes[i].y;
|
|
38501
38541
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38502
|
-
const force =
|
|
38542
|
+
const force = repulsion / (dist * dist);
|
|
38503
38543
|
const fx = dx / dist * force;
|
|
38504
38544
|
const fy = dy / dist * force;
|
|
38505
38545
|
nodes[i].fx -= fx;
|
|
@@ -38515,7 +38555,7 @@ var init_GraphCanvas = __esm({
|
|
|
38515
38555
|
const dx = target.x - source.x;
|
|
38516
38556
|
const dy = target.y - source.y;
|
|
38517
38557
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38518
|
-
const force = (dist -
|
|
38558
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38519
38559
|
const fx = dx / dist * force;
|
|
38520
38560
|
const fy = dy / dist * force;
|
|
38521
38561
|
source.fx += fx;
|
|
@@ -38549,7 +38589,7 @@ var init_GraphCanvas = __esm({
|
|
|
38549
38589
|
return () => {
|
|
38550
38590
|
cancelAnimationFrame(animRef.current);
|
|
38551
38591
|
};
|
|
38552
|
-
}, [propNodes, propEdges, layout]);
|
|
38592
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38553
38593
|
React76.useEffect(() => {
|
|
38554
38594
|
const canvas = canvasRef.current;
|
|
38555
38595
|
if (!canvas) return;
|
|
@@ -38558,6 +38598,7 @@ var init_GraphCanvas = __esm({
|
|
|
38558
38598
|
const w = canvas.width;
|
|
38559
38599
|
const h = canvas.height;
|
|
38560
38600
|
const nodes = nodesRef.current;
|
|
38601
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
38561
38602
|
ctx.clearRect(0, 0, w, h);
|
|
38562
38603
|
ctx.save();
|
|
38563
38604
|
ctx.translate(offset.x, offset.y);
|
|
@@ -38583,20 +38624,27 @@ var init_GraphCanvas = __esm({
|
|
|
38583
38624
|
}
|
|
38584
38625
|
for (const node of nodes) {
|
|
38585
38626
|
const size = node.size || 8;
|
|
38586
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
38627
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
38587
38628
|
const isHovered = hoveredNode === node.id;
|
|
38629
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38630
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38588
38631
|
ctx.beginPath();
|
|
38589
|
-
ctx.arc(node.x, node.y,
|
|
38632
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38590
38633
|
ctx.fillStyle = color;
|
|
38591
38634
|
ctx.fill();
|
|
38592
|
-
|
|
38593
|
-
|
|
38635
|
+
if (isSelected) {
|
|
38636
|
+
ctx.strokeStyle = accentColor;
|
|
38637
|
+
ctx.lineWidth = 3;
|
|
38638
|
+
} else {
|
|
38639
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38640
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38641
|
+
}
|
|
38594
38642
|
ctx.stroke();
|
|
38595
38643
|
if (showLabels && node.label) {
|
|
38596
38644
|
ctx.fillStyle = "#666666";
|
|
38597
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38645
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38598
38646
|
ctx.textAlign = "center";
|
|
38599
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38647
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38600
38648
|
}
|
|
38601
38649
|
}
|
|
38602
38650
|
ctx.restore();
|
|
@@ -38607,6 +38655,97 @@ var init_GraphCanvas = __esm({
|
|
|
38607
38655
|
setZoom(1);
|
|
38608
38656
|
setOffset({ x: 0, y: 0 });
|
|
38609
38657
|
}, []);
|
|
38658
|
+
const handleWheel = React76.useCallback(
|
|
38659
|
+
(e) => {
|
|
38660
|
+
if (!interactive) return;
|
|
38661
|
+
e.preventDefault();
|
|
38662
|
+
const coords = toCoords(e);
|
|
38663
|
+
if (!coords) return;
|
|
38664
|
+
const oldZoom = zoom;
|
|
38665
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38666
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38667
|
+
if (newZoom === oldZoom) return;
|
|
38668
|
+
setOffset((o) => ({
|
|
38669
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38670
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38671
|
+
}));
|
|
38672
|
+
setZoom(newZoom);
|
|
38673
|
+
},
|
|
38674
|
+
[interactive, toCoords, zoom]
|
|
38675
|
+
);
|
|
38676
|
+
const handleMouseDown = React76.useCallback(
|
|
38677
|
+
(e) => {
|
|
38678
|
+
const coords = toCoords(e);
|
|
38679
|
+
if (!coords) return;
|
|
38680
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38681
|
+
const state = interactionRef.current;
|
|
38682
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38683
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38684
|
+
state.startOffset = { ...offset };
|
|
38685
|
+
if (draggable && node) {
|
|
38686
|
+
state.mode = "dragging";
|
|
38687
|
+
state.dragNodeId = node.id;
|
|
38688
|
+
} else if (interactive) {
|
|
38689
|
+
state.mode = "panning";
|
|
38690
|
+
state.dragNodeId = null;
|
|
38691
|
+
} else {
|
|
38692
|
+
state.mode = "none";
|
|
38693
|
+
state.dragNodeId = null;
|
|
38694
|
+
}
|
|
38695
|
+
},
|
|
38696
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38697
|
+
);
|
|
38698
|
+
const handleMouseMove = React76.useCallback(
|
|
38699
|
+
(e) => {
|
|
38700
|
+
const state = interactionRef.current;
|
|
38701
|
+
if (state.mode === "panning") {
|
|
38702
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38703
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38704
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38705
|
+
return;
|
|
38706
|
+
}
|
|
38707
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38708
|
+
const coords2 = toCoords(e);
|
|
38709
|
+
if (!coords2) return;
|
|
38710
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38711
|
+
if (node2) {
|
|
38712
|
+
node2.x = coords2.graphX;
|
|
38713
|
+
node2.y = coords2.graphY;
|
|
38714
|
+
node2.vx = 0;
|
|
38715
|
+
node2.vy = 0;
|
|
38716
|
+
forceUpdate((n) => n + 1);
|
|
38717
|
+
}
|
|
38718
|
+
return;
|
|
38719
|
+
}
|
|
38720
|
+
const coords = toCoords(e);
|
|
38721
|
+
if (!coords) return;
|
|
38722
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38723
|
+
setHoveredNode(node?.id ?? null);
|
|
38724
|
+
},
|
|
38725
|
+
[toCoords, nodeAt]
|
|
38726
|
+
);
|
|
38727
|
+
const handleMouseUp = React76.useCallback(
|
|
38728
|
+
(e) => {
|
|
38729
|
+
const state = interactionRef.current;
|
|
38730
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38731
|
+
state.mode = "none";
|
|
38732
|
+
state.dragNodeId = null;
|
|
38733
|
+
if (moved < 4) {
|
|
38734
|
+
const coords = toCoords(e);
|
|
38735
|
+
if (!coords) return;
|
|
38736
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38737
|
+
if (node) {
|
|
38738
|
+
handleNodeClick(node);
|
|
38739
|
+
}
|
|
38740
|
+
}
|
|
38741
|
+
},
|
|
38742
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38743
|
+
);
|
|
38744
|
+
const handleMouseLeave = React76.useCallback(() => {
|
|
38745
|
+
interactionRef.current.mode = "none";
|
|
38746
|
+
interactionRef.current.dragNodeId = null;
|
|
38747
|
+
setHoveredNode(null);
|
|
38748
|
+
}, []);
|
|
38610
38749
|
if (isLoading) {
|
|
38611
38750
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.LoadingState, { message: t("common.loading"), className });
|
|
38612
38751
|
}
|
|
@@ -38668,20 +38807,11 @@ var init_GraphCanvas = __esm({
|
|
|
38668
38807
|
height,
|
|
38669
38808
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38670
38809
|
style: { height },
|
|
38671
|
-
|
|
38672
|
-
|
|
38673
|
-
|
|
38674
|
-
|
|
38675
|
-
|
|
38676
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38677
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38678
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38679
|
-
return dist < (n.size || 8) + 4;
|
|
38680
|
-
});
|
|
38681
|
-
if (clickedNode) {
|
|
38682
|
-
handleNodeClick(clickedNode);
|
|
38683
|
-
}
|
|
38684
|
-
}
|
|
38810
|
+
onWheel: handleWheel,
|
|
38811
|
+
onMouseDown: handleMouseDown,
|
|
38812
|
+
onMouseMove: handleMouseMove,
|
|
38813
|
+
onMouseUp: handleMouseUp,
|
|
38814
|
+
onMouseLeave: handleMouseLeave
|
|
38685
38815
|
}
|
|
38686
38816
|
) }),
|
|
38687
38817
|
groups.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
package/dist/components/index.js
CHANGED
|
@@ -38343,6 +38343,12 @@ function getGroupColor(group, groups) {
|
|
|
38343
38343
|
const idx = groups.indexOf(group);
|
|
38344
38344
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
38345
38345
|
}
|
|
38346
|
+
function resolveColor2(color, el) {
|
|
38347
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
38348
|
+
if (!m) return color;
|
|
38349
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
38350
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
38351
|
+
}
|
|
38346
38352
|
var GROUP_COLORS2, GraphCanvas;
|
|
38347
38353
|
var init_GraphCanvas = __esm({
|
|
38348
38354
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -38373,6 +38379,9 @@ var init_GraphCanvas = __esm({
|
|
|
38373
38379
|
actions,
|
|
38374
38380
|
onNodeClick,
|
|
38375
38381
|
nodeClickEvent,
|
|
38382
|
+
selectedNodeId,
|
|
38383
|
+
repulsion = 800,
|
|
38384
|
+
linkDistance = 100,
|
|
38376
38385
|
layout = "force",
|
|
38377
38386
|
entity,
|
|
38378
38387
|
isLoading = false,
|
|
@@ -38388,6 +38397,37 @@ var init_GraphCanvas = __esm({
|
|
|
38388
38397
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
38389
38398
|
const nodesRef = useRef([]);
|
|
38390
38399
|
const [, forceUpdate] = useState(0);
|
|
38400
|
+
const interactionRef = useRef({
|
|
38401
|
+
mode: "none",
|
|
38402
|
+
dragNodeId: null,
|
|
38403
|
+
startMouse: { x: 0, y: 0 },
|
|
38404
|
+
startOffset: { x: 0, y: 0 },
|
|
38405
|
+
downPos: { x: 0, y: 0 }
|
|
38406
|
+
});
|
|
38407
|
+
const toCoords = useCallback(
|
|
38408
|
+
(e) => {
|
|
38409
|
+
const canvas = canvasRef.current;
|
|
38410
|
+
if (!canvas) return null;
|
|
38411
|
+
const rect = canvas.getBoundingClientRect();
|
|
38412
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
38413
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
38414
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
38415
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
38416
|
+
return {
|
|
38417
|
+
screenX,
|
|
38418
|
+
screenY,
|
|
38419
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38420
|
+
graphY: (screenY - offset.y) / zoom
|
|
38421
|
+
};
|
|
38422
|
+
},
|
|
38423
|
+
[offset, zoom]
|
|
38424
|
+
);
|
|
38425
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
38426
|
+
return nodesRef.current.find((n) => {
|
|
38427
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38428
|
+
return dist < (n.size || 8) + 4;
|
|
38429
|
+
});
|
|
38430
|
+
}, []);
|
|
38391
38431
|
const handleAction = useCallback(
|
|
38392
38432
|
(action) => {
|
|
38393
38433
|
if (action.event) {
|
|
@@ -38453,7 +38493,7 @@ var init_GraphCanvas = __esm({
|
|
|
38453
38493
|
const dx = nodes[j].x - nodes[i].x;
|
|
38454
38494
|
const dy = nodes[j].y - nodes[i].y;
|
|
38455
38495
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38456
|
-
const force =
|
|
38496
|
+
const force = repulsion / (dist * dist);
|
|
38457
38497
|
const fx = dx / dist * force;
|
|
38458
38498
|
const fy = dy / dist * force;
|
|
38459
38499
|
nodes[i].fx -= fx;
|
|
@@ -38469,7 +38509,7 @@ var init_GraphCanvas = __esm({
|
|
|
38469
38509
|
const dx = target.x - source.x;
|
|
38470
38510
|
const dy = target.y - source.y;
|
|
38471
38511
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38472
|
-
const force = (dist -
|
|
38512
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38473
38513
|
const fx = dx / dist * force;
|
|
38474
38514
|
const fy = dy / dist * force;
|
|
38475
38515
|
source.fx += fx;
|
|
@@ -38503,7 +38543,7 @@ var init_GraphCanvas = __esm({
|
|
|
38503
38543
|
return () => {
|
|
38504
38544
|
cancelAnimationFrame(animRef.current);
|
|
38505
38545
|
};
|
|
38506
|
-
}, [propNodes, propEdges, layout]);
|
|
38546
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38507
38547
|
useEffect(() => {
|
|
38508
38548
|
const canvas = canvasRef.current;
|
|
38509
38549
|
if (!canvas) return;
|
|
@@ -38512,6 +38552,7 @@ var init_GraphCanvas = __esm({
|
|
|
38512
38552
|
const w = canvas.width;
|
|
38513
38553
|
const h = canvas.height;
|
|
38514
38554
|
const nodes = nodesRef.current;
|
|
38555
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
38515
38556
|
ctx.clearRect(0, 0, w, h);
|
|
38516
38557
|
ctx.save();
|
|
38517
38558
|
ctx.translate(offset.x, offset.y);
|
|
@@ -38537,20 +38578,27 @@ var init_GraphCanvas = __esm({
|
|
|
38537
38578
|
}
|
|
38538
38579
|
for (const node of nodes) {
|
|
38539
38580
|
const size = node.size || 8;
|
|
38540
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
38581
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
38541
38582
|
const isHovered = hoveredNode === node.id;
|
|
38583
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38584
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38542
38585
|
ctx.beginPath();
|
|
38543
|
-
ctx.arc(node.x, node.y,
|
|
38586
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38544
38587
|
ctx.fillStyle = color;
|
|
38545
38588
|
ctx.fill();
|
|
38546
|
-
|
|
38547
|
-
|
|
38589
|
+
if (isSelected) {
|
|
38590
|
+
ctx.strokeStyle = accentColor;
|
|
38591
|
+
ctx.lineWidth = 3;
|
|
38592
|
+
} else {
|
|
38593
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38594
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38595
|
+
}
|
|
38548
38596
|
ctx.stroke();
|
|
38549
38597
|
if (showLabels && node.label) {
|
|
38550
38598
|
ctx.fillStyle = "#666666";
|
|
38551
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38599
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38552
38600
|
ctx.textAlign = "center";
|
|
38553
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38601
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38554
38602
|
}
|
|
38555
38603
|
}
|
|
38556
38604
|
ctx.restore();
|
|
@@ -38561,6 +38609,97 @@ var init_GraphCanvas = __esm({
|
|
|
38561
38609
|
setZoom(1);
|
|
38562
38610
|
setOffset({ x: 0, y: 0 });
|
|
38563
38611
|
}, []);
|
|
38612
|
+
const handleWheel = useCallback(
|
|
38613
|
+
(e) => {
|
|
38614
|
+
if (!interactive) return;
|
|
38615
|
+
e.preventDefault();
|
|
38616
|
+
const coords = toCoords(e);
|
|
38617
|
+
if (!coords) return;
|
|
38618
|
+
const oldZoom = zoom;
|
|
38619
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38620
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38621
|
+
if (newZoom === oldZoom) return;
|
|
38622
|
+
setOffset((o) => ({
|
|
38623
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38624
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38625
|
+
}));
|
|
38626
|
+
setZoom(newZoom);
|
|
38627
|
+
},
|
|
38628
|
+
[interactive, toCoords, zoom]
|
|
38629
|
+
);
|
|
38630
|
+
const handleMouseDown = useCallback(
|
|
38631
|
+
(e) => {
|
|
38632
|
+
const coords = toCoords(e);
|
|
38633
|
+
if (!coords) return;
|
|
38634
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38635
|
+
const state = interactionRef.current;
|
|
38636
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38637
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38638
|
+
state.startOffset = { ...offset };
|
|
38639
|
+
if (draggable && node) {
|
|
38640
|
+
state.mode = "dragging";
|
|
38641
|
+
state.dragNodeId = node.id;
|
|
38642
|
+
} else if (interactive) {
|
|
38643
|
+
state.mode = "panning";
|
|
38644
|
+
state.dragNodeId = null;
|
|
38645
|
+
} else {
|
|
38646
|
+
state.mode = "none";
|
|
38647
|
+
state.dragNodeId = null;
|
|
38648
|
+
}
|
|
38649
|
+
},
|
|
38650
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38651
|
+
);
|
|
38652
|
+
const handleMouseMove = useCallback(
|
|
38653
|
+
(e) => {
|
|
38654
|
+
const state = interactionRef.current;
|
|
38655
|
+
if (state.mode === "panning") {
|
|
38656
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38657
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38658
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38659
|
+
return;
|
|
38660
|
+
}
|
|
38661
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38662
|
+
const coords2 = toCoords(e);
|
|
38663
|
+
if (!coords2) return;
|
|
38664
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38665
|
+
if (node2) {
|
|
38666
|
+
node2.x = coords2.graphX;
|
|
38667
|
+
node2.y = coords2.graphY;
|
|
38668
|
+
node2.vx = 0;
|
|
38669
|
+
node2.vy = 0;
|
|
38670
|
+
forceUpdate((n) => n + 1);
|
|
38671
|
+
}
|
|
38672
|
+
return;
|
|
38673
|
+
}
|
|
38674
|
+
const coords = toCoords(e);
|
|
38675
|
+
if (!coords) return;
|
|
38676
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38677
|
+
setHoveredNode(node?.id ?? null);
|
|
38678
|
+
},
|
|
38679
|
+
[toCoords, nodeAt]
|
|
38680
|
+
);
|
|
38681
|
+
const handleMouseUp = useCallback(
|
|
38682
|
+
(e) => {
|
|
38683
|
+
const state = interactionRef.current;
|
|
38684
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38685
|
+
state.mode = "none";
|
|
38686
|
+
state.dragNodeId = null;
|
|
38687
|
+
if (moved < 4) {
|
|
38688
|
+
const coords = toCoords(e);
|
|
38689
|
+
if (!coords) return;
|
|
38690
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38691
|
+
if (node) {
|
|
38692
|
+
handleNodeClick(node);
|
|
38693
|
+
}
|
|
38694
|
+
}
|
|
38695
|
+
},
|
|
38696
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38697
|
+
);
|
|
38698
|
+
const handleMouseLeave = useCallback(() => {
|
|
38699
|
+
interactionRef.current.mode = "none";
|
|
38700
|
+
interactionRef.current.dragNodeId = null;
|
|
38701
|
+
setHoveredNode(null);
|
|
38702
|
+
}, []);
|
|
38564
38703
|
if (isLoading) {
|
|
38565
38704
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
38566
38705
|
}
|
|
@@ -38622,20 +38761,11 @@ var init_GraphCanvas = __esm({
|
|
|
38622
38761
|
height,
|
|
38623
38762
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38624
38763
|
style: { height },
|
|
38625
|
-
|
|
38626
|
-
|
|
38627
|
-
|
|
38628
|
-
|
|
38629
|
-
|
|
38630
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38631
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38632
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38633
|
-
return dist < (n.size || 8) + 4;
|
|
38634
|
-
});
|
|
38635
|
-
if (clickedNode) {
|
|
38636
|
-
handleNodeClick(clickedNode);
|
|
38637
|
-
}
|
|
38638
|
-
}
|
|
38764
|
+
onWheel: handleWheel,
|
|
38765
|
+
onMouseDown: handleMouseDown,
|
|
38766
|
+
onMouseMove: handleMouseMove,
|
|
38767
|
+
onMouseUp: handleMouseUp,
|
|
38768
|
+
onMouseLeave: handleMouseLeave
|
|
38639
38769
|
}
|
|
38640
38770
|
) }),
|
|
38641
38771
|
groups.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|