Can customize shown depth
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@ -13,6 +13,7 @@ import { MemberPhoto } from "./MemberPhoto";
|
||||
|
||||
export function BasicFamilyTree(p: {
|
||||
tree: FamilyTreeNode;
|
||||
depth: number;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<TreeView
|
||||
@ -20,12 +21,15 @@ export function BasicFamilyTree(p: {
|
||||
defaultExpandIcon={<ChevronRightIcon />}
|
||||
sx={{ flexGrow: 1 }}
|
||||
>
|
||||
<FamilyTreeItem n={p.tree} />
|
||||
<FamilyTreeItem n={p.tree} depth={p.depth} />
|
||||
</TreeView>
|
||||
);
|
||||
}
|
||||
|
||||
function FamilyTreeItem(p: { n: FamilyTreeNode }): React.ReactElement {
|
||||
function FamilyTreeItem(p: {
|
||||
depth: number;
|
||||
n: FamilyTreeNode;
|
||||
}): React.ReactElement {
|
||||
let children = p.n.down ?? [];
|
||||
|
||||
if (p.n.couples) {
|
||||
@ -55,9 +59,10 @@ function FamilyTreeItem(p: { n: FamilyTreeNode }): React.ReactElement {
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children.map((c) => (
|
||||
<FamilyTreeItem key={c.member.id} n={c} />
|
||||
))}
|
||||
{p.depth >= 2 &&
|
||||
children.map((c) => (
|
||||
<FamilyTreeItem depth={p.depth - 1} key={c.member.id} n={c} />
|
||||
))}
|
||||
</TreeItem>
|
||||
);
|
||||
}
|
||||
|
@ -9,13 +9,19 @@ import "svg2pdf.js";
|
||||
import { Couple } from "../../api/CoupleApi";
|
||||
import { Member, fmtDate } from "../../api/MemberApi";
|
||||
import { useDarkTheme } from "../../hooks/context_providers/DarkThemeProvider";
|
||||
import { FamilyTreeNode } from "../../utils/family_tree";
|
||||
import {
|
||||
FamilyTreeNode,
|
||||
getAvailableMembers,
|
||||
treeHeight,
|
||||
treeWidth,
|
||||
} from "../../utils/family_tree";
|
||||
import { downloadBlob } from "../../utils/files_utils";
|
||||
import "./family-chart.css";
|
||||
|
||||
export function ComplexFamilyTree(p: {
|
||||
tree: FamilyTreeNode;
|
||||
isUp: boolean;
|
||||
depth: number;
|
||||
}): React.ReactElement {
|
||||
const darkTheme = useDarkTheme();
|
||||
|
||||
@ -23,7 +29,7 @@ export function ComplexFamilyTree(p: {
|
||||
if (!container) return;
|
||||
|
||||
const store = f3.createStore({
|
||||
data: treeToF3Data(p.tree, p.isUp),
|
||||
data: treeToF3Data(p.tree, p.isUp, p.depth),
|
||||
node_separation: 250,
|
||||
level_separation: 150,
|
||||
});
|
||||
@ -197,41 +203,12 @@ export function ComplexFamilyTree(p: {
|
||||
);
|
||||
}
|
||||
|
||||
function treeHeight(node: FamilyTreeNode): number {
|
||||
let res =
|
||||
node.down?.reduce((prev, node) => Math.max(prev, treeHeight(node)), 0) ?? 0;
|
||||
|
||||
node.couples?.forEach(
|
||||
(c) =>
|
||||
(res = Math.max(
|
||||
res,
|
||||
c.down.reduce((prev, node) => Math.max(prev, treeHeight(node)), 0)
|
||||
))
|
||||
);
|
||||
|
||||
return res + 1;
|
||||
}
|
||||
|
||||
function treeWidth(node: FamilyTreeNode): number {
|
||||
const values = new Array(treeHeight(node)).fill(0);
|
||||
treeWidthRecurse(node, values, 0);
|
||||
return Math.max(...values);
|
||||
}
|
||||
|
||||
function treeWidthRecurse(node: FamilyTreeNode, vals: number[], level: number) {
|
||||
vals[level] +=
|
||||
1 + (node.couples?.length ?? 0) + ((node.down?.length ?? 0) > 0 ? 1 : 0);
|
||||
|
||||
node.down?.forEach((n) => treeWidthRecurse(n, vals, level + 1));
|
||||
|
||||
node.couples?.forEach((c) =>
|
||||
c.down.forEach((n) => treeWidthRecurse(n, vals, level + 1))
|
||||
);
|
||||
}
|
||||
|
||||
function treeToF3Data(node: FamilyTreeNode, isUp: boolean): f3Data[] {
|
||||
const availableMembers = new Set<number>();
|
||||
getAvailableMembers(node, availableMembers);
|
||||
function treeToF3Data(
|
||||
node: FamilyTreeNode,
|
||||
isUp: boolean,
|
||||
depth: number
|
||||
): f3Data[] {
|
||||
const availableMembers = getAvailableMembers(node, depth);
|
||||
|
||||
const list: f3Data[] = [];
|
||||
if (isUp) treeToF3DataUpRecurse(node, list, availableMembers);
|
||||
@ -239,17 +216,6 @@ function treeToF3Data(node: FamilyTreeNode, isUp: boolean): f3Data[] {
|
||||
return list;
|
||||
}
|
||||
|
||||
function getAvailableMembers(t: FamilyTreeNode, s: Set<number>) {
|
||||
s.add(t.member.id);
|
||||
|
||||
t.couples?.forEach((c) => {
|
||||
s.add(c.member.id);
|
||||
c.down.forEach((e) => getAvailableMembers(e, s));
|
||||
});
|
||||
|
||||
t.down?.forEach((e) => getAvailableMembers(e, s));
|
||||
}
|
||||
|
||||
function memberData(m: Member, c?: Couple): f3.f3DataData {
|
||||
return {
|
||||
first_name: m.first_name ?? "_",
|
||||
@ -271,6 +237,8 @@ function treeToF3DataUpRecurse(
|
||||
child?: number,
|
||||
spouses?: number[]
|
||||
) {
|
||||
if (!availableMembers.has(node.member.id)) return;
|
||||
|
||||
array.push({
|
||||
data: memberData(node.member),
|
||||
id: node.member.id.toString(),
|
||||
@ -309,11 +277,13 @@ function treeToF3DataDownRecurse(
|
||||
array: f3Data[],
|
||||
availableMembers: Set<number>
|
||||
) {
|
||||
if (!availableMembers.has(node.member.id)) return;
|
||||
|
||||
// Get all members ids
|
||||
const children = node?.down?.map((c) => c.member.id.toString()) ?? [];
|
||||
node.couples?.map((c) =>
|
||||
c.down.forEach((m) => children.push(m.member.id.toString()))
|
||||
);
|
||||
let children = node?.down?.map((c) => c.member.id) ?? [];
|
||||
node.couples?.map((c) => c.down.forEach((m) => children.push(m.member.id)));
|
||||
|
||||
children = children.filter((c) => availableMembers.has(c));
|
||||
|
||||
array.push({
|
||||
data: memberData(node.member),
|
||||
@ -328,8 +298,10 @@ function treeToF3DataDownRecurse(
|
||||
? node.member.mother.toString()
|
||||
: undefined,
|
||||
|
||||
spouses: node.couples?.map((c) => c.member.id.toString()),
|
||||
children: children,
|
||||
spouses: node.couples
|
||||
?.filter((s) => availableMembers.has(s.member.id))
|
||||
.map((c) => c.member.id.toString()),
|
||||
children: children.map((c) => c.toString()),
|
||||
},
|
||||
});
|
||||
|
||||
@ -339,6 +311,7 @@ function treeToF3DataDownRecurse(
|
||||
|
||||
if (node.couples) {
|
||||
for (const c of node.couples) {
|
||||
if (!availableMembers.has(c.member.id)) continue;
|
||||
array.push({
|
||||
data: memberData(c.member, c.couple),
|
||||
id: c.member.id.toString(),
|
||||
@ -352,7 +325,9 @@ function treeToF3DataDownRecurse(
|
||||
? c.member.mother.toString()
|
||||
: undefined,
|
||||
spouses: [node.member.id.toString()],
|
||||
children: c.down.map((c) => c.member.id.toString()),
|
||||
children: c.down
|
||||
.filter((c) => availableMembers.has(c.member.id))
|
||||
.map((c) => c.member.id.toString()),
|
||||
},
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user