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
相关产品推荐
相关产品推荐

