D3v4 堆叠条形图提示框

5

我正在使用d3.stack()创建一个归一化的堆叠条形图。
但是我在访问初始数据集的相关值以进行鼠标提示时遇到了问题。

serie.selectAll("rect")
    .data(function(d) { return d; })
    .enter().append("rect")
      ...
      .on("mousemove", function(d){
          let coords = d3.mouse(svg.node());
          tooltip.style("left", coords[0] + "px");
          tooltip.style("top", coords[1] - 70 + "px");
          tooltip.style("display", "inline-block");
          tooltip.html("HOW TO ACCESS DATA HERE?");
        });

d 是此时 Array[2] 的值,定义基线/顶线,d.data 是完整的原始数据对象,但缺少我当前悬停在哪个系列的信息。
理想情况下,我希望工具提示显示类似于 {name:"item1", foo:10, bar:20} 的数据集。

value: 10
percentage: 33%

当悬停在foo矩形上方时。
我找到的所有示例都是针对D3v3的,您可以简单地使用d.y来访问相关值,但是在D3v4中似乎不再起作用。


v4中的第一个参数(d)与v3完全相同。我建议您发布一个MCVE - Gerardo Furtado
那么我认为这是版本相关的假设是错误的,尽管如此问题仍然存在:我如何知道我正在悬停在系列的哪个矩形上方?根据这个例子(http://bl.ocks.org/mstanaland/6100713),它应该只是 d.y,但这里是一个 fiddle,因为 d 是堆栈数组,所以它不起作用:https://jsfiddle.net/vu624zrg/1/。 - TommyF
1个回答

8
你可以通过访问父元素的数据来获取元素的名称,并使用该名称获取其值:
.on('mouseover', function(d, i) {
    var thisName = d3.select(this.parentNode).datum().key;
    var thisValue = d.data[thisName];
    var total = d.data.foo + d.data.bar;
    tooltip.html("Name: " + thisName + "<br>Value: " + thisValue + "<br>Percentage: " + thisValue / total + "%");
});

以下是您的代码进行此修改后的版本:

var svg = d3.select("svg"),
    margin = {
        top: 20,
        right: 60,
        bottom: 30,
        left: 40
    },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.1)
    .align(0.1);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);
var stack = d3.stack()
    .offset(d3.stackOffsetExpand);

var colors = ["#FF0000", "#00FF00", "#0000FF"];

var data = [{
    name: "item1",
    foo: 10,
    bar: 20
}, {
    name: "item2",
    foo: 50,
    bar: 50
}];

x.domain(data.map(function(d) {
    return d.name;
}));

var serie = g.selectAll(".serie")
    .data(stack.keys(["foo", "bar"])(data))
    .enter().append("g")
    .attr("class", "serie")
    .attr("fill", function(d, i) {
        return colors[i];
    });


var tooltip = d3.select('#tooltip');

var rects = serie.selectAll("rect")
    .data(function(d) {
        return d;
    })
    .enter().append("rect")

rects.attr("x", function(d) {
        return x(d.data.name);
    })
    .attr("y", function(d) {
        return y(d[1]);
    })
    .attr("height", function(d) {
        return y(d[0]) - y(d[1]);
    })
    .attr("width", x.bandwidth())
    .on('mouseover', function(d, i) {
        var thisName = d3.select(this.parentNode).datum().key;
        var thisValue = d.data[thisName];
        var total = d.data.foo + d.data.bar;
        tooltip.html("Name: " + thisName + "<br>Value: " + thisValue + "<br>Percentage: " + thisValue / total + "%");
    });

g.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

g.append("g")
    .attr("class", "axis axis--y")
    .call(d3.axisLeft(y).ticks(10, "%"));
<script src="https://d3js.org/d3.v4.min.js"></script>

<div id="tooltip">tooltip</div>
<svg width="500" height="300"></svg>


非常感谢,d3.select(this.parentNode).datum().key 是我无法理解的部分! - TommyF
@Gerardo Furtado,我们如何在悬停时将工具提示移动到条形图上方?对于像您这样有知识的人来说,这可能是一个快速修复。谢谢。 - Mixter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接