Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Javascript D3 library, how can I determine mouse position in data set of an area element on mousemove event?

I am trying to setup a tooltip for an area path that I created. I checked all the arguments being passed into the on mousemove event handler, and I'm just getting the full data set, 0, 0. Nothing to indicate my index in the data as far as I can see. "This" context also is the svg path element. Still nothing useful. Even looked at d3.select(this), and I can't find the index anywhere there either. Is there some way to determine over which data point my mouse is?

Looking around I found a reference to d3.mouse(this), and that gives me x/y coordinate, but how do I map that back to a data point in the data set?

My goal is to have a tooltip to display some meta-data related to that specific data point in the set.

Here is are some code snippets as requested:

var area=d3.svg.area()
    .interpolate("monotone")
    .x(function(d){
      return(scale.x(d.date));
    })
    .y0(height-padding.bottom)
    .y1(function(d){
      return(scale.y(d.count));
    });

var path=svg.append('path')
            .datum(data)
            .attr('d',area)
            .attr("clip-path", "url(#clip)")
            .attr('fill','url(#gradient)')
            // .attr('title','path')
            .on('mousemove',function(){
              console.log(arguments);
              console.log(d3.select(this));
              console.log(d3.mouse(this));        
            });          
like image 688
Douglas Mauch Avatar asked Nov 01 '12 20:11

Douglas Mauch


1 Answers

@nautat has the right answer in his edit, but I'd like to expand on it because for whatever reason the blocks examples rarely have comments and can be like unfolding someone else's origami.

This is the relavant part from http://bl.ocks.org/3902569 ... comments along the way are mine

// define a function for mouse move
// this function is wired up to the visualization elsewhere with .on('mousemove', fn)
function mousemove() {
  // using the x scale, in this case a d3 time scale
  // use the .invert() function to interpolate a date along the scale
  // given the x-coordinates of the mouse
  var x0 = x.invert(d3.mouse(this)[0]),

    // using the interpolated date, find an index in the sorted data
    // this would be the index suitable for insertion
    i = bisectDate(data, x0, 1),

    // now that we know where in the data the interpolated date would "fit"
    // between two values, pull them both back as temporaries
    d0 = data[i - 1],
    d1 = data[i],

    // now, examine which of the two dates we are "closer" to
    // to do this, compare the delta values
    d = x0 - d0.date > d1.date - x0 ? d1 : d0;

    // move the "focus" element into position
    // we find the X and Y values for the new position using the x and y scales
    // using the closest data point to the mouse
    focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");

    // set the text of the "focus" element to be the value of the element selected
    focus.select("text").text(formatCurrency(d.close));
}
like image 128
slf Avatar answered Oct 21 '22 11:10

slf