show value when click or move mouse over on d3.svg.line

13,504 views
Skip to first unread message

Diana

unread,
Jan 31, 2012, 7:45:14 PM1/31/12
to d3-js
Dear All,

I implemented a line animation from a series of x (date), y (value)
data pair, using d3.svg.line. I'd like to show the time and value pair
when I move the cursor on the line.

The segments of data is as following:

var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });

var chart = chart.append("svg:svg")
.attr("width", chartWidth )
.attr("height", chartHeight )
.append("svg:g");


chart.select("path.line").attr("d", line(data));

I tried to use this:
chart.select("path.line").attr("d", line(data)).on("mouseover",
function(d, i) { return alert("value: " + d[i].value);});

Which doesn't work because of i doesn't return the index as I
expected. Also, I don't want to use alert for the dialog box.

Any tip/thought/suggestion is greatly appreciated.

Thanks
Diana



Ian Johnson

unread,
Jan 31, 2012, 11:18:05 PM1/31/12
to d3...@googlegroups.com

All you need to do is remove the [i] because the mouseover callback just receives the data for the element that was moused over:
alert(d.value)

Ian Johnson

unread,
Jan 31, 2012, 11:21:29 PM1/31/12
to d3...@googlegroups.com

Oops, I miss read your code, the index i will refer to the path (you only seem to have one path) so the mouseover can't tell you about an individual point on the path. To do that you may want to have a circle at each point in your data array which you attach a mouseover event instead.

Mike Bostock

unread,
Feb 1, 2012, 2:27:53 AM2/1/12
to d3...@googlegroups.com
Right, the issue here is that you have a single path element (that
represents multiple data points), so you can't really use the normal
technique of just registering a mouseover listener. There are a few
alternative things you can do:

* Draw circles on top of the line, and put your mouseover listener
there. If you like, you can even use invisible circles with
pointer-events all.

* Use a mousemove listener rather than a mouseover listener, and then
use your scale's invert method to find the corresponding x-value. You
can then find the closest x-value in your dataset (say by using
d3.bisect) and determine the value that way.

* Use the voronoi layout to create an invisible overlay. This is a bit
like the previous approach, but finds the closest point in x & y
rather than just x. You can see an example of this technique here:

http://mbostock.github.com/d3/talk/20111018/airports.html

Mike

Diana

unread,
Feb 1, 2012, 2:35:31 AM2/1/12
to d3-js
Hi Ian,

Your suggestion worked! : )

Here is my code:
chart.selectAll("circle")
.data(data)
.enter()
.append("svg:circle")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.value); })
.attr("r", 3)
.attr("opacity", 0)
.append("svg:title").text(function(d) {return "Time: " + d.date +
"\nValue: " + d.value;});

Many thanks!

On Jan 31, 8:21 pm, Ian Johnson <enja...@gmail.com> wrote:
> Oops, I miss read your code, the index i will refer to the path (you only
> seem to have one path) so the mouseover can't tell you about an individual
> point on the path. To do that you may want to have a circle at each point
> in your data array which you attach a mouseover event instead.
> On Jan 31, 2012 8:18 PM, "Ian Johnson" <enja...@gmail.com> wrote:
>
>
>
>
>
>
>
> > All you need to do is remove the [i] because the mouseover callback just
> > receives the data for the element that was moused over:
> > alert(d.value)

Diana

unread,
Feb 1, 2012, 2:52:45 AM2/1/12
to d3-js
Mike,

Thanks for your answer!

I will try the 2nd and 3rd methods later.

I made the first approach working well when not animating (see the
code in my response to Ian's message). However, I am having some
trouble to make those circles moving smoothly with the line. I
animated the line following the example : http://bl.ocks.org/1148374.
The code to do the transformation is as follows:

chart.select("path.line")
.attr("transform", "translate(" + x(data[1].date) + ")")
.attr("d", line(data))
.transition()
.ease("linear")
.duration(interval)
.attr("transform", "translate(" + x(data[0].date) + ")");

So the line appears moving smoothly, rather than jumping at each time
interval. I did the same transformation for the circles. It doesn't
work. Any idea?

Thanks
-Diana

Mike Bostock

unread,
Feb 1, 2012, 2:55:42 AM2/1/12
to d3...@googlegroups.com
> So the line appears moving smoothly, rather than jumping at each time
> interval.  I did the same transformation for the circles. It doesn't
> work. Any idea?

I'd read this tutorial:

http://bost.ocks.org/mike/path/

Mike

Shripad K

unread,
Jan 5, 2013, 7:19:13 AM1/5/13
to d3...@googlegroups.com, mbos...@cs.stanford.edu
Sorry for invoking a dead thread. This method works great for line charts with linear interpolation. But if you change the interpolation to say, "basis" or "cardinal", the circles don't coincide with the line path http://bl.ocks.org/4461225 . Anyway to get the modified data when using a different interpolation?

Ian Johnson

unread,
Jan 8, 2013, 9:12:50 PM1/8/13
to d3...@googlegroups.com
one way to deal with this would be to use getPointAtLength on your path to get x,y coordinates at various point's of your path.
you wouldn't be able to get these points from data space, you would have to do something like divide the length of the path up evenly to get them, but it would let you put circles accurately.
here is an example of using that api function:

and a video where i talk about it
--
Ian Johnson - 周彦

Shripad K

unread,
Jan 9, 2013, 5:42:14 AM1/9/13
to d3...@googlegroups.com
@Ian awesome thanks for those links. Will watch & try them and get back to you :)

Shreeram Kushwaha

unread,
Jan 9, 2013, 8:27:02 AM1/9/13
to d3...@googlegroups.com
I have one query.
Suppose I have 10 different paths( in form of bezier curve), then How I am going to show the transition effect simultaneously as you have shown in the example.

Ian Johnson

unread,
Jan 9, 2013, 3:36:54 PM1/9/13
to d3...@googlegroups.com
perhaps you could post a simple example to clarify your question, but if you stored the "len" variable on the data for each path, then you could select all your paths and modify the transition attrTween to access d.len, allowing each one to track its own length and manage its own transition.
Reply all
Reply to author
Forward
0 new messages