diff --git a/geneit_app/src/widgets/simple_family_tree/SimpleFamilyTree.tsx b/geneit_app/src/widgets/simple_family_tree/SimpleFamilyTree.tsx index ecf6540..88e7eac 100644 --- a/geneit_app/src/widgets/simple_family_tree/SimpleFamilyTree.tsx +++ b/geneit_app/src/widgets/simple_family_tree/SimpleFamilyTree.tsx @@ -26,13 +26,28 @@ interface SimpleTreeNode { member: Member; spouse?: SimpleTreeSpouseInfo; down: SimpleTreeNode[]; + + /** + * The width of the parent and its children + */ width: number; + + /** + * The width of the parents + */ + parentWidth: number; + + /** + * The sum of the width of the children + */ + childrenWidth: number; } /** * Get the width of a member card */ -function memberCardWidth(m: Member): number { +function memberCardWidth(m?: Member): number { + if (!m) return 0; const nameWidth = getTextWidth(m.fullName, NAME_FONT); const birthDeathWidth = getTextWidth(m.displayBirthDeath, BIRTH_FONT); return Math.max(FACE_WIDTH, nameWidth, birthDeathWidth); @@ -58,7 +73,7 @@ function buildSimpleDownTreeNode( ); else childrenToProcess = []; - const node = { + const node: SimpleTreeNode = { down: childrenToProcess?.map((c) => buildSimpleDownTreeNode(c, depth - 1)) ?? [], @@ -69,20 +84,33 @@ function buildSimpleDownTreeNode( member: lastCouple.member, } : undefined, + parentWidth: -1, + childrenWidth: -1, width: -1, }; // Compute current level width - let levelWidth = - memberCardWidth(node.member) + - (node.spouse ? SPOUSE_SPACING + memberCardWidth(node.spouse.member) : 0) + - CARD_SPACING; + let levelWidth: number; + if (node.spouse) { + levelWidth = + CARD_SPACING + + SPOUSE_SPACING + + 2 * + Math.max( + memberCardWidth(node.member), + memberCardWidth(node.spouse.member) + ); + } else { + levelWidth = memberCardWidth(node.member) + CARD_SPACING; + } // Compute down level width const downWidth = SIBLINGS_SPACING * node.down.length + node.down.reduce((prev, n) => prev + n.width, 0); + node.parentWidth = levelWidth; + node.childrenWidth = downWidth; node.width = Math.max(levelWidth, downWidth); return node; } @@ -141,18 +169,12 @@ function NodeArea(p: { childrenLinkDestY?: number; node: SimpleTreeNode; }): React.ReactElement { - const parent_x_offset = - p.x + - Math.floor( - (p.node.width - - (memberCardWidth(p.node.member) + - (p.node.spouse - ? SPOUSE_SPACING + memberCardWidth(p.node.spouse.member) - : 0))) / - 2 - ); + let parent_x_offset: number; - let downXOffset = p.x; + parent_x_offset = p.x + center(p.node.width, p.node.parentWidth); + + let unusedChildrenWidth = p.node.width - p.node.childrenWidth; + let downXOffset = p.x + Math.floor(unusedChildrenWidth / 2); let endFirstFaceX = parent_x_offset + @@ -160,7 +182,9 @@ function NodeArea(p: { FACE_WIDTH; let beginingOfSecondCardX = - parent_x_offset + memberCardWidth(p.node.member) + SPOUSE_SPACING; + parent_x_offset + + p.node.parentWidth - + memberCardWidth(p.node.spouse?.member); let beginSecondFaceX = p.node.spouse &&