简体   繁体   中英

How can I Loop through array to assign html to tooltip

I have a line chart and am trying to add html to a mouseover/tooltip on my legend. I want to loop through the array (full_names) so that 'full_names[0]' is displayed in the tooltip on the first legend line, 'full_names[1]' one the second, etc. Currently, they all display 'full_names[0]'. Why do my full_names not loop through correctly?

id_list is also an array that I loop through in order to sequentially assign id's.

my legend:

var lineLegend = svg.selectAll(".lineLegend").data(id_list)
        .enter().append("g")
        .attr("class", "lineLegend")
        .attr("id", function (d, i) { return id_list[i % id_list.length] 
        })
        .attr("transform", function (d, i) {
            return "translate(" + width + "," + (i * 20) + ")";
        })

        .on("click", function (id) {
            var this_chart = d3.select("#temperature_graph")
            var liney = this_chart.select("#" + id)
            var alldots = this_chart.selectAll("." + id)
            var isActive = liney.classed("active");
            var dotsActive = alldots.classed("active")
            console.log(liney)
            liney.classed("active", !isActive);
            alldots.classed("active", !dotsActive)
        })
        .on("mouseover", function (i) {
            div.transition()
                .duration(100)
                .style("opacity", .9);

I want to loop through the array (full_names) here:

 div.html( function (d, i) { return full_names[i % full_names.length]})
                .style('color', '#404040')
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 28) + "px");
        })

the rest:

        .on("mouseout", function (d) {
            div.transition()
                .duration(500)
                .style("opacity", 0);
        });
 lineLegend.append("text").text(function (d) {
            return d;}).attr("transform", 
       "translate(-94,15)").style("font-family", "Sans- 
       Serif").style('fill', '#5a5a5a'); //align texts with boxes
 lineLegend.append("rect")
            .attr("fill", function (d, i) { return colors[i % 
       colors.length] })
            .attr("width", 12).attr("height", 10).attr("transform", 
       "translate(-32,4)").attr("rx", "3");

I think that I may have a scoping issue with my array? As in, I can correctly loop through id_list, just not full_names. Both variables were created in the same place. Is that because id_list is included in my var linelegend?

Thanks so much!!

The problem here is this: i in your html() anonymous function refers to the index of the div , and that will be always 0. Instead of that, you want to get the index of the lineLegend you hover over.

Here are some brief examples. Right now you're doing this:

lineLegend.on("mouseover", function(d,i){
    tooltip.html(function(d,i){
        //here, 'i' is the index of the 'tooltip', always 0.
    });
});

As you can see, the index in the outer anonymous function is not the same of the index in the inner anonymous function.

It should be:

lineLegend.on("mouseover", function(d,i){
    tooltip.html(function(){
        //here, 'i' is the index of the 'lineLegend'.
    });
});

Or, if you want to use parameters in the html() anonymous function, give them other names:

It should be:

lineLegend.on("mouseover", function(d,i){
    tooltip.html(function(e,j){//no 'i' here
        //here, 'i' is the 'lineLegend' index and 'j' the tooltip index
    });
});

And here are some demos. First, using the incorrect i , you can see that the "tooltip" always shows name1 :

 var fullNames = ["name1", "name2", "name3"]; var tooltip = d3.select("#tooltip"); var p = d3.select("body") .selectAll(null) .data(["foo", "bar", "baz"]) .enter() .append("p") .text(String); p.on("mouseover", function(d, i) { tooltip.html(function(d, i) { return fullNames[i] }) }) 
 #tooltip { width: 100%; background-color: wheat; } 
 <script src="https://d3js.org/d3.v5.min.js"></script> <div id="tooltip">Tooltip</div> 

Now the same code, referencing the correct i :

 var fullNames = ["name1", "name2", "name3"]; var tooltip = d3.select("#tooltip"); var p = d3.select("body") .selectAll(null) .data(["foo", "bar", "baz"]) .enter() .append("p") .text(String); p.on("mouseover", function(d, i) { tooltip.html(function() { return fullNames[i] }) }) 
 #tooltip { width: 100%; background-color: wheat; } 
 <script src="https://d3js.org/d3.v5.min.js"></script> <div id="tooltip">Tooltip</div> 

Finally, an advice: don't do what you're trying to do (using the element's indices to get values in another array), that's not the idiomatic D3. Just bind the data. That way, things are clear and won't break unexpectedly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM