diff --git a/geneit_app/src/routes/family/FamilyMemberTreeRoute.tsx b/geneit_app/src/routes/family/FamilyMemberTreeRoute.tsx index 6c8e8c5..687ca6a 100644 --- a/geneit_app/src/routes/family/FamilyMemberTreeRoute.tsx +++ b/geneit_app/src/routes/family/FamilyMemberTreeRoute.tsx @@ -27,9 +27,11 @@ import { BasicFamilyTree } from "../../widgets/BasicFamilyTree"; import { MemberItem } from "../../widgets/MemberItem"; import { RouterLink } from "../../widgets/RouterLink"; import { ComplexFamilyTree } from "../../widgets/complex_family_tree/ComplexFamilyTree"; +import { SimpleFamilyTree } from "../../widgets/simple_family_tree/SimpleFamilyTree"; enum CurrTab { BasicTree, + SimpleTree, AdvancedTree, } @@ -43,7 +45,7 @@ export function FamilyMemberTreeRoute(): React.ReactElement { const family = useFamily(); - const [currTab, setCurrTab] = React.useState(CurrTab.AdvancedTree); + const [currTab, setCurrTab] = React.useState(CurrTab.SimpleTree); const [currMode, setCurrMode] = React.useState(TreeMode.Descending); const member = family.members.get(Number(memberId)); @@ -146,6 +148,7 @@ export function FamilyMemberTreeRoute(): React.ReactElement { aria-label="basic tabs example" > + @@ -154,6 +157,12 @@ export function FamilyMemberTreeRoute(): React.ReactElement { {currTab === CurrTab.BasicTree ? ( + ) : currTab === CurrTab.SimpleTree ? ( + ) : ( 1) + tree.couples?.forEach( + (c) => (childrenToProcess = childrenToProcess?.concat(c.down)) + ); + else childrenToProcess = []; + + const node = { + down: + childrenToProcess?.map((c) => buildSimpleDownTreeNode(c, depth - 1)) ?? + [], + member: tree.member, + spouse: lastCouple + ? { + couple: lastCouple.couple, + member: lastCouple.member, + } + : undefined, + width: -1, + }; + + // Compute current level width + let levelWidth = + (node.spouse ? COUPLE_CARDS_WIDTH : CARD_WIDTH) + CARD_SPACING; + + // Compute down level width + const downWidth = + SIBLINGS_SPACING * node.down.length + + node.down.reduce((prev, n) => prev + n.width, 0); + + node.width = Math.max(levelWidth, downWidth); + return node; +} + +// TODO : if useless, remove and merge up and down techniques +function buildSimpleUpTreeNode( + tree: FamilyTreeNode, + depth: number +): SimpleTreeNode { + /*if (depth === 0) throw new Error("Too much recursion reached!"); + + return { + member: tree.member, + children: + depth === 1 + ? [] + : tree.down?.map((c) => buildSimpleUpTreeNode(c, depth - 1)) ?? [], + };*/ + return buildSimpleDownTreeNode(tree, depth); +} + +/** + * Simple family tree + * + * Only one couple can be shown in this version + */ + +export function SimpleFamilyTree(p: { + tree: FamilyTreeNode; + isUp: boolean; + depth: number; +}): React.ReactElement { + const tree = React.useMemo( + () => + p.isUp + ? buildSimpleUpTreeNode(p.tree, p.depth) + : buildSimpleDownTreeNode(p.tree, p.depth), + [p.tree, p.isUp, p.depth] + ); + + const height = p.depth * (CARD_HEIGHT + LEVEL_SPACING) - LEVEL_SPACING; + + console.info(`tree width=${tree.width} height=${height}`); + + return ( + + + + ); +} + +function NodeArea(p: { + x: number; + y: number; + node: SimpleTreeNode; +}): React.ReactElement { + const couple_x_offset = Math.floor( + (p.node.width - (p.node.spouse ? COUPLE_CARDS_WIDTH : CARD_WIDTH)) / 2 + ); + + return ( + <> + + + {p.node.spouse && ( + + )} + + ); +} + +function MemberCard(p: { + x: number; + y: number; + member: Member; +}): React.ReactElement { + let birthDeath = []; + if (p.member.dateOfBirth) birthDeath.push(fmtDate(p.member.dateOfBirth)); + if (p.member.dateOfDeath) birthDeath.push(fmtDate(p.member.dateOfDeath)); + + return ( + + {/* Member image */} + {p.member.hasPhoto ? ( + + ) : ( + + )} + + {/* Member text */} + + + {p.member.fullName} + + + {birthDeath.join(" - ")} + + + + ); +} + +function GenderlessIcon(p: { + width: number; + height: number; +}): React.ReactElement { + return ( + + + + + + + ); +}