Skip to content

Commit

Permalink
Merge pull request #201 from boostcampwm-2024/feature-fe-#200
Browse files Browse the repository at this point in the history
가장 가까운 핸들에 연결, 노드 간 1개의 엣지만 가능하게 수정
  • Loading branch information
yewonJin authored Nov 19, 2024
2 parents 428419b + a6ce459 commit eda692a
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 12 deletions.
124 changes: 112 additions & 12 deletions apps/frontend/src/components/canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
BackgroundVariant,
ConnectionMode,
type Node,
Position,
NodeChange,
Edge,
EdgeChange,
Expand All @@ -29,6 +30,8 @@ import useYDocStore from "@/store/useYDocStore";
import { useCollaborativeCursors } from "@/hooks/useCursor";
import { CollaborativeCursors } from "../CursorView";

import { getHandlePosition } from "@/lib/getHandlePosition";

const proOptions = { hideAttribution: true };

interface CanvasProps {
Expand Down Expand Up @@ -176,6 +179,7 @@ function Flow({ className }: CanvasProps) {
(changes: NodeChange[]) => {
if (!ydoc) return;
const nodesMap = ydoc.getMap("nodes");
const edgesMap = ydoc.getMap("edges");

changes.forEach((change) => {
if (change.type === "position" && change.position) {
Expand All @@ -187,13 +191,66 @@ function Flow({ className }: CanvasProps) {
selected: false,
};
nodesMap.set(change.id, updatedNode);

edges.forEach((edge) => {
if (edge.source === change.id || edge.target === change.id) {
const sourceNode = nodes.find((n) => n.id === edge.source);
const targetNode = nodes.find((n) => n.id === edge.target);

if (sourceNode && targetNode) {
const handlePositions = [
Position.Left,
Position.Right,
Position.Top,
Position.Bottom,
];
let shortestDistance = Infinity;
let bestHandles = {
source: edge.sourceHandle,
target: edge.targetHandle,
};

handlePositions.forEach((sourceHandle) => {
handlePositions.forEach((targetHandle) => {
const sourcePosition = getHandlePosition(
sourceNode,
sourceHandle,
);
const targetPosition = getHandlePosition(
targetNode,
targetHandle,
);
const distance = Math.sqrt(
Math.pow(sourcePosition.x - targetPosition.x, 2) +
Math.pow(sourcePosition.y - targetPosition.y, 2),
);

if (distance < shortestDistance) {
shortestDistance = distance;
bestHandles = {
source: sourceHandle,
target: targetHandle,
};
}
});
});

const updatedEdge = {
...edge,
sourceHandle: bestHandles.source,
targetHandle: bestHandles.target,
};
edgesMap.set(edge.id, updatedEdge);
}
}
});
}
}
});

onNodesChange(changes);
},
[nodes, onNodesChange],
[nodes, edges, onNodesChange],
);

const handleEdgesChange = useCallback(
Expand All @@ -216,18 +273,61 @@ function Flow({ className }: CanvasProps) {
(connection: Connection) => {
if (!connection.source || !connection.target || !ydoc) return;

const newEdge: Edge = {
id: `e${connection.source}-${connection.target}`,
source: connection.source,
target: connection.target,
sourceHandle: connection.sourceHandle || undefined,
targetHandle: connection.targetHandle || undefined,
};

ydoc.getMap("edges").set(newEdge.id, newEdge);
setEdges((eds) => addEdge(connection, eds));
const isConnected = edges.some(
(edge) =>
(edge.source === connection.source &&
edge.target === connection.target) ||
(edge.source === connection.target &&
edge.target === connection.source),
);

if (isConnected) return;

const sourceNode = nodes.find((n) => n.id === connection.source);
const targetNode = nodes.find((n) => n.id === connection.target);

if (sourceNode && targetNode) {
const handlePositions = [
Position.Left,
Position.Right,
Position.Top,
Position.Bottom,
];
let shortestDistance = Infinity;
let closestHandles = {
source: connection.sourceHandle,
target: connection.targetHandle,
};

handlePositions.forEach((sourceHandle) => {
handlePositions.forEach((targetHandle) => {
const sourcePosition = getHandlePosition(sourceNode, sourceHandle);
const targetPosition = getHandlePosition(targetNode, targetHandle);
const distance = Math.sqrt(
Math.pow(sourcePosition.x - targetPosition.x, 2) +
Math.pow(sourcePosition.y - targetPosition.y, 2),
);

if (distance < shortestDistance) {
shortestDistance = distance;
closestHandles = { source: sourceHandle, target: targetHandle };
}
});
});

const newEdge: Edge = {
id: `e${connection.source}-${connection.target}`,
source: connection.source,
target: connection.target,
sourceHandle: closestHandles.source,
targetHandle: closestHandles.target,
};

ydoc.getMap("edges").set(newEdge.id, newEdge);
setEdges((eds) => addEdge(newEdge, eds));
}
},
[setEdges],
[setEdges, edges, nodes, ydoc],
);

const nodeTypes = useMemo(() => ({ note: NoteNode }), []);
Expand Down
28 changes: 28 additions & 0 deletions apps/frontend/src/lib/getHandlePosition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Position, type Node } from "@xyflow/react";
export function getHandlePosition(node: Node, handleId: Position) {
const nodeElement = document.querySelector(`[data-id="${node.id}"]`);
const nodeRect = nodeElement!.getBoundingClientRect();
const nodeWidth = nodeRect.width;
const nodeHeight = nodeRect.height;

const positions = {
[Position.Left]: {
x: node.position.x,
y: node.position.y + nodeHeight / 2,
},
[Position.Right]: {
x: node.position.x + nodeWidth,
y: node.position.y + nodeHeight / 2,
},
[Position.Top]: {
x: node.position.x + nodeWidth / 2,
y: node.position.y,
},
[Position.Bottom]: {
x: node.position.x + nodeWidth / 2,
y: node.position.y + nodeHeight,
},
};

return positions[handleId];
}

0 comments on commit eda692a

Please sign in to comment.