Use shortest orthogonal relation paths

This commit is contained in:
2026-06-24 11:04:26 +09:00
parent 0a72256c2c
commit d9b8c2ae74

View File

@@ -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)'}
/>
);
})}