Как правильно создать связь от брака к ребёнку для построения древа семьи?
Код по построению графа (древа семьи). Нужно найти и преобразовать связи между узлами. Проблема в определении ребёнка от второго брака. ??? Создаю сайт по построению древа семьи. Использую 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 } // связь от другого родителя к ребёнку
Если из них построить древо без изменения связей, то оно будет выглядеть так:

Из скриншота видно, что муж на уровень выше своей жены, что нежелательно. От каждого родителя идут линии к каждому ребёнку, что создаёт хаос.
Для более симпатичного отображения решил преобразовать изначальные связи по следующим правилам:
- Из связи с types: "marriage" создаю узел брака;
- От мужа и жены создаю связи к браку;
- В дальнейшем удаляю первоначальную связь от мужа к жене.
- Создаю связь от брака родителей к ребёнку; - как раз на этом этапе возникает сложность!!!
- В дальнейшем удаляю связь от родителей к ребёнку.
Теперь древо получается более понятным:
Однако связь к "Максиму" (в самом низу) должна идти от другого брака и тоже самое про ребёнка "Текля"
Данные:
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 };
};