Search code examples
javascriptd3.jstooltip

How to align d3js tooltip in center of time divisions?


I'm creating a tooltip that shows the y-value as you mouse over the graph region. However, I notice that the jump in value occurs on the x0 value tick, rather than the middle, between the x0 and x1 value ticks. If you look at the image below, you can see the red line represents the x-position of the cursor and how the y-value is incorrectly placed for x0+1px to (x1+x0)/2 [where x0 is the 15th and x1 is the 16th].

tooltip alignment screenshot

Here is my code, which is borrowing heavily from this example.

AC.bisectDate = d3.bisector(function(d) { return d.date; }).left;

function mousemoveall(){;
    var x0 = AC.charts[0].x.invert(d3.mouse(this)[0]);
    AC.charts.forEach(function(thisChart){
        mousemove(thisChart,x0);
    });

}

function mousemove(thisChart,x0){

    var i = AC.bisectDate(thisChart.chartData, x0, 1),
        d0 = thisChart.chartData[i - 1],
        d1 = thisChart.chartData[i],
        d = x0 - d0.date > d1.date - x0 ? d1 : d0;
    var mydata = thisChart.chartData[i][AC.props[thisChart.id]];

    thisChart.focus.attr("transform","translate(" 
        + (thisChart.x(d.date) + thisChart.margin.left) + "," 
        + (thisChart.margin.top + (thisChart.height * thisChart.id) + (10 * thisChart.id) 
        + thisChart.y(mydata) ) + ")");
    thisChart.focus.select("text").text(mydata);    

}   

How would I go about having the y-value jump take place exactly between the 15th and the 16th, rather than at the 15th?


Solution

  • I discovered that the reason I was experiencing these jumps was that I needed to decrement the index whenever the mouse passed over the interface between the two x-values (in this case, two dates). Creating this i2 variable that adjusts for the transition fixed my tracking problem. The modified mousemove function is below:

    function mousemove(thisChart,x0){
        var i = AC.bisectDate(thisChart.chartData, x0, 1),
            i2 = i,
            d0 = thisChart.chartData[i - 1],
            d1 = thisChart.chartData[i],
            d = x0 - d0.date > d1.date - x0 ? d1 : d0;
    
        if (x0 - d0.date <= d1.date - x0) {i2 = i-1;}
    
        var mydata = thisChart.chartData[i2][AC.props[thisChart.id]],
            yPos = thisChart.y(mydata)+10+thisChart.margin.top,
            xPos = +thisChart.x(d.date) + +thisChart.margin.left;
        thisChart.focus.attr("transform","translate(" + xPos + "," + yPos + ")");
        thisChart.focus.select("text").text(mydata);    
    }   
    

    I'm not sure why I couldn't find this sort of if statement in other examples' code, while their tooltip alignment seemed fine. Maybe I have something strange in my code, or maybe their datasets are so densely packed you don't notice the awkward jump?