This is a two-month old question, so I'm not sure if this can still help the original poster, but maybe it will help someone else:
When you pass a function as a parameter to another method, the parameter that are given to your function are determined by the code for that method. (Longer explanation here.) Most (although not all) d3 methods on selections will pass the values for the data object, the selection index, and the group index (d
, i
, and j
in the common terminology). However, the group index is not well-established in examples and usage, and it isn't used at all by the code for the d3.helper.tooltip module you're using. The tooltip function never accesses j
, and it never passes j
to the functions you give it.
There are two ways you can fix this:
Option 1: Change the code for the tooltips, so that the event-handling functions accept the third parameter from the elements they are attached to, and pass that parameter on to the functions they call:
/* from https://gist.github.com/biovisualize/2973775 */
function tooltip(selection){
selection.on('mouseover.tooltip', function(pD, pI, pJ){
var name, value;
// Clean up lost tooltips
d3.select('body').selectAll('div.tooltip').remove();
// Append tooltip
tooltipDiv = d3.select('body').append('div');
tooltipDiv.attr(attrs);
tooltipDiv.style(styles);
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv.style({
left: (absoluteMousePos[0] + 10)+'px',
top: (absoluteMousePos[1] - 15)+'px',
position: 'absolute',
'z-index': 1001
});
// Add text using the accessor function, Crop text arbitrarily
tooltipDiv.style('width', function(d, i){
return (text(pD, pI, pJ).length > 80) ? '300px' : null;
})
.html(function(d, i){return text(pD, pI, pJ);});
})
.on('mousemove.tooltip', function(pD, pI, pJ){
// Move tooltip
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv.style({
left: (absoluteMousePos[0] + 10)+'px',
top: (absoluteMousePos[1] - 15)+'px'
});
// Keep updating the text, it could change according to position
tooltipDiv.html(function(d, i){ return text(pD, pI, pJ); });
})
.on('mouseout.tooltip', function(pD, pI, pJ){
// Remove tooltip
tooltipDiv.remove();
});
}
Option 2: If you don't want to change the module script, you could work around it by making sure that the index you're interested in is embedded within the data object for the element:
var test = svg.selectAll("g#container g.points")
.data(categs)
.enter().append("g")
.attr("class", function(d,i) {return "points pt"+i;})
.style("stroke", function(d,i) {return "#"+z(i);})
.attr("fill", function(d,i) {return "#"+z(i);})
.selectAll("circle")
.data(function(groupData,groupIndex) {
d.values.forEach(function(v){v.groupIndex = groupIndex;});
//modify each value to reference the groupIndex
//Note that in the data-join function the data and the *first*
//index parameter refer to the data and index for the group
return d.values;
//each of the values will become a data object for a
//separate circle in this group
})
.enter().append("circle")
.attr("cx", function(d,i) {return x(d.date);})
.attr("cy", function(d,i) {return y(d.y+d.y0);})
.attr("r", 5)
.call(d3.helper.tooltip()
.attr({class: "tooltip"})
.text(function(d, i) { return "Category: "+ d.groupIndex; })
//use the saved index, passed to the tooltip function as part
//of the element's data object
);