d3.v3可折叠水平树节点与路径对齐问题技术求助
解决D3水平树节点与连线对齐问题
看起来你在把垂直树转为水平树时,因为手动调整连线坐标导致了错位问题,我来帮你梳理下问题点和解决方案:
问题根源
你在更新连线时手动修改了source和target的坐标(比如var s = { x: d.source.x0 + -15, y: d.source.y0 + 120 }这类代码),这破坏了D3树布局自动计算的节点位置关联,同时树布局的配置和对角线投影也没适配水平树的逻辑,才导致了错位。
修复步骤
1. 调整树布局配置
把原来的nodeSize改为size来定义整个树的可用空间,让D3自动分配节点位置:
// 替换原来的tree定义 var tree = d3.layout.tree() .size([height, width]); // [纵向高度, 横向宽度]
如果偏好使用nodeSize,需要设置为单个节点的间距(比如nodeSize([rectH + 10, rectW + 20]),即纵向和横向的节点间距),而不是整个画布的尺寸。另外建议把height调大一点(比如改为600),避免节点重叠:
var height = 600 - margin.top - margin.bottom;
2. 修正对角线连线逻辑
水平树的连线应该从父节点右侧延伸到子节点左侧,我们需要调整对角线的投影和端点计算:
// 替换原来的diagonal定义 var diagonal = d3.svg.diagonal() // 投影函数将节点坐标转换为SVG坐标 .projection(function(d) { return [d.y, d.x + rectH / 2]; // y是横向位置,x+rectH/2是节点垂直中心 }) // 定义连线起点(父节点右侧) .source(function(d) { return {x: d.source.x + rectH / 2, y: d.source.y + rectW}; }) // 定义连线终点(子节点左侧) .target(function(d) { return {x: d.target.x + rectH / 2, y: d.target.y}; });
3. 移除手动修改连线坐标的代码
删掉你在link.transition里手动构造s和t的代码,直接使用修正后的diagonal:
// 替换原来的link.transition部分 link.transition() .duration(duration) .attr("d", diagonal);
4. 调整节点位置归一化逻辑
如果使用了tree.size,可以去掉手动设置d.y = d.depth * 180的代码,让D3自动计算节点的横向位置:
// 注释或删除这行代码 // nodes.forEach(function(d) { d.y = d.depth * 180; });
核心修改后的代码片段
var margin = { top: 20, right: 120, bottom: 20, left: 120 }, width = 960 - margin.right - margin.left, height = 600 - margin.top - margin.bottom; // 增大高度避免节点重叠 var i = 0, duration = 750, rectW = 120, rectH = 30; var tree = d3.layout.tree() .size([height, width]); // 改用size定义树的整体空间 var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.y, d.x + rectH / 2]; }) .source(function(d) { return {x: d.source.x + rectH / 2, y: d.source.y + rectW}; }) .target(function(d) { return {x: d.target.x + rectH / 2, y: d.target.y}; }); // ... 其他原有代码保持不变 ... function update(source) { var nodes = tree.nodes(root).reverse(), links = tree.links(nodes); // 注释手动设置y的代码,让tree.size自动计算 // nodes.forEach(function(d) { d.y = d.depth * 180; }); // ... 节点更新相关代码保持不变 ... // 更新连线部分 link.transition() .duration(duration) .attr("d", diagonal); // 直接使用修正后的diagonal // ... 其他原有代码保持不变 ... }
这样调整后,节点和连线就能正确对齐了。核心思路是让D3的树布局自动管理节点位置,只在对角线函数里适配节点边缘的连线逻辑,而不是手动修改坐标破坏原有布局逻辑。
内容的提问来源于stack exchange,提问作者cullimorer
相关产品推荐
相关产品推荐

