import { getNodeDimensions, pickSideFromPoint, START_NODE_ID, type HandleSide, } from './strategyFlowLayout'; export type EdgeDragZone = 'source' | 'middle' | 'target'; /** 연결선 상 클릭/드래그 위치 → 좌(소스) / 중(경로) / 우(타겟) 구간 */ export function getEdgeDragZone( sourceX: number, sourceY: number, targetX: number, targetY: number, pointerX: number, pointerY: number, ): EdgeDragZone { const dx = targetX - sourceX; const dy = targetY - sourceY; const len2 = dx * dx + dy * dy; if (len2 < 4) return 'middle'; const t = ((pointerX - sourceX) * dx + (pointerY - sourceY) * dy) / len2; const clamped = Math.max(0, Math.min(1, t)); if (clamped < 1 / 3) return 'source'; if (clamped > 2 / 3) return 'target'; return 'middle'; } function sideToSourceHandle(side: HandleSide): string { return `s-${side}`; } function sideToTargetHandle(side: HandleSide): string { return `t-${side}`; } /** 드래그 위치에 맞는 소스(출발) 핸들 */ export function pickSourceHandleAtPoint( nodeId: string, flowPos: { x: number; y: number }, positions: Map, ): string { const pos = positions.get(nodeId) ?? { x: 0, y: 0 }; const dim = getNodeDimensions(nodeId); return sideToSourceHandle(pickSideFromPoint(flowPos, pos, dim)); } /** 드래그 위치에 맞는 타겟(도착) 핸들 */ export function pickTargetHandleAtPoint( nodeId: string, flowPos: { x: number; y: number }, positions: Map, ): string { const pos = positions.get(nodeId) ?? { x: 0, y: 0 }; const dim = getNodeDimensions(nodeId); return sideToTargetHandle(pickSideFromPoint(flowPos, pos, dim)); } export function buildPositionsFromNodes( nodes: { id: string; position: { x: number; y: number } }[], ): Map { const map = new Map(); for (const n of nodes) { map.set(n.id, { x: n.position.x, y: n.position.y }); } if (!map.has(START_NODE_ID)) { map.set(START_NODE_ID, { x: 0, y: 220 }); } return map; }