引入核心库
<script src="https://d3js.org/d3.v7.min.js"></script>
准备DOM容器
<div id="tree-container"> <svg width="800" height="600"></svg> </div>
树状数据需符合嵌套格式:
{ "name": "根节点", "children": [ { "name": "子节点1", "children": [ {"name": "叶节点1"}, {"name": "叶节点2"} ] } ] }
const root = d3.hierarchy(data); const treeLayout = d3.tree() .size([600, 400]) .nodeSize([120, 80]); treeLayout(root);
关键参数说明:
size([width, height])
:定义布局范围nodeSize([xSpacing, ySpacing])
:控制节点间距separation()
:自定义兄弟节点间距算法const svg = d3.select("svg") .attr("viewBox", [-50, -50, 800, 600]) .style("background", "#f8f9fa");
const links = svg.selectAll(".link") .data(root.links()) .join("path") .attr("class", "link") .attr("d", d3.linkHorizontal() .x(d => d.y) .y(d => d.x)) .style("stroke", "#6c757d");
const nodes = svg.selectAll(".node") .data(root.descendants()) .join("g") .attr("class", "node") .attr("transform", d => `translate(${d.y},${d.x})`);
// 节点圆形 nodes.append("circle") .attr("r", 18) .style("fill", "#4a8cff") .style("stroke", "#1e5cb3"); // 文字标签 nodes.append("text") .text(d => d.data.name) .attr("dy", 5) .attr("dx", -15) .style("font-family", "Segoe UI") .style("font-size", "0.9em");
折叠/展开功能
nodes.on("click", function(event, d) { if(d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } updateChart(root); });
动态更新函数
function updateChart(source) { const updatedRoot = treeLayout(root);
// 节点过渡动画
nodes.transition()
.duration(500)
.attr(“transform”, d => translate(${d.y},${d.x})
);
// 连线平滑过渡
links.transition()
.duration(500)
.attr(“d”, d3.linkHorizontal()
.x(d => d.y)
.y(d => d.x));
}
---
### 五、样式优化建议
```css
.link {
fill: none;
stroke-width: 1.5px;
}
.node circle {
cursor: pointer;
transition: stroke 0.3s;
}
.node text {
user-select: none;
text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
大数据量处理
内存管理