Question

I have been trying to solve a tooltip problem for quite some time now. I have searched through Stackoverflow and I think my problem is that I am not yet knowledgable enough to piece together a solution from existing posts. I am working on a d3 chart which you can view here, in all its broken glory:

Link to broken chart.

The default "Global" view works. When the "US" button is pressed, the data update correctly; but the tooltips do not. There are more data points in the US dataset than the default Global dataset. The difference in data points is the exact number of tooltips I am missing. I am struggling to use the Update Selection to gain access to the entering tooltips, I can't seem to get at them.

Below please find the d3 code I am using to generate the default view (this is working for me so far):

d3.tsv("data/global.tsv", function(error, data) {
        data.forEach(function(d){
        d.change = +d.change;
        d.score = +d.score;
});


//Create circles            
svg.selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
        return xScale(d.change);
    })
    .attr("cy", function(d){
        return yScale(d.score); 
    })
    .attr("r", 7)
    .attr("class","chart")
    .style("opacity",.8)
    .style("fill", function(d) {
        return d.code;
    })
    .on("mouseover", function(d) {
        var xPosition = parseFloat(d3.select(this).attr("cx"));
        var yPosition = parseFloat(d3.select(this).attr("cy"));

        //Update the tooltip position and value
        d3.select("#tooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px")
            .select("#brand")
            .style("color", d3.select(this).style("fill"))
            .text(d.brand);

        d3.select("#tooltip")
            .select("#change")
            .text(d.change);

        d3.select("#tooltip")
            .select("#score")
            .text(d.score);

        //Show the tooltip
        d3.select("#tooltip").classed("hidden", false);     //quickly apply or remove classes from an element
        })

    .on("mouseout", function() {

        //Hide the tooltip
        d3.select("#tooltip").classed("hidden", true);  //quickly apply or remove classes from an element
        })  

}); //this ends the code on the selected svg element

The block of code below correctly updates my scatterplot when a user clicks on the "US" button:

d3.selectAll("#us_data").on("click", function() {
    d3.tsv("data/us.tsv", function(error, data) {
        data.forEach(function(d) {
            d.change = +d.change;
            d.score = +d.score;
    });

    var circles = svg.selectAll("circle")
        .data(data);


    circles.enter()
        .append("circle")   
        .attr("cx", function(d) { return xScale(d.change); })
        .attr("cy", function(d){ return yScale(d.score); })
        .attr("r", 7)
        .attr("class","chart")
        .style("opacity",.8)
        .style("fill", function(d) { return d.code; });

    circles.transition()
        .duration(500)
        .attr("cx", function(d) { return xScale(d.change); })
        .attr("cy", function(d){ return yScale(d.score); })
        .attr("r", 7)
        .attr("class","chart")
        .style("opacity",.8)
        .style("fill", function(d) { return d.code; });

But when I try to use the same format to update my tooltips for the US selection, nothing happens. I do not yet understand enough JavaScript (or d3) to stray far from existing conventions... so I am sure this is where I fall down.

    var labels = d3.selectAll("#tooltip")
        .data(data);


    labels.enter()
        .append("#tooltip")
        .select("#brand")
        .style("color", d3.select(this).style("fill"))
        .text(d.brand);

    labels.transition()
        .duration(500)
        .select("#brand")
        .style("color", d3.select(this).style("fill"))
        .text(d.brand);


    labels.enter()
        .append("#tooltip")
        .select("#change")
        .text(d.change);

    labels.transition() 
        .duration(500)
        .select("#change")
        .text(d.change);

    labels.enter()
        .append("#tooltip")
        .select("#score")
        .text(d.score); 

I am using this code to create the tooltips on my html page:

    <div id="tooltip" class="hidden">
        <p>Brand: <strong><span id="brand">name</span></strong></p>
        <p>Change: <span id="change">100</span></p>
        <p>Score: <span id="score">100</span></p>

    </div>

Any advice is greatly appreciated.

Best, Gail Z

Was it helpful?

Solution

I had to create a plunker with all your stuff in order to see this more clearly. I factored out the mouseover and mouseout functions so as to re-use them for the us circles. Here is the changed code:

circles.enter()
    .append("circle")   
    .attr("cx", function(d) { return xScale(d.change); })
    .attr("cy", function(d){ return yScale(d.score); })
    .attr("r", 7)
    .attr("class","chart")
    .style("opacity",.8)
    .style("fill", function(d) { return d.code; })
    .on("mouseover", mouseover) // added
    .on("mouseout", mouseout); // added

I hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top