I'm getting crazy on how to add tooltip to my linear d3 chart, so that the user can see the specific value of the performance along the years. This is the fiddle: http://jsfiddle.net/d9Lya/ and this the code
// define dimensions of graph
var m = [20, 80, 80, 80]; // margins
var w = 650 - m[1] - m[3]; // width
var h = 500 - m[0] - m[2]; // height
var data = [30, 28, 33] ;
var years = [2010, 2011, 2012] ;
var data2 = [100, 200, 200] ;
var years2 = [2009, 2010, 2011] ;
var alldata = data.concat(data2);
var allyears = years.concat(years2);
var data3 = [200, 220, 300] ;
var years3 = [2011, 2012, 2013] ;
var alldata = data.concat(data2, data3);
var allyears = years.concat(years2, years3);
//unique vals functin
var unique = function(origArr) {
var newArr = [],
origLen = origArr.length,
found,
x, y;
for ( x = 0; x < origLen; x++ ) {
found = undefined;
for ( y = 0; y < newArr.length; y++ ) {
if ( origArr[x] === newArr[y] ) {
found = true;
break;
}
}
if ( !found) newArr.push( origArr[x] );
}
return newArr;
};
allyears = unique(allyears);
var x = d3.scale.linear().domain([d3.min(allyears), d3.max(allyears)]).range([0,w]);
var y = d3.scale.linear().domain([0, (d3.max(alldata))*1.3]).range([h, 0]);
var line = d3.svg.line()
.x(function(d,i) {
return x(years[i]);
})
.y(function(d) {
return y(d);
})
var line2 = d3.svg.line()
.x(function(d,i) {
return x(years2[i]);
})
.y(function(d) {
return y(d);
})
var line3 = d3.svg.line()
.x(function(d,i) {
return x(years3[i]);
})
.y(function(d) {
return y(d);
})
// Add an SVG element with the desired dimensions and margin.
var graph = d3.select("#graph").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
// create xAxis
var xAxis = d3.svg.axis().scale(x).ticks(allyears.length).tickSize(-h).tickSubdivide(true);
// Add the x-axis.
graph.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
// create left yAxis
var yAxisLeft = d3.svg.axis().scale(y).ticks(8).orient("left");
// Add the y-axis to the left
graph.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(-25,0)")
.call(yAxisLeft);
graph.append("svg:text")
.attr("class", "title1")
.attr("x", (w/2))
.attr("y", 0)
.text("Performance")
.style({ "stroke": "Black", "fill": "Black", "stroke-width": "1px"})
.attr("text-anchor", "middle")
.style("font-size", "16px") ;
graph.append("svg:path").attr("d", line(data)).style("stroke", "steelblue");
graph.append("svg:text")
.attr("class", "title1")
.attr("x", 0)
.attr("y", 30)
.text("TEAM A")
.style({ "stroke": "steelblue", "fill": "steelblue", "stroke-width": "0px"});
graph.append("svg:path")
.attr("d", line2(data2)).style("stroke", "green")
;
graph.append("svg:text")
.attr("class", "title2")
.attr("x", 0)
.attr("y", 50)
.text("TEAM B")
.style({ "stroke": "Green", "fill": "Green", "stroke-width": "0px"});
graph.append("svg:path").attr("d", line3(data3)).style("stroke", "red");
graph.append("svg:text")
.attr("class", "title3")
.attr("x", 0)
.attr("y", 70)
.text("team C")
.style({ "stroke": "Red", "fill": "Red", "stroke-width": "0px"});
I'm actually new to D3 and I've seen seveal other samples around and I'm not able to reproduce them on my js code. Can anyone help me? Regards
I mentioned in the comments that "the line's data is the complete array, and figuring out where on the line the user's mouse is would require extra calculation". That's one reason to use "invisible circles" to grab mouse events over datapoints. Another is that you can make the radius of the circle much larger than the stroke width to make a larger area for mouse events. A third is that you can then decorate the circles on mouseover, like in the NVD3 line charts.
But what if you don't want extra circles crowding up your DOM. Or what if you want the mouseover event to be triggered anywhere on the line, not just on the points? You can still figure out where the mouse is relative to the line, and can use that to find the correct point in the data array for that line.
Live example here: http://fiddle.jshell.net/c2mru/8/
The
d
value passed to the event handler function is the data object attached to the<path>
element. That is normally the array of points on the line, although sometimes it is an object that contains the array of points as a property, in which case you'd have to amend this to suit. Usingd3.mouse(container)
you can figure out the position of the mouse in the relevant SVG coordinate system, and using the invert method of the scale you can figure out the position of the mouse relative to the horizontal axis. Then, assuming that your data is a normal line graph that doesn't repeat x-values, it's a simple matter of scrolling through the array of points to find the one closest to the mouse.Note that this method won't work with @picus' original code, because that code doesn't actually use d3 methods to link data to the elements. (@picus, check out the Tutorials page for how to make working with d3 much easier!)