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

求助:解决D3.v5水平堆叠柱状图JSON数据加载报错问题

解决D3.v5水平堆叠柱状图的报错问题

咱们先逐个拆解你遇到的核心错误,然后给出修复后的完整代码,再聊聊后续优化的小建议:

错误1:<rect> width属性解析失败

你设置柱子宽度的时候写了return d;,但这里的d是数组里的完整对象(比如{ position: 1, label: '70k', value: 1708026 }),D3没办法把一个对象转换成SVG能识别的长度值,所以才会报Expected length, "[object Object]"的错误。

修复方法:把宽度的回调改成返回对象的value属性,也就是return d.value;,这样传给width的就是纯数值了。

错误2:sum函数的参数与内部逻辑错误

你调用sum函数的时候传了bar1Data.value,但bar1Data是一个数组,根本没有value属性,这直接导致了Cannot read property '0' of undefined的报错;另外就算传对了数组,sum函数里直接累加array[i]也不对,因为数组里的元素是对象,不是纯数值。

修复方法:

  • 调用sum时传入完整的bar1Data数组:sum(bar1Data, 0, i)
  • 改造sum函数,累加每个元素的value属性:
function sum(array, start, end) {
  var total = 0;
  for (var i = start; i < end; i++) {
    total += array[i].value; // 这里要明确取对象的value值
  }
  return total;
}

错误3:DOM选择器不匹配

你的HTML里是<div id="bar"></div>,但代码里用了d3.select('#bars')(多了个s),这会导致D3找不到要挂载SVG的容器,等于白忙活一场。

修复方法:把选择器改成d3.select('#bar'),和HTML里的id对应上。


修复后的完整代码

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

<script>
var bar1Data = [{ position: 1, label: '70k', value: 1708026 }, { position: 2, label: '71K - 149K', value: 1915059 }]; 

// 按position升序排序
bar1Data = bar1Data.sort(function(a, b) { 
  return d3.ascending(a.position, b.position); 
}); 

var colors = ['green', 'blue']; 

var bars = d3.select('#bar') 
  .append('svg') 
  .attr('width', 800) 
  .attr('height', 200); 

bars.selectAll('rect') 
  .data(bar1Data) 
  .enter() 
  .append('rect') 
  .attr('width', function(d) { 
    return d.value; // 取对象的value作为宽度
  }) 
  .attr('x', function(d, i) { 
    return sum(bar1Data, 0, i); // 传入完整数组计算堆叠偏移
  }) 
  .attr('fill', function(d, i) { 
    return colors[i]; 
  }) 
  .attr('y', 0) 
  .attr('height', 100); 

// 修正后的sum函数,累加每个元素的value
function sum(array, start, end) { 
  var total = 0; 
  for (var i = start; i < end; i++) { 
    total += array[i].value; 
  } 
  return total; 
} 
</script>

后续优化小建议

现在的代码直接用原始数值作为宽度,你的value都是百万级,而SVG宽度只有800,柱子肯定会超出画布。后续可以用D3的线性比例尺来映射数值到合适的范围,比如:

// 定义线性比例尺,把总数值映射到SVG的可用宽度(留50px边距)
var xScale = d3.scaleLinear()
  .domain([0, d3.sum(bar1Data, d => d.value)]) // 定义域:0到所有value的总和
  .range([0, 750]); // 值域:0到750px(SVG总宽度800,留50px边距)

// 然后把width和x的属性改成用比例尺转换:
.attr('width', function(d) { 
  return xScale(d.value); 
}) 
.attr('x', function(d, i) { 
  return xScale(sum(bar1Data, 0, i)); 
})

这样柱子就会自适应SVG的宽度,不会超出范围啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:53:11