|
@@ -294,24 +294,23 @@
|
|
|
let rootNode = d3.hierarchy(treeData, d => (d && d.children) || []);
|
|
let rootNode = d3.hierarchy(treeData, d => (d && d.children) || []);
|
|
|
|
|
|
|
|
// 动态调整间距,保证节点绝对不重叠,长辈/同辈/配偶使用固定基础间距
|
|
// 动态调整间距,保证节点绝对不重叠,长辈/同辈/配偶使用固定基础间距
|
|
|
- const nodeWidth = 90; // 基础宽度
|
|
|
|
|
|
|
+ const nodeWidth = 120; // 增加基础宽度以避免重叠
|
|
|
const nodeHeight = 260; // 基础高度,调大以避免上下层重叠
|
|
const nodeHeight = 260; // 基础高度,调大以避免上下层重叠
|
|
|
const treemap = d3.tree().nodeSize([nodeWidth, nodeHeight]).separation((a, b) => {
|
|
const treemap = d3.tree().nodeSize([nodeWidth, nodeHeight]).separation((a, b) => {
|
|
|
- return a.parent === b.parent ? 1.4 : 2.0;
|
|
|
|
|
|
|
+ return a.parent === b.parent ? 2.0 : 2.0; // 增加同级节点间距
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
let nodesHier = treemap(rootNode);
|
|
let nodesHier = treemap(rootNode);
|
|
|
|
|
|
|
|
- // 配偶固定在“下层半级”:纵向放到两代中间;横向围绕本人轻度展开
|
|
|
|
|
- const spouseHalfLevelOffsetY = Math.round(nodeHeight * 0.5); // 半级
|
|
|
|
|
- const spouseSpreadX = 110; // 多配偶时的横向间距
|
|
|
|
|
|
|
+ // 配偶固定在同一水平线上:与本人并列显示
|
|
|
|
|
+ const spouseSpreadX = 140; // 增加间距以确保不重叠
|
|
|
nodesHier.descendants().forEach(parent => {
|
|
nodesHier.descendants().forEach(parent => {
|
|
|
const spouses = (parent.children || []).filter(c => c.data && c.data.isSpouseNode);
|
|
const spouses = (parent.children || []).filter(c => c.data && c.data.isSpouseNode);
|
|
|
if (spouses.length === 0) return;
|
|
if (spouses.length === 0) return;
|
|
|
spouses.forEach((spouse, idx) => {
|
|
spouses.forEach((spouse, idx) => {
|
|
|
- const order = idx - (spouses.length - 1) / 2;
|
|
|
|
|
- spouse.x = parent.x + order * spouseSpreadX;
|
|
|
|
|
- spouse.y = parent.y + spouseHalfLevelOffsetY;
|
|
|
|
|
|
|
+ // 计算配偶位置,从右侧开始排列
|
|
|
|
|
+ spouse.x = parent.x + (idx + 1) * spouseSpreadX;
|
|
|
|
|
+ spouse.y = parent.y; // 同一水平线
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -371,21 +370,20 @@
|
|
|
const spouses = (node.children || []).filter(c => c.data && c.data.isSpouseNode);
|
|
const spouses = (node.children || []).filter(c => c.data && c.data.isSpouseNode);
|
|
|
|
|
|
|
|
// 配偶连线拐点:位于本人与配偶节点之间,匹配“下层半级”显示
|
|
// 配偶连线拐点:位于本人与配偶节点之间,匹配“下层半级”显示
|
|
|
- const hY = node.y + Math.round(spouseHalfLevelOffsetY * 0.55);
|
|
|
|
|
|
|
+ // const hY = node.y + Math.round(spouseHalfLevelOffsetY * 0.55);
|
|
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
|
|
|
|
|
|
- // 夫妻关系:倒U型连线(主节点向下,然后横向连到配偶上面)
|
|
|
|
|
|
|
+ // 夫妻关系:水平连线(主节点右侧连接到配偶左侧)
|
|
|
if (spouses.length > 0) {
|
|
if (spouses.length > 0) {
|
|
|
const g = svg.append("g").attr("class", "link-group");
|
|
const g = svg.append("g").attr("class", "link-group");
|
|
|
spouses.forEach((spouse, idx) => {
|
|
spouses.forEach((spouse, idx) => {
|
|
|
- // 主节点向下,拐向配偶,再向下连接配偶顶部 (spouse.y - circleR)
|
|
|
|
|
- const pathD = `M${num(node.x)},${num(node.y + circleR)}
|
|
|
|
|
- L${num(node.x)},${num(hY)}
|
|
|
|
|
- L${num(spouse.x)},${num(hY)}
|
|
|
|
|
- L${num(spouse.x)},${num(spouse.y - circleR)}`;
|
|
|
|
|
|
|
+ // 水平连线,稍微向下偏移一点以避开节点
|
|
|
|
|
+ const linkY = node.y + 10;
|
|
|
|
|
+ const pathD = `M${num(node.x + circleR)},${num(linkY)}
|
|
|
|
|
+ L${num(spouse.x - circleR)},${num(linkY)}`;
|
|
|
g.append("path").attr("class", "link link-spouse").attr("d", pathD);
|
|
g.append("path").attr("class", "link link-spouse").attr("d", pathD);
|
|
|
|
|
|
|
|
- if (idx === 0) addBadge(g, (node.x + spouse.x) / 2, hY + 14, "配偶");
|
|
|
|
|
|
|
+ if (idx === 0) addBadge(g, (node.x + spouse.x) / 2, linkY, "配偶");
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -395,9 +393,9 @@
|
|
|
const minChildX = d3.min(realChildren, c => c.x);
|
|
const minChildX = d3.min(realChildren, c => c.x);
|
|
|
const maxChildX = d3.max(realChildren, c => c.x);
|
|
const maxChildX = d3.max(realChildren, c => c.x);
|
|
|
|
|
|
|
|
- // 如果有配偶,子代主线从配偶连线的中间引出,否则从自己直接引出
|
|
|
|
|
- const startX = spouses.length > 0 ? (node.x + spouses[0].x) / 2 : node.x;
|
|
|
|
|
- const startY = spouses.length > 0 ? hY : node.y + circleR;
|
|
|
|
|
|
|
+ // 如果有配偶,子代主线从本人和最右侧配偶的中间引出,否则从自己直接引出
|
|
|
|
|
+ const startX = spouses.length > 0 ? (node.x + spouses[spouses.length - 1].x) / 2 : node.x;
|
|
|
|
|
+ const startY = node.y + circleR;
|
|
|
|
|
|
|
|
// 将子女横线也相应地下移一些,避免和配偶长名字重叠
|
|
// 将子女横线也相应地下移一些,避免和配偶长名字重叠
|
|
|
const sibsY = childrenY - 60;
|
|
const sibsY = childrenY - 60;
|