scooterlord
scooterlord

Reputation: 15339

d3.js adding circle focus points to multi-line series

After 6 long hours, I managed to add just a couple of more lines to my example, following my previous post (D3 tooltip show values from nested dataset) concerning the use of tooltips.

Now I am stuck at a different point - I can't make circle points that snap to the line points. Other users have already pointed me to a few directions (thanks @Mark), but still haven't been able to combine everything and make it work as I want it.

I have created one circle for each line with its corresponding line color. When hovering over with the mouse, a tooltip with all the lines' values appears and the circles must be positioned on the lines on the x and y axis.

My problem lies in the following piece of code, located inside the mousemove function, in line #106 of this fiddle edit: updated fiddle (https://jsfiddle.net/2en21Lqh/13/):

d3.selectAll(parent + ' .d3-focuspoint')
  .classed("hidden", false)
  .attr("cx", xz(lastDate))
  .attr("cy", function(c) { 
    return d3.map(c.values, function(d,i) {
      if (lastDate == d.date) {
        console.log(d.value);
        return d.value;
      }
   })
});

The circles are already bound to the existing data (two days ago I wouldn't have figured this on my own! - at least I am sligthly improving! :/ ), so I am trying to apply the correct cy value but can't figure out the way to do it. The function inside cy returns an object rather than the d.value I am looking for. What am I doing wrong? I've been trying for hours to find any similar examples but can't find any :/

edit: even pointers to the right direction would help :/

Upvotes: 0

Views: 1023

Answers (1)

Mark
Mark

Reputation: 108512

Try this:

var mousemoveFunc = function(d, i) {

  var x0 = xz.invert(d3.mouse(this)[0]);

  var lastDate,
      cys = [], //<-- create array to hold y values for circles
      ds = []; //<-- create array to hold tooltip text

  dataGroup.forEach(function(e) { //<-- loop the data (I removed the map since we now need to return two things)
    var i = bisectDate(e.values, x0, 1),
        d0 = e.values[i - 1],
        d1 = e.values[i];

    var d = x0 - d0.date > d1.date - x0 ? d1 : d0;

    lastDate = d.date; //<-- hold onto the date (same for all xs)
    cys.push(d.value); //<-- hold onto the y value for all circles
    ds.push(e.key + " " + d.value); //<-- make the tooltip line
  });

  var mouse = d3.mouse(svg.node()).map(function(d) {
    return parseInt(d);
  });
  var left = Math.min(containerwidth, mouse[0]+margin.left+margin.right),
      top = Math.min(containerheight, mouse[1]+margin.top+margin.right);

  d3.selectAll(parent + ' .d3-focuspoint')
    .classed("hidden", false)
    .attr("cx", xz(lastDate)) //<-- set x position
    .attr("cy", function(d,i) {        
        return yz(cys[i]); //<-- loop the 3 circles and set y position
  });

  tooltip
    .html(lastDate.toString() + "<br/>" + ds.join("<br/>"))
    .classed('hidden', false)
    .style('left', left + 'px')
    .style('top', top + 'px');          

};

Updated fiddle.

Upvotes: 1

Related Questions