diff --git a/components/family-tree.vue b/components/family-tree.vue index bcc480b..7ffc73a 100644 --- a/components/family-tree.vue +++ b/components/family-tree.vue @@ -4,10 +4,13 @@ import { type AnchorSpec, BlankEndpoint, type BrowserJsPlumbInstance, + type Connection, FlowchartConnector, newInstance, + type OverlaySpec, ready, } from "@jsplumb/browser-ui"; +import { ChevronDown } from "lucide-vue-next"; import type { TempTriple } from "@/types/resulttypes"; @@ -28,6 +31,9 @@ const childContainer = ref(); const partnerContainer = ref(); const meContainer = ref(); +const showAllChilldren = ref(false); +const uncollapseChildrenContainer = ref(); + function filterUniqueObjects(list: Array<{ id: number; name: string }>) { return list.filter((entry, idx) => list.findIndex((e) => e.id === entry.id) === idx); } @@ -51,13 +57,63 @@ const partners = computed(() => { props.relations.filter((r) => r.name === "hat Ehe mit").map((r) => r.to), ); }); + const instance = ref(); // Add resize handler to monitor container width and adapt chart function resizeHandler() { - console.log("Resize"); instance.value?.repaintEverything(); } +const childConnections = ref>(); +function drawChildConnections() { + const container = + showAllChilldren.value || children.value.length <= 3 + ? childContainer.value + : uncollapseChildrenContainer.value; + const childContainerChildren = [...(container?.children ?? [])]; + const getOverlays = (idx: number) => { + let overlays: Array = [ + { + type: "PlainArrow", + options: { location: 1, direction: 1, length: 8, width: 10 }, + }, + ]; + if (idx === 0 && showAllChilldren.value) + overlays.push({ + type: "Custom", + options: { + location: 8, + create() { + const d = document.createElement("button"); + d.innerHTML = `${t("FamilyTree.collapse-children")}`; + d.onclick = toggleShowAllChildren; + return d; + }, + }, + }); + return overlays; + }; + instance.value?.batch(() => { + childConnections.value + ?.filter((con): con is Connection => con !== undefined) + .forEach((con) => instance.value?.deleteConnection(con)); + + childConnections.value = childContainerChildren.map((child, idx) => { + return instance.value?.connect({ + source: meContainer.value, + target: child, + connector: { + type: FlowchartConnector.type, + options: { midpoint: 0.9999, stub: [12, 20], alwaysRespectStubs: true }, + }, + anchors: [AnchorLocations.Bottom, AnchorLocations.Top], + endpoint: BlankEndpoint.type, + overlays: getOverlays(idx), + }); + }); + }); +} + onMounted(() => { ready(() => { instance.value = newInstance({ @@ -124,32 +180,8 @@ onMounted(() => { }); }); }); + drawChildConnections(); - // Add child connectors only to uppermost children - const childContainerChildren = [...(childContainer.value?.children ?? [])]; - const minHeight = Math.min( - ...childContainerChildren.map((el) => el.getBoundingClientRect().top), - ); - childContainerChildren - .filter((child) => child.getBoundingClientRect().top === minHeight) - .forEach((child) => { - instance.value?.connect({ - source: meContainer.value, - target: child, - connector: { - type: FlowchartConnector.type, - options: { midpoint: 0.9, stub: 12, alwaysRespectStubs: true }, - }, - anchors: [AnchorLocations.Bottom, AnchorLocations.Top], - endpoint: BlankEndpoint.type, - overlays: [ - { - type: "PlainArrow", - options: { location: 1, direction: 1, length: 8, width: 10 }, - }, - ], - }); - }); window.addEventListener("resize", resizeHandler); }); }); @@ -157,6 +189,11 @@ onMounted(() => { onBeforeUnmount(() => { window.removeEventListener("resize", resizeHandler); }); + +function toggleShowAllChildren() { + showAllChilldren.value = !showAllChilldren.value; + void nextTick(drawChildConnections); +} diff --git a/messages/de.json b/messages/de.json index 3b64ba7..1293aee 100644 --- a/messages/de.json +++ b/messages/de.json @@ -201,7 +201,9 @@ "children": "Kinder", "parents": "Eltern", "show-all-children": "Zeige alle {count} Kinder", - "show-all-siblings": "Zeige alle {count} Geschwister" + "show-all-siblings": "Zeige alle {count} Geschwister", + "collapse-children": "Kinder einklappen", + "collapse-siblings": "Geschwister einklappen" }, "ui": { "showing-results": "Zeige {first} - {last} von {all} Ergebnissen", diff --git a/messages/en.json b/messages/en.json index 8a47e4a..06eb9ca 100644 --- a/messages/en.json +++ b/messages/en.json @@ -201,7 +201,9 @@ "children": "Children", "parents": "Parents", "show-all-children": "Show all {count} children", - "show-all-siblings": "Show all {count} siblings" + "show-all-siblings": "Show all {count} siblings", + "collapse-children": "Collapse children", + "collapse-siblings": "Collapse siblings" }, "ui": { "showing-results": "Showing {first} - {last} out of {all} results", diff --git a/public/assets/icons/reduce.svg b/public/assets/icons/reduce.svg new file mode 100644 index 0000000..a9ab42c --- /dev/null +++ b/public/assets/icons/reduce.svg @@ -0,0 +1 @@ +