add edges

This commit is contained in:
2024-05-04 13:58:05 +02:00
parent d0af8f0250
commit 8176277fcb
6 changed files with 146 additions and 53 deletions

View File

@@ -1,7 +1,26 @@
<script>
import { Handle, Position } from '@xyflow/svelte';
<script lang="ts">
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
type $$Props = NodeProps;
export let person = {
export let id: $$Props['id'];
id;
export let dragHandle: $$Props['dragHandle'] = undefined;
dragHandle;
export let type: $$Props['type'] = undefined;
type;
export let selected: $$Props['selected'] = undefined;
selected;
export let width: $$Props['width'] = undefined;
width;
export let height: $$Props['height'] = undefined;
height;
export let dragging: $$Props['dragging'];
dragging;
export let targetPosition: $$Props['targetPosition'] = undefined;
targetPosition;
export let sourcePosition: $$Props['sourcePosition'] = undefined;
sourcePosition;
export let data = {
ID: '',
Lastname: 'Nem',
Firstname: 'Ismert',
@@ -10,43 +29,43 @@
};
</script>
<div class="rounded-badge card card-compact bg-primary">
<div class="rounded-badge card card-compact bg-base-300">
<div class="card-body items-center text-center w-30">
<div class="avatar">
<figure class="w-24 mask mask-squircle">
<img src={person.ProfilePicture} alt="Picture of {person.Lastname} {person.Firstname}" />
<img src={data.ProfilePicture} alt="Picture of {data.Lastname} {data.Firstname}" />
</figure>
</div>
<h2 class="card-title text-primary-content">
{person.Lastname}
{person.Firstname}
{person.Middlename}
<h2 class="card-title text-base-content">
{data.Lastname}
{data.Firstname}
{data.Middlename}
</h2>
</div>
</div>
<Handle
type="target"
position={Position.Top}
id="sibling"
id="spouse"
style="transform: translate(10px, 50%); left: 0;"
/>
<Handle
type="source"
position={Position.Top}
id="sibling"
id="spouse"
style="transform: translate(0, 50%); left: auto; right: 10px"
/>
<Handle type="target" position={Position.Top} id="parent" style="transform: translate(0, 50%);" />
<Handle
type="source"
position={Position.Right}
id="right"
style="transform: translate(-3px, 50%);"
/>
<Handle type="target" position={Position.Left} id="left" style="transform: translate(3px, 50%);" />
<Handle
type="source"
position={Position.Bottom}
id="child"
style="transform: translate(0, -3px);"
/>
<Handle type="target" position={Position.Top} id="child" style="transform: translate(0, 50%);" />
<Handle
type="source"
position={Position.Bottom}
id="parent"
style="transform: translate(0, -3px);"
/>

View File

@@ -4,8 +4,8 @@ import { Position, type Node, type Edge } from '@xyflow/svelte';
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeWidth = 172;
const nodeHeight = 36;
const nodeWidth = 250;
const nodeHeight = 250;
function getLayoutedElements(nodes: Node[], edges: Edge[], direction = 'TB') {
const isHorizontal = direction === 'LR';

View File

@@ -0,0 +1,57 @@
import { type Node, type Edge } from '@xyflow/svelte';
function AddToNodesData(data: any, i: number, pushToNodesCallback: (arg: Node) => void) {
if (data[0].Values[i] != null) {
if (Object.prototype.toString.call(data[0].Values[i]) === '[object Array]') {
data[0].Values[i].forEach((person: { ElementId: string; Props: {} }) => {
pushToNodesCallback({
id: person.ElementId,
type: 'custom',
data: person.Props,
position: { x: 0, y: 0 }
});
});
} else {
console.log(data[0].Values[i]);
pushToNodesCallback({
id: data[0].Values[i].ElementId,
type: 'custom',
data: data[0].Values[i].Props,
position: { x: 0, y: 0 }
});
}
}
}
function AddToEdgesData(data: any, i: number, pushToEdgesCallback: (arg: Edge) => void) {
if (data[0].Values[i] != null) {
if (Object.prototype.toString.call(data[0].Values[i]) === '[object Array]') {
data[0].Values[i].forEach((edge: { ElementId: string; StartElementId: string; EndElementId: string; Type: string; Props: {} }) => {
pushToEdgesCallback({
id: edge.ElementId,
source: edge.StartElementId,
sourceHandle: edge.Type === 'Parent' ? 'parent' : edge.Type === 'Child' ? 'child' : 'spouse',
target: edge.EndElementId,
targetHandle: edge.Type === 'Parent' ? 'child' : edge.Type === 'Child' ? 'parent' : 'spouse',
label: edge.Type,
data: edge.Props,
zIndex: edge.Type === 'Spouse' ? 1 : 0
});
});
} else {
console.log(data[0].Values[i]);
pushToEdgesCallback({
id: data[0].Values[i].ElementId,
source: data[0].Values[i].StartElementId,
sourceHandle: data[0].Values[i].Type === 'Parent' ? 'parent' : data[0].Values[i].Type === 'Child' ? 'child' : 'spouse',
target: data[0].Values[i].EndElementId,
targetHandle: data[0].Values[i].Type === 'Parent' ? 'child' : data[0].Values[i].Type === 'Child' ? 'parent' : 'spouse',
label: data[0].Values[i].Type,
data: data[0].Values[i].Props,
zIndex: data[0].Values[i].Type === 'Spouse' ? 1 : 0
});
}
}
}
export { AddToNodesData, AddToEdgesData };

View File

@@ -10,12 +10,14 @@ user.subscribe((value) => {
});
async function fetch_family_tree() {
console.log(PUBLIC_API_URL);
const response = await fetch(
{ PUBLIC_API_URL } + '/familyTree?id=8a8b9b05bdc24550a5cc73e0b55e8d7d',
PUBLIC_API_URL + '/familyTree?id=8a8b9b05bdc24550a5cc73e0b55e8d7d',
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
Authorization: auth_token
}
}

View File

@@ -1,14 +1,14 @@
<script lang="ts">
import { writable } from 'svelte/store';
import { onMount } from 'svelte';
import { SvelteFlowProvider, SvelteFlow, Controls, MiniMap } from '@xyflow/svelte';
import { SvelteFlowProvider, SvelteFlow, Controls, MiniMap, Background } from '@xyflow/svelte';
import type { Node, Edge, NodeTypes } from '@xyflow/svelte';
import { isAuthenticated } from '../lib/stores';
import PersonNode from './../lib/family_tree/PersonNode.svelte';
import { login } from '../lib/auth';
import { fetch_family_tree } from '$lib/family_tree/getFamilyTree';
import { getLayoutedElements } from '$lib/family_tree/dagreLayout';
import { AddToNodesData, AddToEdgesData } from '$lib/family_tree/dataAdapter';
let edges_data: {
id: string;
source: string;
@@ -25,36 +25,26 @@
console.log('user authenticated:', $isAuthenticated);
console.log('fetching nodes');
fetch_family_tree().then((data) => {
let Position = { x: 0, y: 0 };
let nodes_data: Node[] = [];
function AddToNodesData(data: any, i: number) {
if (data[0].Values[i] != null) {
if (Object.prototype.toString.call(data[0].Values[i]) === '[object Array]') {
data[0].Values[i].forEach((person: { ElementId: string; Props: {} }) => {
nodes_data.push({
id: person.ElementId,
type: 'custom',
data: person.Props,
position: Position
});
});
} else {
nodes_data.push({
id: data[0].Values[i].ElementId,
type: 'custom',
data: data[0].Values[i].Props,
position: Position
});
}
}
function pushNodeToData(node: Node) {
nodes_data.push(node);
}
AddToNodesData(data, 0);
AddToNodesData(data, 2);
AddToNodesData(data, 4);
AddToNodesData(data, 6);
AddToNodesData(data, 8);
edges_data = [];
AddToNodesData(data, 0, pushNodeToData);
AddToNodesData(data, 2, pushNodeToData);
AddToNodesData(data, 4, pushNodeToData);
AddToNodesData(data, 6, pushNodeToData);
AddToNodesData(data, 8, pushNodeToData);
let edges_data: Edge[] = [];
function pushEdgeToData(edge: Edge) {
edges_data.push(edge);
}
AddToEdgesData(data, 1, pushEdgeToData);
AddToEdgesData(data, 3, pushEdgeToData);
AddToEdgesData(data, 5, pushEdgeToData);
AddToEdgesData(data, 7, pushEdgeToData);
const layoutedElements = getLayoutedElements(nodes_data, edges_data, 'TB');
@@ -67,13 +57,37 @@
const nodeTypes: NodeTypes = {
custom: PersonNode
};
let menu: { id: string; top?: number; left?: number; right?: number; bottom?: number } | null;
let width: number;
let height: number;
function handleContextMenu({ detail: { event, node } }) {
// Prevent native context menu from showing
event.preventDefault();
// Calculate position of the context menu. We want to make sure it
// doesn't get positioned off-screen.
menu = {
id: node.id,
top: event.clientY < height - 200 ? event.clientY : undefined,
left: event.clientX < width - 200 ? event.clientX : undefined,
right: event.clientX >= width - 200 ? width - event.clientX : undefined,
bottom: event.clientY >= height - 200 ? height - event.clientY : undefined
};
}
// Close the context menu if it's open whenever the window is clicked.
function handlePaneClick() {
menu = null;
}
</script>
<div style="height:100vh;">
<SvelteFlowProvider>
<SvelteFlow {nodes} {nodeTypes} {edges} class="bg-base-100" fitView onlyRenderVisibleElements>
<Controls class="bg-base-300 text-primary-content" />
<MiniMap />
<Controls class="bg-base-300 text-base-content" />
<MiniMap class="bg-base-200"/>
</SvelteFlow>
</SvelteFlowProvider>
</div>

View File

@@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{html,svelte,js,ts}'],
important: true,
theme: {
extend: {}
},