Как правильно создать связь от брака к ребёнку для построения древа семьи?

Код по построению графа (древа семьи). Нужно найти и преобразовать связи между узлами. Проблема в определении ребёнка от второго брака. ??? Создаю сайт по построению древа семьи. Использую react, react-flow для визуализации графа, dagre для расчёта координат узлов.

Не получается написать правильный код добавления детей к браку. Если у родителей был только один брак, то всё ок. Но если у кого-то из родителей был ребёнок от второго брака, то этот ребёнок может записаться не к тому браку. Нужно, чтобы ребёнок привязывался к браку, в котором муж и жена соответствуют обоим родителям.

Изначально данные связей получаю в таком виде:

{ id: "8", source: "1", target: "4", types: "marriage", type: edgeType },  // связь брака от мужа к жене
    { id: "1", source: "1", target: "2", types: "children", type: edgeType },  // связь от одного родителя к ребёнку
    { id: "2", source: "4", target: "2", types: "children", type: edgeType },  // связь от другого родителя к ребёнку
    { id: "5", source: "5", target: "4", types: "marriage", type: edgeType },  // связь брака от мужа к жене (второй брак жены)
    { id: "6", source: "5", target: "1", types: "children", type: edgeType },  // связь от одного родителя к ребёнку
    { id: "7", source: "4", target: "1", types: "children", type: edgeType } // связь от другого родителя к ребёнку

Если из них построить древо без изменения связей, то оно будет выглядеть так: введите сюда описание изображения

Из скриншота видно, что муж на уровень выше своей жены, что нежелательно. От каждого родителя идут линии к каждому ребёнку, что создаёт хаос.

Для более симпатичного отображения решил преобразовать изначальные связи по следующим правилам:

  1. Из связи с types: "marriage" создаю узел брака;
  2. От мужа и жены создаю связи к браку;
  3. В дальнейшем удаляю первоначальную связь от мужа к жене.
  4. Создаю связь от брака родителей к ребёнку; - как раз на этом этапе возникает сложность!!!
  5. В дальнейшем удаляю связь от родителей к ребёнку.

Теперь древо получается более понятным: Однако связь к "Максиму" (в самом низу) должна идти от другого брака и тоже самое про ребёнка "Текля" Однако связь к "Максиму" (в самом низу) должна идти от другого брака и тоже самое про ребёнка "Текля"

Данные:

const position = { x: 0, y: 0 };
const edgeType = "smoothstep";

export const initialNodes = [
    {
        id: "1",
        type: 'person',
        data: {
            lastName: "Метельский",
            firstName: "Геннадий"
        },
        position: { x: 0, y: 0 },
    },
    {
        id: "2",
        type: 'person',
        data: {
            lastName: "Метельский",
            firstName: "Богдан"
        },
        position: { x: 0, y: 0 },
    },
    {
        id: "3",
        type: 'person',
        data: {
            lastName: "Метельская",
            firstName: "Алина"
        },
        position: { x: 0, y: 0 },
    },
    {
        id: "4",
        type: 'person',
        data: {
            lastName: "Метельская",
            firstName: "Татьяна"
        },
        position: { x: 0, y: 0 }
    },
    {
        id: "5",
        type: 'person',
        data: {
            lastName: "Метельский",
            firstName: "Георгий"
        },
        position: { x: 0, y: 0 },
    }
];


export const initialEdges = [
    { id: "8", source: "1", target: "4", types: "marriage", type: edgeType },
    { id: "1", source: "1", target: "2", types: "children", type: edgeType },
    { id: "4", source: "4", target: "2", types: "children", type: edgeType },
    { id: "5", source: "5", target: "4", types: "marriage", type: edgeType },
    { id: "6", source: "4", target: "3", types: "children", type: edgeType },
    { id: "7", source: "5", target: "3", types: "children", type: edgeType },
];

Часть кода преобразующий данные:

const getLayoutedElements = (nodes, edges/*, direction = "TB"*/) => {
    /*dagreGraph.setGraph({ rankdir: direction });*/

    //nodes.forEach((node) => {
    //    dagregraph.setnode(node.id, { width: nodewidth, height: nodeheight });
    //});

    const childMarriages = {};

    edges.forEach((edge) => {
        if (edge.types === "marriage") {
            const marriageId = `${edge.source}-marriage-${edge.target}`;
            const marriageNode = {
                id: marriageId,
                types: "marriage",
                position,
                data: {
                    husband: edge.source,
                    wife: edge.target,
                    children: [],
                },
            };

            const husbandToMarriage = {
                id: `${edge.source}-to-${marriageId}`,
                source: edge.source,
                target: marriageId,
                type: edgeType,
            };
            const wifeToMarriage = {
                id: `${edge.target}-to-${marriageId}`,
                source: edge.target,
                target: marriageId,
                type: edgeType,
            };
            // Переносим фильтрацию связей типа "children" внутрь map
            const childrenFromMarriage = edges
                .filter((childEdge) => childEdge.types === "children")
                .map((childEdge) => {
                    const childNode = nodes.find((node) => node.id === childEdge.target);
                    if (childNode) {
                        const childId = childNode.id;
                        // Проверяем, принадлежит ли ребенок к данному браку
                        if (
                            (childEdge.source === edge.source ||
                                childEdge.source === edge.target) &&
                            childMarriages[childId] === undefined // Проверяем, что у ребенка еще нет браков
                        ) {
                            childMarriages[childId] = marriageId;
                            marriageNode.data.children.push(childId);
                            return {
                                id: `${marriageId}-to-${childId}`,
                                source: marriageId,
                                target: childId,
                                type: "smoothstep",
                            };
                        }
                    }
                    return null;
                })
                .filter(Boolean);

            nodes.push(marriageNode);
            edges.push(husbandToMarriage);
            edges.push(wifeToMarriage);
            childrenFromMarriage.forEach((edge) => edges.push(edge));
        }
    });
    edges = edges.filter((edge) => edge.types !== "children");
    edges = edges.filter((edge) => edge.types !== "marriage");

    return { nodes, edges };
};


Ответы (0 шт):