Я пытаюсь создать собственный макет генеалогического древа, используя D3.js (без d3.tree) и позиционирование вручную [заJavascript

Форум по Javascript
Ответить
Anonymous
 Я пытаюсь создать собственный макет генеалогического древа, используя D3.js (без d3.tree) и позиционирование вручную [за

Сообщение Anonymous »

Требования
1.Все сыновья должны быть выровнены по левому краю
2.Все дочери должны быть выровнены по правому краю
3.Вся семья каждого ребенка (ребенок → супруг → потомки) должна рассматриваться как один вертикальный блок
4.Когда семья первого сына заканчивается, семья второго сына начинается непосредственно под ним
5.Та же логика вертикального стекирования применяется к дочерним элементам
6.Родители подключаются к дочерним элементам через одну среднюю точку, а затем разветвляются к дочерним узлам
Примечание. Я прикрепил эталонное изображение, показывающее ожидаемый результат.
Что я пробовал
Я вычисляю позиции вручную, используя рекурсию и отслеживая смещения по оси Y.
Код ниже приведен минимальный воспроизводимый пример, демонстрирующий логику макета.
Минимально воспроизводимый пример

Код: Выделить всё






.link {
fill: none;
stroke: #000;
stroke-width: 2px;
}

.node rect {
fill: #fff;
stroke-width: 1.5px;
}

.male { stroke: #007bff; }
.female { stroke: #dc3545; }

text {
font-family: Arial, sans-serif;
font-size: 12px;
text-anchor: middle;
dominant-baseline: middle;
}

.dot {
fill: #333;
}







const data = {
name: "Shobhan",
spouse: "Jatabai",
children: [
{
name: "Mahesh",
side: "left",
spouse: "Sunita",
children: [
{ name: "Sogan", spouse: "Samarta", children: [
{ name: "Samaraj" },
{ name: "Satyam" }
]}
]
},
{
name: "Renjana",
side: "right",
spouse: "Ramchandra",
children: [
{ name: "Aakash", spouse: "Neka" },
{ name: "Vishal", spouse: "Priti" }
]
}
]
};

const svg = d3.select("#svg");
const centerX = 600;
const topY = 80;
const leftX = 300;
const rightX = 900;

const nodeW = 100;
const nodeH = 36;
const vGap = 30;

let nodes = [];
let links = [];

// calculate height of an entire family block
function familyHeight(person) {
let h = nodeH;
if (person.children) {
person.children.forEach(c => {
h += familyHeight(c) + vGap;
});
}
return h;
}

// recursive layout
function layoutFamily(person, x, y, parentMid) {
const node = { ...person, x, y };
nodes.push(node);

if (parentMid) {
links.push({
x1: parentMid.x,
y1: parentMid.y,
x2: x,
y2: y
});
}

if (!person.children) return y + nodeH + vGap;

let cy = y + nodeH + vGap;
person.children.forEach(child => {
cy = layoutFamily(child, x, cy, { x, y });
});

return cy;
}

// root connector
svg.append("line")
.attr("x1", centerX)
.attr("y1", 20)
.attr("x2", centerX)
.attr("y2", topY)
.attr("stroke", "#000")
.attr("stroke-width", 2);

let leftY = topY + 60;
let rightY = topY + 60;

// layout children
data.children.forEach(child => {
const h = familyHeight(child);
const x = child.side === "left" ? leftX : rightX;
const y = child.side === "left" ? leftY : rightY;

links.push({
x1: centerX,
y1: topY,
x2: x,
y2: y
});

layoutFamily(child, x, y, null);

if (child.side === "left") leftY += h + vGap;
else rightY += h + vGap;
});

// draw links
svg.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", d =>  `
M ${d.x1} ${d.y1}
V ${(d.y1 + d.y2) / 2}
H ${d.x2}
V ${d.y2}
`);

// draw nodes
const g = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x},${d.y})`);

g.append("rect")
.attr("class", "male")
.attr("x", -nodeW - 10)
.attr("y", -nodeH / 2)
.attr("width", nodeW)
.attr("height", nodeH);

g.append("text")
.attr("x", -nodeW / 2 - 10)
.text(d => d.name);

const couples = g.filter(d => d.spouse);

couples.append("rect")
.attr("class", "female")
.attr("x", 10)
.attr("y", -nodeH / 2)
.attr("width", nodeW)
.attr("height", nodeH);

couples.append("text")
.attr("x", nodeW / 2 + 10)
.text(d => d.spouse);

couples.append("circle")
.attr("r", 4);





Справочное изображение


Подробнее здесь: https://stackoverflow.com/questions/798 ... ut-d3-tree
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»