D3.js径向树图表如何将节点圆形替换为SVG环形图(donut)
实现方案
核心改动思路
你当前的代码是直接在节点位置渲染圆形,只需将单个circle替换为承载环形图的分组容器即可实现需求,具体改动步骤如下:
步骤1:补充节点的百分比数据
先给原始数据的每个节点增加百分比字段,示例:
var data = { "name": "AirtelApp", "percent": 60, // 新增百分比字段 "children": [ { "name": "airteltopicsOne", "percent": 75, // 新增 "children": [ { "name": "airteltopicsOne1.1", "percent": 90 }, // 新增 { "name": "airteltopicsOne1.2", "percent": 45 }, // 新增 ] }, // 其余节点同理补充percent字段 ] };
步骤2:定义环形图生成器
在节点渲染逻辑前新增D3环形图相关生成器配置:
// 环形图尺寸和原有圆形尺寸匹配 const donutWidth = 10; // 环形的宽度 const outerRadius = 30.5; const innerRadius = outerRadius - donutWidth; // 饼图生成器,仅展示百分比和剩余值两部分 const pie = d3.pie() .sort(null) .value(d => d); // 环形路径生成器 const arc = d3.arc() .innerRadius(innerRadius) .outerRadius(outerRadius); // 环形图配色:第一部分是已完成占比,第二部分是剩余占比 const color = d3.scaleOrdinal() .range(['#4CAF50', '#e0e0e0']);
步骤3:替换原有圆形节点为环形图节点
把你原来直接生成circle的节点逻辑,替换为生成分组容器,在容器内渲染环形图:
// 原来的var node = g.selectAll('.node')...那段整体替换为下面的代码 var node = g .selectAll('.node') .data(nodes.descendants()) .join('g') // 替换为g作为节点容器 .attr('class', 'node') .attr( 'transform', (d) => ` rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0) ` ); // 每个节点容器内渲染环形图 node.each(function(d) { // 生成环形数据:[百分比值, 剩余值] const pieData = pie([d.data.percent, 100 - d.data.percent]); // 渲染环形路径 d3.select(this) .selectAll('path') .data(pieData) .join('path') .attr('d', arc) .attr('fill', (d, i) => color(i)); // 可选:环形中间显示百分比数值 d3.select(this) .append('text') .attr('text-anchor', 'middle') .attr('dy', '0.3em') .attr('font-size', '10px') // 修正文字旋转,保证正显 .attr('transform', d.x >= Math.PI ? 'rotate(180)' : '') .text(`${d.data.percent}%`); });
步骤4:微调原有文字标签位置
因为节点从圆形变成了环形,原有标签的偏移量可以稍微调大,避免和环形重叠,修改fonts部分的x属性即可:
.attr('x', (d) => (d.x < Math.PI === !d.children ? 36 : -36)) // 把原来的6/-6改成36/-36即可
效果参考

注意事项
- 如果需要不同层级的节点环形大小不同,可以根据
d.depth调整outerRadius和innerRadius的数值 - 环形图的配色可以根据业务需求自行修改
color的range值 - 原有节点的hover交互可以直接绑定在
.node类上,无需额外调整
内容的提问来源于stack exchange,提问作者Prasad Sonawane
相关产品推荐
相关产品推荐

