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.