From d9b8c2ae741abeacab3143a3caf02946930527df Mon Sep 17 00:00:00 2001 From: Hyein Date: Wed, 24 Jun 2026 11:04:26 +0900 Subject: [PATCH] Use shortest orthogonal relation paths --- src/App.jsx | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 766e300..09536fc 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1752,41 +1752,15 @@ function RelationTreePanel({ const startY = from.y + miniNodeHeight; const endY = to.y; const midY = startY + Math.max(30, (endY - startY) / 2); - const skipEdges = relations.filter((item) => (levelMap[item.to.id] ?? 0) - (levelMap[item.from.id] ?? 0) > 1); - const isRightSkipEdge = fromLevel >= 2 || toCenterX > fromCenterX; - const sideSkipEdges = skipEdges.filter((item) => { - const skipFrom = miniNodePositions[item.from.id]; - const skipTo = miniNodePositions[item.to.id]; - if (!skipFrom || !skipTo) return false; - const skipFromCenterX = skipFrom.x + miniNodeWidth / 2; - const skipToCenterX = skipTo.x + miniNodeWidth / 2; - return (skipToCenterX > skipFromCenterX) === isRightSkipEdge; - }); - const skipFromLevels = [...new Set(sideSkipEdges.map((item) => levelMap[item.from.id] ?? 0))].sort((a, b) => a - b); - const leftMostNodeX = Math.min(...Object.values(miniNodePositions).map((position) => position.x)); - const rightMostNodeX = Math.max(...Object.values(miniNodePositions).map((position) => position.x + miniNodeWidth)); - const leftOuterLaneX = 16; - const leftInnerLaneX = Math.max(leftOuterLaneX + 28, leftMostNodeX - 42); - const rightOuterLaneX = miniGraphWidth - 16; - const rightInnerLaneX = Math.min(rightOuterLaneX - 28, rightMostNodeX + 42); - const getSkipLaneX = (level) => { - const levelIndex = Math.max(0, skipFromLevels.indexOf(level)); - const laneRatio = skipFromLevels.length <= 1 ? 0 : levelIndex / (skipFromLevels.length - 1); - return isRightSkipEdge - ? rightOuterLaneX + (rightInnerLaneX - rightOuterLaneX) * laneRatio - : leftOuterLaneX + (leftInnerLaneX - leftOuterLaneX) * laneRatio; - }; - const skipIncoming = sideSkipEdges.filter((item) => item.to.id === relation.to.id); - const innermostSkipLevel = Math.max(...skipIncoming.map((item) => levelMap[item.from.id] ?? 0)); - const isInnermostSkipEdge = fromLevel === innermostSkipLevel; - const innermostLaneX = getSkipLaneX(innermostSkipLevel); - const laneX = isRightSkipEdge && fromLevel >= 2 - ? Math.min(rightOuterLaneX - 12, from.x + miniNodeWidth + 40) - : getSkipLaneX(fromLevel); + const isRightSkipEdge = toCenterX > fromCenterX; + const laneX = isRightSkipEdge + ? from.x + miniNodeWidth + 40 + : from.x - 40; + const skipTargetY = to.y + miniNodeHeight / 2; const pathD = isSkipEdge ? isRightSkipEdge - ? `M ${from.x + miniNodeWidth} ${from.y + miniNodeHeight / 2} H ${laneX} V ${to.y - 18} H ${toCenterX} V ${to.y - 8}` - : `M ${from.x} ${from.y + miniNodeHeight / 2} H ${laneX} V ${to.y + miniNodeHeight / 2} H ${isInnermostSkipEdge ? to.x - 8 : innermostLaneX}` + ? `M ${from.x + miniNodeWidth} ${from.y + miniNodeHeight / 2} H ${laneX} V ${skipTargetY} H ${to.x - 8}` + : `M ${from.x} ${from.y + miniNodeHeight / 2} H ${laneX} V ${skipTargetY} H ${to.x + miniNodeWidth + 8}` : Math.abs(fromCenterX - toCenterX) < 6 ? `M ${fromCenterX} ${startY} L ${toCenterX} ${endY - 8}` : `M ${fromCenterX} ${startY} C ${fromCenterX} ${midY}, ${toCenterX} ${midY}, ${toCenterX} ${endY - 8}`; @@ -1799,7 +1773,7 @@ function RelationTreePanel({ strokeWidth={isSkipEdge ? '2.2' : '2'} strokeDasharray={isSkipEdge ? '6 5' : undefined} opacity={isSkipEdge ? '0.82' : '1'} - markerEnd={isSkipEdge ? (isRightSkipEdge || isInnermostSkipEdge ? 'url(#sidebar-relation-arrow-skip)' : undefined) : 'url(#sidebar-relation-arrow)'} + markerEnd={isSkipEdge ? 'url(#sidebar-relation-arrow-skip)' : 'url(#sidebar-relation-arrow)'} /> ); })}