diff --git a/apps/app/src/lib/graph/FamilyEdge.svelte b/apps/app/src/lib/graph/FamilyEdge.svelte index 502fdc0..ea3f324 100644 --- a/apps/app/src/lib/graph/FamilyEdge.svelte +++ b/apps/app/src/lib/graph/FamilyEdge.svelte @@ -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({ diff --git a/apps/app/src/lib/graph/PersonNode.svelte b/apps/app/src/lib/graph/PersonNode.svelte index 58e5031..34bf307 100644 --- a/apps/app/src/lib/graph/PersonNode.svelte +++ b/apps/app/src/lib/graph/PersonNode.svelte @@ -26,6 +26,38 @@ class={'card card-compact flex h-40 w-40 flex-col items-center justify-center rounded-full shadow-lg' + nodeColor} > + + + +
-
+
Picture of {data.last_name} {data.first_name}
-

+

{data.first_name} {data.middle_name ? data.middle_name : ''} {data.last_name} diff --git a/apps/app/src/lib/graph/layout.ts b/apps/app/src/lib/graph/layout.ts index 7f49f02..a1496db 100644 --- a/apps/app/src/lib/graph/layout.ts +++ b/apps/app/src/lib/graph/layout.ts @@ -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;