Use shortest orthogonal relation paths
This commit is contained in:
42
src/App.jsx
42
src/App.jsx
@@ -1752,41 +1752,15 @@ function RelationTreePanel({
|
|||||||
const startY = from.y + miniNodeHeight;
|
const startY = from.y + miniNodeHeight;
|
||||||
const endY = to.y;
|
const endY = to.y;
|
||||||
const midY = startY + Math.max(30, (endY - startY) / 2);
|
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 = toCenterX > fromCenterX;
|
||||||
const isRightSkipEdge = fromLevel >= 2 || toCenterX > fromCenterX;
|
const laneX = isRightSkipEdge
|
||||||
const sideSkipEdges = skipEdges.filter((item) => {
|
? from.x + miniNodeWidth + 40
|
||||||
const skipFrom = miniNodePositions[item.from.id];
|
: from.x - 40;
|
||||||
const skipTo = miniNodePositions[item.to.id];
|
const skipTargetY = to.y + miniNodeHeight / 2;
|
||||||
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 pathD = isSkipEdge
|
const pathD = isSkipEdge
|
||||||
? isRightSkipEdge
|
? isRightSkipEdge
|
||||||
? `M ${from.x + miniNodeWidth} ${from.y + miniNodeHeight / 2} H ${laneX} V ${to.y - 18} H ${toCenterX} V ${to.y - 8}`
|
? `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 ${to.y + miniNodeHeight / 2} H ${isInnermostSkipEdge ? to.x - 8 : innermostLaneX}`
|
: `M ${from.x} ${from.y + miniNodeHeight / 2} H ${laneX} V ${skipTargetY} H ${to.x + miniNodeWidth + 8}`
|
||||||
: Math.abs(fromCenterX - toCenterX) < 6
|
: Math.abs(fromCenterX - toCenterX) < 6
|
||||||
? `M ${fromCenterX} ${startY} L ${toCenterX} ${endY - 8}`
|
? `M ${fromCenterX} ${startY} L ${toCenterX} ${endY - 8}`
|
||||||
: `M ${fromCenterX} ${startY} C ${fromCenterX} ${midY}, ${toCenterX} ${midY}, ${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'}
|
strokeWidth={isSkipEdge ? '2.2' : '2'}
|
||||||
strokeDasharray={isSkipEdge ? '6 5' : undefined}
|
strokeDasharray={isSkipEdge ? '6 5' : undefined}
|
||||||
opacity={isSkipEdge ? '0.82' : '1'}
|
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)'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user