简体   繁体   中英

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));        
            });          

@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));
}

Your problem is not so much related to the mouseover event listener, but more to the way you bind data to your path; you don't do a proper data join.

Read more about data joins: http://bost.ocks.org/mike/join/

The following example is using divs instead of paths, but the principle is the same. See working example at: http://jsfiddle.net/RghQn/

var data = ['a', 'b', 'c'];
d3.select("body").selectAll("div")
    .data(data)
  .enter().append("div")
    .text(String)
    .on("mouseover", function(d,i) {
        console.log("mouseover!");
        // d: bound datum to DOM element
        console.log("d: ", d);
        // i: index of the selection
        console.log("i: ", i);
        // this context: the current DOM element
        console.log(d3.select(this).text());
    });
​​​​​​​​​​​​​​​

See also the API docs section about event listeners: https://github.com/mbostock/d3/wiki/Selections#wiki-on

selection.on(type[, listener[, capture]])

Adds or removes an event listener to each element in the current selection, for the specified type. The type is a string event type name, such as "click", "mouseover", or "submit". The specified listener is invoked in the same manner as other operator functions, being passed the current datum d and index i, with the this context as the current DOM element. To access the current event, use the global d3.event.


EDIT

I know realize I misunderstood your question. You have one path and want to get information about the path coordinates at the location of the mouse.

There is not straightforward. You can see how Mike did it in the following example: http://bl.ocks.org/3902569

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