问题
I got stacked bar in d3 and need to add tooltip to it. I have trouble to figure out which bar the mouse is in, any idea how can I decide which bar the mouse is in?
group.enter().append("g")
.classed("layer", true)
.attr("fill", d => z(d.key))
.on("mouseover", function(d) {
var num = d.key == "xkey" ? d[4][1] : d[4][1] - d[4][0]
tip.html("<p>" + d.key + " " + num + "</p>")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style("visibility", "visible")
})
.on("mouseout", function(d) {
tip.style("visibility", "hidden")
});
Now I just hardcoded to show the last bar's data. Maybe I can play with xScale and event's x position? Or this is not the D3 way to do it?
Here is the plunker: http://plnkr.co/edit/6xB2Kzi46hWL37UjlgTs?p=preview
回答1:
Instead of triggering mouseover events on the group I suggest you trigger the events on your bars
. The reason is that your data
bind on the groups is stacked for Male and Female and therefore not able to give you the bar type i.e. Relations
. However in your bars
if you console.log(d)
in the mouseover function you can clearly see the appropriate d.data.Relations
.
However, now in place of a single number, you will get an array for e.g. [0,70]
when you mouse over for female and [60,130]
when you mouse over for male for the data for year 2002 and "Other" Relations
. The way this array works is that the first value is the current value, while the second value is the total. We can compare this value to the value from the d.data
to evaluate whether it is for the gender Male or Female. So if d[1]
is equal to the numF
, i.e. the value of +d.data.Female
, then it is a female, but if d[1]
is equal to numF+numM
, i.e. the sum of the value of (+d.data.Male) + (+d.data.Female)
then it is a male, as the male is stacked on top of the female in this case due to the order of the keys
being ["Female","Male"]
.
bars.enter().append("rect")
.attr("width", xScale.bandwidth())
.merge(bars)
.on("mouseover", function(d) {
console.log(d);
// get number of females
let numF = +d.data.Female;
// get number of males
let numM = +d.data.Male;
// get the Relations
let Relations = d.data.Relations;
// Evaluate the gender by comparing the mouseover data value for d[1] to the numF for 'Female'
// or
// numF+numM
let gender,value;
if (d[1] === numF){
gender = 'Female';
value = numF;
}else if (d[1] === numF+numM) {
gender = 'Male';
value = numM;
}
//produce the tooltip
tip.html("<p>" +Relations + "<br>" + gender + ": " + value + "</p>")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style("visibility", "visible");
})
.on("mouseout", function(d) {
tip.style("visibility", "hidden");
})
.transition().duration(speed)
.attr("x", d => xScale(d.data.Relations))
.attr("y", d => yScale(d[1]))
.attr("height", d => yScale(d[0]) - yScale(d[1]));
Note I had to change the css for the tooltip to make it slightly taller as I added a
between the Relations
and the Gender: number
.
Working Plunker as a Demo.
P.S. I also cleaned up the code a bit for clarity such as semicolons and placing the <svg>
and tooltip <div>
within the <body>
and not outside of it.
来源:https://stackoverflow.com/questions/59189153/how-do-i-know-which-bar-the-mouse-is-in-for-d3-stacked-bar