问题
I have a webpage with 4 d3 charts for each of 11 different regions. One of those charts is an area chart and the code snippet is:
for (mm=0; mm<regions.length; mm++) {
areas.append("path")
.attr("class",function(d,i){ return "area cons ar"+i+" region"+mm;} )
.attr("id", function(d,i) { return "area_"+i+"_"+mm})
.attr("d", function(d,i) { return area(d)} );
var test = d3.selectAll("path.region"+mm)
.call(d3.helper.tooltip()
.attr("class", function(d, i) { return "tooltip"; })
.text(function(d, i){
console.log(mm);
return "i "+consSubProducts[i]+', i: '+i;}));
}
I want to add tooltips to the charts. In the area plot, each region has different products. Some have 7 products, others have 5. I need to use the mm variable at its runtime values (0-10) to call the correct product array where consSubProducts is currently. (ConsSubProducts is set to a different product array at the top of the for...loop, but as with mm, the code can only see the finally-set array and not the runtime arrays.)
In this code, mm always returns 11, i.e. it returns the final value of mm rather than the values at runtime.
I have tried passing mm in within tooltip() and within .text(function(d,i,mm) - the latter clearly doesn't work as it's expecting a j. I've also tried attaching mm to the class or ID of an object, but within the call() console.log(this) logs object.window.
I've tried modifying tooltip.js but although I can generate the label I want I can't work out how to override the text. Tooltip.js:
d3.helper = {};
d3.helper.tooltip = function(){
var tooltipDiv;
var bodyNode = d3.select('body').node();
var attrs = {};
var text = '';
var styles = {};
function tooltip(selection){
selection.on('mouseover.tooltip', function(pD, pI){
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).length > 80) ? '300px' : null; })
.html(function(d, i){return text(pD, pI);});
})
.on('mousemove.tooltip', function(pD, pI){
// 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); });
})
.on('mouseout.tooltip', function(pD, pI){
// Remove tooltip
tooltipDiv.remove();
});
}
tooltip.attr = function(_x){
if (!arguments.length) return attrs;
attrs = _x;
return this;
};
tooltip.style = function(_x){
if (!arguments.length) return styles;
styles = _x;
return this;
};
tooltip.text = function(_x){
if (!arguments.length) return text;
text = d3.functor(_x);
return this;
};
return tooltip;
};
Any help appreciated!
回答1:
It looks like this is way over the top for something that is super simple. Unless I'm missing something. Let me post some code for how I handle tooltips.
Predefine the tooltip div in the page HTML and class it .tooltip and apply the css of display:none; position:absolute; and add .tooltip.show{display:block;}
var tooltip = d3.select('.tooltip');
function tipUpdate(d,i) {
tooltip.classed('show',true).html(d+" : "+i);
}
areas.append('path')
//all your path attributs
.on('mouseover', tipUpdate)
.on('mouseout', function() { tooltip.classed('show',false); });
areas.on('mousemove', function(d,i) {
var mouse = d3.mouse('body').map( function(d) { return parseInt(d); });
tooltip.attr("style", "left:"+(mouse[0]+10)+"px;top:"+(mouse[1]-15)+"px");
});
This will show the tooltip div on mouseover of the path and move the tooltip relative to it's position in the body and hide the tooltip when the mouse leaves the path. It will display the data and index of the point in the path that it is currently over. You might want to change that but it should be easy.
One problem I thought about later is you cannot do a working tooltip like this on a path. It will always show the data from the last point in the path. I have posted a working fiddle. D3 tooltip
来源:https://stackoverflow.com/questions/34659444/d3-tooltip-passing-in-a-variable