You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.js带连接线环形图问题:标签与连接线无法正常显示

解决D3环形图(Donut Chart)分类标签与连接线不显示的问题

我仔细看了你的代码,问题主要出在两个地方:完全没写分类标签的渲染逻辑,以及连接线的坐标判断和路径生成逻辑有误。下面就给你针对性的修复方案:

问题拆解

  1. 你当前只实现了百分比数值的文本渲染,但完全忽略了label字段的处理,所以分类标签根本没被添加到页面中;
  2. 原代码里连接线的坐标计算和路径拼接逻辑搞反了方向,导致线条要么错位要么被隐藏。

修复后的完整代码

<!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>

关键修复细节

  1. 新增分类标签渲染:

    • 专门添加了.category-label文本元素,通过d.data.label获取原始数据里的分类名称(D3的pie布局会把原始数据包装在data属性中);
    • 根据标签在环形的左侧/右侧,设置不同的文本对齐方式(左对齐/右对齐),避免文本超出可视区域。
  2. 修正连接线逻辑:

    • 重新调整了sx(连接线起点)和ox(分类标签位置)的计算规则,根据环形上点的x坐标正负判断方向,确保连接线路径正确;
    • 简化了路径生成逻辑,直接从环形上的点连接到百分比标签的边缘,避免了原代码中错误的路径拼接。
  3. 元素分类管理:给不同类型的文本元素添加了专属类名,方便后续样式调整和代码维护。

这样修改后,分类标签和连接线就能正常显示,整体布局也会更协调。

内容的提问来源于stack exchange,提问作者lexiexiexi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:35:50