0

As a follow up to this question, I've managed to create a multi-series line chart out of nested arrays. I'm now trying to add tooltips to chart similar to the one on this post by Mike Bostock.

This means that I have to figure out a method for bisecting the nested array and then selecting those values for a tooltip. How do I transfer the lines of code below to a nested array?

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

Further into the script:

i = bisectDate(data, x0, 1),
    d0 = data[i - 1],
    d1 = data[i],

Thanks for any help, here is an example JS Fiddle which I'd like to use to create tooltips: http://jsfiddle.net/JYS8n/2/

Community
  • 1
  • 1
ekatz
  • 1,050
  • 1
  • 11
  • 29
  • You would need a nested bisect -- the outer one to select the line (using the y value) and the inner to select the position on the line (using the x value). Could you post the complete code where you're trying to do this please, preferably in a jsfiddle? – Lars Kotthoff Jan 14 '14 at 19:29
  • Lars, the code I'm working with is too heavy to post and isolate my question. Here's a multi-series line chart JS Fiddle (courtesy of @ musically_ut): http://jsfiddle.net/JYS8n/2/. I'd like to add tooltips to the chart by using the bisect function. – ekatz Jan 14 '14 at 19:45

1 Answers1

0

You need to use bisect twice here, first to find the matching x value and then to find the matching y value. First, you'll need to define a second custom bisector that takes the value into account.

var bisectValue = d3.bisector(function(d) { return d.Value; }).left;

The first part of the handler is not changed a lot from the non-nested version. The only difference is that instead of considering only a single data series, we are iterating over all of them and collecting the closest data point for each.

var x0 = x.invert(d3.mouse(this)[0]),
    ds = data.map(function(e) {
        var i = bisectDate(e.Data, x0, 1),
            d0 = e.Data[i - 1],
            d1 = e.Data[i];
        return x0 - d0.Date > d1.Date - x0 ? d1 : d0;
    });

Now ds is a list of data points, the closest one to the cursor position for each series. All that remains to be done now is to bisect again to find the one with the closest value to the current cursor position.

var y0 = y.invert(d3.mouse(this)[1]),
    i = bisectValue(ds.sort(), y0, 1),
    d0 = ds[i - 1],
    d1 = ds[i],
    d = y0 - d0.Value > d1.Value - y0 ? d1 : d0;

The basic skeleton is the same as before, only this time we are comparing y and .Value. Now d is the data point to be highlighted.

focus.attr("transform", "translate(" + x(d.Date) + "," + y(d.Value) + ")");
focus.select("text").text(d.Value);

Full example here. I've also changed the line interpolation -- while that makes it look nicer, the line doesn't go through the actual points anymore.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204