Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3: finding graph y-coordinate with mouseover

I am making an interactive area chart using D3. While mousing over the area-chart, I'd like to have a dot rolling along the top of the chart, as in the following example: http://hci.stanford.edu/jheer/files/zoo/ex/time/multiples.html

Once I get the mouse position (using d3.mouse), how do I translate these coordinates to the corresponding data? The x-axis is straightforward using the inverse of the x-scale (e.g. x.invert). However, I can't find the corresponding y-coordinate for my graph. Ideally I could "look up" the x-coordinate in my data and find the corresponding y-coordinate, but not sure how to do this with D3. Thanks!

like image 492
registered user Avatar asked Jul 06 '12 18:07

registered user


Video Answer


2 Answers

It's actually relatively easy to create your own lookup table:

/* Create the lookup table */
var table = {};
data.forEach(function(d) {
    table[d.x] = d.y;
});

This is a viable solution if you have enough data points, but it's likely that you will probably need to use some sort of rounding or interpolator to fill in the intermediate x-values. For instance, if there is a fixed spacing between your points, you can use a linear interpolator and do the following calculations to get the coordinates for your circle on mouseover:

var x = d3.mouse(this)[0];
var y;

if ( table[x] === undefined ) {
    var lower = x - (x % SPACING);
    var upper = lower + SPACING;
    var between = d3.interpolateNumber(table[lower], table[upper]);
    y = between( (x % SPACING) / SPACING );
} else {
    y = table[x];
}

Here is the code in action: http://jsfiddle.net/Wexcode/KGxHF/

Here is another example of how you could do this from Mike Bostock: http://bl.ocks.org/3025699

like image 53
Wex Avatar answered Oct 20 '22 09:10

Wex


mbostock (D3.js author) implement this here

svg.append("rect")
  .attr("class", "overlay")
  .attr("width", width)
  .attr("height", height)
  .on("mouseover", function() { focus.style("display", null); })
  .on("mouseout", function() { focus.style("display", "none"); })
  .on("mousemove", mousemove);

function mousemove() {
  var x0 = x.invert(d3.mouse(this)[0]),
    i = bisectDate(data, x0, 1),
    d0 = data[i - 1],
    d1 = data[i],
    d = x0 - d0.date > d1.date - x0 ? d1 : d0;
  focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
  focus.select("text").text(formatCurrency(d.close));
}
like image 40
Alban Avatar answered Oct 20 '22 08:10

Alban