better edge layout

This commit is contained in:
2025-06-27 10:31:55 +02:00
parent cb86748281
commit 305004d06a
3 changed files with 96 additions and 11 deletions

View File

@@ -28,22 +28,31 @@
let srcPos: Position = $state(sourcePosition || Position.Bottom);
let tgtPos: Position = $state(targetPosition || Position.Top);
// Determine edge styling and positioning based on relationship type
// Determine edge styling and positioning based on relationship type and handles
if (edgeType === 'spouse') {
edgeColor = 'stroke: red;';
edgeLabel = spouse();
// For spouse connections, use horizontal positioning
if (sourceX < targetX) {
// Use handle-based positioning for spouses
if (sourceHandleId === 'spouse-right') {
srcPos = Position.Right;
tgtPos = Position.Left;
} else {
} else if (sourceHandleId === 'spouse-left') {
srcPos = Position.Left;
tgtPos = Position.Right;
} else {
// Fallback to position-based logic
if (sourceX < targetX) {
srcPos = Position.Right;
tgtPos = Position.Left;
} else {
srcPos = Position.Left;
tgtPos = Position.Right;
}
}
} else if (edgeType === 'child') {
edgeColor = 'stroke: blue;';
edgeLabel = child();
// Use the handles set by the layout: child handle (bottom) to parent handle (top)
// Parent-child: from parent's bottom (child handle) to child's top (parent handle)
srcPos = Position.Bottom;
tgtPos = Position.Top;
} else if (edgeType === 'parent') {
@@ -55,13 +64,22 @@
} else if (edgeType === 'sibling') {
edgeColor = 'stroke: orange;';
edgeLabel = sibling();
// For siblings, use horizontal positioning
if (sourceX < targetX) {
// Use handle-based positioning for siblings
if (sourceHandleId === 'spouse-right') {
srcPos = Position.Right;
tgtPos = Position.Left;
} else {
} else if (sourceHandleId === 'spouse-left') {
srcPos = Position.Left;
tgtPos = Position.Right;
} else {
// Fallback to position-based logic
if (sourceX < targetX) {
srcPos = Position.Right;
tgtPos = Position.Left;
} else {
srcPos = Position.Left;
tgtPos = Position.Right;
}
}
} else {
edgeColor = 'stroke: gray;';
@@ -71,13 +89,25 @@
tgtPos = targetPosition || Position.Top;
}
// Override with handle-specific positioning if handles are specified
// Explicit handle overrides (these should take precedence)
if (sourceHandleId === 'child') {
srcPos = Position.Bottom;
}
if (targetHandleId === 'parent') {
tgtPos = Position.Top;
}
if (sourceHandleId === 'spouse-left') {
srcPos = Position.Left;
}
if (sourceHandleId === 'spouse-right') {
srcPos = Position.Right;
}
if (targetHandleId === 'spouse-left') {
tgtPos = Position.Left;
}
if (targetHandleId === 'spouse-right') {
tgtPos = Position.Right;
}
let [path, labelX, labelY] = $derived(
getSmoothStepPath({

View File

@@ -26,6 +26,38 @@
class={'card card-compact flex h-40 w-40 flex-col items-center justify-center rounded-full shadow-lg' +
nodeColor}
>
<Handle
class="customHandle"
id="spouse-left"
{isValidConnection}
position={Position.Left}
isConnectable={true}
type="source"
/>
<Handle
class="customHandle"
id="spouse-right"
{isValidConnection}
position={Position.Right}
isConnectable={true}
type="source"
/>
<Handle
class="customHandle"
id="spouse-left"
{isValidConnection}
position={Position.Left}
isConnectable={true}
type="target"
/>
<Handle
class="customHandle"
id="spouse-right"
{isValidConnection}
position={Position.Right}
isConnectable={true}
type="target"
/>
<Handle
class="customHandle"
id="child"
@@ -81,7 +113,7 @@
/>
<div class="avatar mb-2" style="z-index: 2; cursor: pointer;">
<div class={"w-24 rounded-full border-0 ring-offset-1"+nodeColor}>
<div class={'w-24 rounded-full border-0 ring-offset-1' + nodeColor}>
<img
src={data.profile_picture || 'https://cdn-icons-png.flaticon.com/512/10628/10628885.png'}
alt="Picture of {data.last_name} {data.first_name}"
@@ -90,7 +122,7 @@
</div>
<div class="px-2 text-center" style="z-index: 2; cursor: pointer;">
<h2 class="text-sm leading-tight font-semibold">
<h2 class="text-sm font-semibold leading-tight">
{data.first_name}
{data.middle_name ? data.middle_name : ''}
{data.last_name}

View File

@@ -174,6 +174,7 @@ export class FamilyTree extends dagre.graphlib.Graph {
let newEdge = { ...edge };
if (String(edge.data?.type).toLowerCase() === 'child') {
// Parent to child: source (parent) uses 'child' handle (bottom), target (child) uses 'parent' handle (top)
newEdge.sourceHandle = 'child';
newEdge.targetHandle = 'parent';
} else if (String(edge.data?.type).toLowerCase() === 'parent') {
@@ -185,6 +186,28 @@ export class FamilyTree extends dagre.graphlib.Graph {
return; // Skip this duplicate spouse edge
}
processedSpouseEdges.add(spouseKey);
// Set spouse handles based on position
const sourceNode = this.node(edge.source);
const targetNode = this.node(edge.target);
if (sourceNode.x < targetNode.x) {
newEdge.sourceHandle = 'spouse-right';
newEdge.targetHandle = 'spouse-left';
} else {
newEdge.sourceHandle = 'spouse-left';
newEdge.targetHandle = 'spouse-right';
}
} else if (String(edge.data?.type).toLowerCase() === 'sibling') {
// Set sibling handles based on position
const sourceNode = this.node(edge.source);
const targetNode = this.node(edge.target);
if (sourceNode.x < targetNode.x) {
newEdge.sourceHandle = 'spouse-right';
newEdge.targetHandle = 'spouse-left';
} else {
newEdge.sourceHandle = 'spouse-left';
newEdge.targetHandle = 'spouse-right';
}
}
newEdge.hidden = false;