Reputation: 7150
I'm using d3.stack()
to create a normalized stacked barchart.
But I'm having trouble accessing the relevant values of the inital dataset for a mousover tooltip.
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
is the Array[2]
at this point with the values defining baseline / topline, d.data
is the complete original data object but is missing the information over which stack of the series I'm currently hovering.
Ideally I want the tooltip to show for a dataset like {name:"item1", foo:10, bar:20}
value: 10
percentage: 33%
when hovering above the foo
rect.
All the examples I've found are for D3v3 where you can simply use d.y
to access the relevant value but that doesn't seem to work any more with D3v4.
Upvotes: 5
Views: 3584
Reputation: 102194
You can get the name of the element accessing the parent's data, and using that name to get the value:
.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 + "%");
});
Here is your code with that modification:
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>
Upvotes: 8