From 186fc0690663103a31b1e1ca4d7d9381b74e2c08 Mon Sep 17 00:00:00 2001 From: Hyein Date: Wed, 24 Jun 2026 10:49:58 +0900 Subject: [PATCH] Route later skip links to the right --- src/App.jsx | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 0d9f2f3..d654d85 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1743,22 +1743,40 @@ function RelationTreePanel({ programs, onProgramClick, onOpenRelationPopup, side 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 skipFromLevels = [...new Set(skipEdges.map((item) => levelMap[item.from.id] ?? 0))].sort((a, b) => a - b); + 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 outerLaneX = 16; - const innerLaneX = Math.max(outerLaneX + 28, leftMostNodeX - 42); + 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 ? 1 : levelIndex / (skipFromLevels.length - 1); - return outerLaneX + (innerLaneX - outerLaneX) * laneRatio; + const laneRatio = skipFromLevels.length <= 1 ? 0 : levelIndex / (skipFromLevels.length - 1); + return isRightSkipEdge + ? rightOuterLaneX + (rightInnerLaneX - rightOuterLaneX) * laneRatio + : leftOuterLaneX + (leftInnerLaneX - leftOuterLaneX) * laneRatio; }; - const skipIncoming = skipEdges.filter((item) => item.to.id === relation.to.id); + 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 = getSkipLaneX(fromLevel); + const laneX = isRightSkipEdge && fromLevel >= 2 + ? Math.min(rightOuterLaneX - 12, from.x + miniNodeWidth + 40) + : getSkipLaneX(fromLevel); const pathD = isSkipEdge - ? `M ${from.x} ${from.y + miniNodeHeight / 2} H ${laneX} V ${to.y + miniNodeHeight / 2} H ${isInnermostSkipEdge ? to.x - 8 : innermostLaneX}` + ? isRightSkipEdge + ? `M ${from.x + miniNodeWidth} ${from.y + miniNodeHeight / 2} C ${laneX} ${from.y + miniNodeHeight + 34}, ${laneX} ${to.y - 48}, ${toCenterX} ${to.y - 8}` + : `M ${from.x} ${from.y + miniNodeHeight / 2} H ${laneX} V ${to.y + miniNodeHeight / 2} H ${isInnermostSkipEdge ? to.x - 8 : innermostLaneX}` : Math.abs(fromCenterX - toCenterX) < 6 ? `M ${fromCenterX} ${startY} L ${toCenterX} ${endY - 8}` : `M ${fromCenterX} ${startY} C ${fromCenterX} ${midY}, ${toCenterX} ${midY}, ${toCenterX} ${endY - 8}`; @@ -1771,7 +1789,7 @@ function RelationTreePanel({ programs, onProgramClick, onOpenRelationPopup, side strokeWidth={isSkipEdge ? '2.2' : '2'} strokeDasharray={isSkipEdge ? '6 5' : undefined} opacity={isSkipEdge ? '0.82' : '1'} - markerEnd={isSkipEdge ? (isInnermostSkipEdge ? 'url(#sidebar-relation-arrow-skip)' : undefined) : 'url(#sidebar-relation-arrow)'} + markerEnd={isSkipEdge ? (isRightSkipEdge || isInnermostSkipEdge ? 'url(#sidebar-relation-arrow-skip)' : undefined) : 'url(#sidebar-relation-arrow)'} /> ); })}