Scott
Scott

Reputation: 6736

D3: Multi-line graph is slightly off compared to axises when zooming in

I have a multi-line chart (jsfiddle) that is not plotting data points accurately on the graph, and is proving very difficult to debug.

To add some perspective, I can replicate this in Firefox v43.0.4, IE11 and Chrome 36.0.1985.125 m, the two browsers available to myself and my customers.

Upon first glance, as you hover over the graph, you'll see two lines and a circle intersect and snap to he closest date as dictated by line (230):

var x0 = d3.time.day.round(x.invert(d3.mouse(this)[0])),

Note how they aren't exactly centered on the day's data point.

enter image description here

They settle slightly right of the line. At first I thought that it was an issue with the circle's cx property, but according to all the examples I've based this off of, there doesn't appear to be anything wrong with the event handler mouseMove:

function mouseMove() {
    var x0 = d3.time.day.round(x.invert(d3.mouse(this)[0])),
      i = bisectDate(data, x0, 1);

  focusCircle.transition()
    .duration(333)
    .delay(50)
    .ease('bounce')
    .attr('cx', x(x0))
    .attr('cy', function(d) { return y(d.values[i-1].stat); });

  focusXLine.transition()
    .duration(333)
    .delay(50)
    .ease('bounce')
    .attr('x1', 0)
    .attr('x2', x(x0))
    .attr('y1', function(d) { return y(d.values[i-1].stat); })
    .attr('y2', function(d) { return y(d.values[i-1].stat); });

  focusYLine.transition()
    .duration(333)
    .delay(50)
    .ease('bounce')
    .attr('x1', x(x0))
    .attr('x2', x(x0))
    .attr('y1', height)
    .attr('y2', function(d) { return y(d.values[i-1].stat); });
}

Sure enough, if you zoom in either using the brush, or scroll the mouse wheel, the problem is exacerbated:

enter image description here

Keep in mind, I snap to the closest day, and in the above illustration, there's a two day gap between the two axis points, indicating that the plots to the left are intended to fall on the day I'm currently hovering over, yet they aren't. Being that the axis and the lines/circle line up correctly, I assume it has something to do with the x.domain() and how it's lining up with the corresponding data being fed in by line 232:

x.domain(brush.empty() ? x2.domain() : brush.extent());

I haven't been able to come up with anything on this, and despite this being one rather large cannibalization of others' examples, I would have expected this to be an issue somewhere else, yet no amount of Google-fu is coming up with anything at all on this. What is causing the data to fall to the left of the mouse hover point?

Upvotes: 1

Views: 1002

Answers (1)

meetamit
meetamit

Reputation: 25157

It has to do with dates. At the top, where you generate data, you generate dates that have an hour and minutes component. Later, on mousemove, you snap to the nearest day d3.time.day.round(...). So it doesn't snap to the data, and I would expect the discrepancy to change throughout the day (like, at midnight it'll either align properly or perhaps be off by and entire day).

The fix

When you generate the dates, round to nearest day:

date: d3.time.day.round(new Date(new Date().setDate(new Date().getDate() - count)))

Then, when you set the y-position of the circle, you'll no longer need that i-1 hack (which wasn't working anyway). It becomes simply:

.attr('cy', function(d) { return y(d.values[i].stat); });

See fiddle

Upvotes: 2

Related Questions