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

D3环形图工具提示的数据绑定异常问题排查

问题

使用D3 v3创建带平滑过渡和工具提示的环形图时,图表可正常渲染,但mouseEnter事件中d.data始终为undefined。虽能通过d.explicitOriginalTarget.__data__获取数据,但该属性不适合生产环境使用。

解决方案

核心问题

事件绑定对象错误:当前把mouseenter事件绑定在父容器<g>元素上,而非每个环形分段的<path>元素。父容器未绑定数据,因此事件回调中的d无法获取到分段数据。

具体修改步骤

  • 将事件绑定到path元素:在创建或更新path元素时,为每个path绑定mouseenter事件,而非绑定到父g元素。
  • 修复arcTween函数的interpolate引用:原代码中interpolate未定义,需改为d3.interpolate。
  • 调整pie布局的起始角度:原startAngle(-(Math.PI / 2) * 5)会导致图表起始角度异常,改为-(Math.PI / 2)让环形图从顶部开始,符合常规视觉习惯。

修改后的完整代码

JavaScript代码

const margin = 40;
const width = 450;
const height = 450;

const radius = Math.min(width, height) / 2 - margin;
const innerRadius = 120;
const cornerRadius = 8;
const padAngle = 0.01;
const transitionDuration = 2000;
const color = d3.scale.ordinal().range(["#0aa849", "#e3df0b", "#a11f0b"]);

let svg = null;
let gElement = null;
let chartPie = null;
let chartArc = null;
let tooltip = null;

svg = d3.select(`#donut_chart`)
  .append("svg")
  .attr("viewBox", `0 0 ${width} ${height}`);

gElement = svg
  .append("g")
  .attr("transform", `translate(${width / 2},${height / 2})`);

chartArc = d3.svg.arc()
  .innerRadius(innerRadius)
  .outerRadius(radius)
  .cornerRadius(cornerRadius);

function arcTween(a) {
  var i = d3.interpolate(this._current, a); // 修复interpolate引用
  this._current = i(0);
  return function(t) {
    return chartArc(i(t));
  };
}

function onMouseEnter(d) {
  console.log(d.data); // 现在可以正常获取数据
  console.log(d.data[1]); // 获取数值
}

function updateChart(data) {
  chartPie = d3.layout.pie()
    .startAngle(-(Math.PI / 2)) // 调整起始角度到顶部
    .value((d) => d[1])
    .sort(null)
    .padAngle(padAngle)(data);

  // 处理已有path的过渡
  const paths = gElement.selectAll("path").data(chartPie);
  
  // 更新已有元素
  paths.transition()
    .duration(transitionDuration)
    .attrTween("d", arcTween);

  // 添加新元素
  paths.enter()
    .append("path")
    .attr("class", `donut_chart`)
    .attr("fill", (d) => color(d.data[0]))
    .attr("d", chartArc)
    .each(function(d) {
      this._current = d;
    })
    .on("mouseenter", onMouseEnter); // 为每个path绑定事件

  // 移除多余元素(如果数据数量减少)
  paths.exit().remove();
}

let newData = Object.entries({
  high: 3,
  middle: 4,
  low: 2
})
updateChart(newData);

HTML代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div id="donut_chart"></div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:45:24