D3.js水平堆叠柱状图:如何设置x属性实现分段堆叠?
实现D3.js水平堆叠柱状图的矩形衔接
你遇到的核心问题是每个堆叠的矩形需要从前一个矩形的末端开始绘制,也就是每个矩形的x坐标应该是前面所有矩形宽度的累积值(经过比例尺转换后)。下面是具体的解决方案和修改后的代码:
关键思路
要实现堆叠效果,我们需要为每个数据项计算起始偏移量——也就是当前项之前所有数据值的总和。然后通过x比例尺将这个偏移量转换为SVG画布上的实际x坐标。
修改后的完整代码
const bars = d3.select('#bars').append('svg').attr('width', 800).attr('height', 200); d3.json('HHPro.json').then(data => { var bar1Data = [ { position: 1, label: '70k', value: data.lemon.HH_Income.seventyK }, { position: 2, label: '71K - 149K', value: data.lemon.HH_Income.seventyoneK_onefortynineK }, ]; // 按值降序排序 bar1Data = bar1Data.sort(function(a, b) { return d3.descending(a.value, b.value); }); // 计算每个数据项的累积起始偏移量 let cumulativeOffset = 0; bar1Data.forEach(d => { d.startX = cumulativeOffset; cumulativeOffset += d.value; }); var colorScale = d3.scaleOrdinal() .range(["#E8A82B", "#000000"]); const x = d3.scaleLinear() .domain([0, cumulativeOffset]) // 用计算好的总累积值作为域的上限 .range([0, 800]); // 修正y比例尺(原代码的rangeRound设置有误,这里调整为适合水平柱状图的范围) const y = d3.scaleLinear() .domain([0, 1]) // 因为是单组堆叠,y轴只需要一个分组位置 .range([50, 150]); // 控制柱状图的垂直位置和高度 // 数据绑定+enter-update模式的正确写法 const rects = bars.selectAll('rect') .data(bar1Data); // 更新已有元素 rects .attr('width', d => x(d.value)) .attr('height', 100) .attr('x', d => x(d.startX)) .attr('y', y(0)) .style("fill", (d, i) => colorScale(i)); // 添加新元素 rects.enter() .append('rect') .attr('width', d => x(d.value)) .attr('height', 100) .attr('x', d => x(d.startX)) // 这里使用计算好的起始偏移量 .attr('y', y(0)) .style("fill", (d, i) => colorScale(i)); });
核心修改点说明
- 计算累积偏移量:
通过遍历数据数组,为每个数据项添加startX属性,记录当前项之前所有值的总和。这个值就是该矩形在数据域中的起始位置。 - 设置x属性:
将x属性设置为x(d.startX),通过x比例尺把数据域的累积值转换为画布上的像素坐标,这样每个矩形就会精准衔接在前一个的末端。 - 修正y比例尺:
原代码的y比例尺设置有误,这里调整为适合单组水平堆叠图的配置,控制柱状图的垂直位置和高度。
另外,如果你后续需要多组堆叠柱状图,可以使用D3内置的d3.stack()方法,它会自动帮你计算每个堆叠层的起始和结束位置,代码会更简洁。
内容的提问来源于stack exchange,提问作者AliShahVis
相关产品推荐
相关产品推荐

