How do I know which bar the mouse is in for D3 stacked bar?

天涯浪子 提交于 2020-01-24 13:03:19

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!