D3.js带连接线环形图问题:标签与连接线无法正常显示
解决D3环形图(Donut Chart)分类标签与连接线不显示的问题
我仔细看了你的代码,问题主要出在两个地方:完全没写分类标签的渲染逻辑,以及连接线的坐标判断和路径生成逻辑有误。下面就给你针对性的修复方案:
问题拆解
- 你当前只实现了百分比数值的文本渲染,但完全忽略了
label字段的处理,所以分类标签根本没被添加到页面中; - 原代码里连接线的坐标计算和路径拼接逻辑搞反了方向,导致线条要么错位要么被隐藏。
修复后的完整代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>D3 Donut Chart with Labels & Connectors</title> </head> <body> <script src="https://d3js.org/d3.v3.min.js"></script> <script> var data = [ { percentage: 19, label: 'Consulting' }, { percentage: 3, label: 'Consumer Goods' }, { percentage: 5, label: 'Energy/Chemical/Gas' }, { percentage: 3, label: 'Entrepreneurship' }, { percentage: 1, label: 'Environment & Sustainability' }, { percentage: 19, label: 'Financial Services' }, { percentage: 3, label: 'General Management' }, { percentage: 6, label: 'Government' }, { percentage: 7, label: 'Hospital/Health Care/Health Services' }, { percentage: 2, label: 'Human Resources' }, { percentage: 4, label: 'IT' }, { percentage: 2, label: 'International Development' }, { percentage: 3, label: 'Manufacturing/Operations' }, { percentage: 4, label: 'Marketing/PR/Advertising' }, { percentage: 1, label: 'Media/Sports/Entertainment' }, { percentage: 7, label: 'Nonprofit/Education/Special Org.' }, { percentage: 6, label: 'Other' }, { percentage: 2, label: 'Research & Development' }, { percentage: 4, label: 'Sales/Business Development' }, ]; var width = 300, height = 300, radius = Math.min(width, height) / 2; var color = d3.scale.ordinal() .range(["#243668", "#2b7eb4", "#186b97", "#6391a1", "#d2c5b7", "#9c9286", "#5b5b59"]); var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.percentage; }); var arc = d3.svg.arc() .innerRadius(radius - 100) .outerRadius(radius - 50); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var path = svg.selectAll("path") .data(pie(data)) .enter().append("path") .attr("fill", function(d, i) { return color(i); }) .attr("d", arc); // 渲染百分比标签 svg.selectAll(".percentage-label").data(pie(data)) .enter() .append("text") .attr("class", "percentage-label") .attr("text-anchor", "middle") .attr("x", function(d) { var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2; d.cx = Math.cos(a) * (radius - 75); return d.x = Math.cos(a) * (radius - 20); }) .attr("y", function(d) { var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2; d.cy = Math.sin(a) * (radius - 75); return d.y = Math.sin(a) * (radius - 20); }) .text(function(d) { return d.value; }) .each(function(d) { var bbox = this.getBBox(); // 根据标签在环形的左右侧,调整连接线和标签的坐标 if (d.cx > 0) { d.sx = d.x + bbox.width/2 + 8; // 右侧:连接线从百分比标签右侧延伸 d.ox = d.cx + 10; // 分类标签的位置(环形外侧) } else { d.sx = d.x - bbox.width/2 - 8; // 左侧:连接线从百分比标签左侧延伸 d.ox = d.cx - 10; // 分类标签的位置(环形外侧) } d.sy = d.oy = d.y + 5; }); // 新增:渲染分类标签 svg.selectAll(".category-label").data(pie(data)) .enter() .append("text") .attr("class", "category-label") .attr("text-anchor", function(d) { return d.cx > 0 ? "start" : "end"; }) .attr("x", function(d) { return d.ox; }) .attr("y", function(d) { return d.oy; }) .text(function(d) { return d.data.label; }); // 注意:D3 pie布局会把原始数据存在data属性里 // 定义连接线的箭头标记 svg.append("defs").append("marker") .attr("id", "circ") .attr("markerWidth", 6) .attr("markerHeight", 6) .attr("refX", 3) .attr("refY", 3) .append("circle") .attr("cx", 3) .attr("cy", 3) .attr("r", 3); // 修正:渲染连接线 svg.selectAll("path.pointer").data(pie(data)).enter() .append("path") .attr("class", "pointer") .style("fill", "none") .style("stroke", "black") .attr("marker-end", "url(#circ)") .attr("d", function(d) { // 根据标签位置的左右,生成对应方向的连接线 return "M" + d.cx + "," + d.cy + " L" + d.sx + "," + d.sy; }); </script> </body> </html>
关键修复细节
新增分类标签渲染:
- 专门添加了
.category-label文本元素,通过d.data.label获取原始数据里的分类名称(D3的pie布局会把原始数据包装在data属性中); - 根据标签在环形的左侧/右侧,设置不同的文本对齐方式(左对齐/右对齐),避免文本超出可视区域。
- 专门添加了
修正连接线逻辑:
- 重新调整了
sx(连接线起点)和ox(分类标签位置)的计算规则,根据环形上点的x坐标正负判断方向,确保连接线路径正确; - 简化了路径生成逻辑,直接从环形上的点连接到百分比标签的边缘,避免了原代码中错误的路径拼接。
- 重新调整了
元素分类管理:给不同类型的文本元素添加了专属类名,方便后续样式调整和代码维护。
这样修改后,分类标签和连接线就能正常显示,整体布局也会更协调。
内容的提问来源于stack exchange,提问作者lexiexiexi
相关产品推荐
相关产品推荐

