change tooltip position based on whether mouse is above or below the path

2,593 views
Skip to first unread message

Curiouslearn

unread,
Feb 27, 2012, 9:57:56 PM2/27/12
to d3...@googlegroups.com
Hi All,

Please see the working example below. You can hover over the
rectangles to see the tooltip (I have deliberately left the opacity
greater than zero for them for the purpose of this example). As you
can see the tooltip appears above the mouse pointer. I want the
tooltip to appear above the mouse pointer when the pointer is above
the drawn path and below the mouse pointer when mouse pointer is below
the path. One way I can think of doing this is to find the mouse
location in the svg figure, its (xcoord, ycoord) and then comparing
this ycoord with the path's y value when x = xcoord.

I tried adding the line console.log(d3.svg.mouse(this)) and also
console.log(d3.mouse(this)) to the addtooltip() function to see if I
could get the mouse location relative to the origin of the SVG figure.
However, doing so gives me the following error when I hover my mouse
on any of the rectangles:

Uncaught TypeError: Object [object DOMWindow] has no method
'getBoundingClientRect'

Any ideas how I can achieve what I want.

Thanks for reading this.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"
src="http://mbostock.github.com/d3/d3.js"></script>
<style type="text/css">
div.tooltip {
position: absolute;
text-align: center;
z-index: 50;
width: 140px;
height: auto;
padding: 8px;
font: 24px sans-serif;
background: red;
color: white;
border: solid 1px #aaa;
border-radius: 8px;
opacity: 0.8;
}
</style>

</head>
<body>
<div id="viz"></div>

<script type="text/javascript">

var w = 600;
var h = 500;

canvas = d3.select("#viz")
.append("svg:svg")
.attr("width", w)
.attr("height", h);

group1 = canvas.append("svg:g");

var xunscaled = d3.range(10, 40);
console.log(xunscaled);

var genydata = function(x){
return 20 + 2*(Math.pow(x,1.3));
}

yunscaled = xunscaled.map(genydata);

console.log(yunscaled);

xscale = d3.scale.linear().domain([0,40]).range([0,w]);
yscale = d3.scale.linear().domain([20,275]).range([0,h]);

plotData = d3.zip(xunscaled,yunscaled);

console.log(plotData);

d3line = d3.svg.line()
.x(function(d){return xscale(d[0]);})
.y(function(d){return h - yscale(d[1]);})
.interpolate("linear");

group1.append("svg:path")
.attr("d", d3line(plotData))
.style("stroke-width", 2.5)
.style("stroke", "steelblue")
.style("fill", "none");


//****************************************************
// Create rectangles for tooltips
//****************************************************
var rectH = 80;
var rectW = 10;
group1.selectAll("rect.tooltip")
.data(plotData)
.enter()
.append("svg:rect")
.attr("x", function(d){return xscale(d[0]) - (rectW/2);})
.attr("y", function(d){return h - yscale(d[1]) - (rectH/2);})
.attr("width", rectW)
.attr("height", rectH)
.style("z-index", 10)
.style("stroke-width", 1)
.style("stroke", "steelblue")
.style("stroke-opacity", 0.5)
.style("fill", "orange")
.style("fill-opacity", 0.4)
.on("mouseover", function(d){return addtooltip(d);})
.on("mouseout", function(d){return removetooltip();});


//**************************************
// Tooltip
//**************************************
var addtooltip = function(d){
// Round the ratio to two decimal places
adrdRatio = Math.round(Math.pow(10,2) * d[1])/Math.pow(10,2);
// console.log(d3.mouse(this)); //This line gives error
when uncommented.
// Tooltip box with information
d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("top", (d3.event.pageY-90) + "px")
.style("left",(d3.event.pageX-90) + "px")
.html("<table><tr><td>X: </td><td align=left>" + d[0] +
"</td></tr> <tr><td>Y: </td><td align=left>" + adrdRatio +
"</td></tr></table>");
}


var removetooltip = function(){
d3.select("div.tooltip")
.remove();
d3.select("#highlight").remove();
}


</script>
</body>
</html>

Mike Bostock

unread,
Feb 28, 2012, 1:05:04 AM2/28/12
to d3...@googlegroups.com
The reason d3.mouse(this) didn't work for you is because you are
losing the `this` context by the way in which you are calling
addtooltip and removetooltip. Try changing these two lines:

.on("mouseover", function(d){return addtooltip(d);})
.on("mouseout", function(d){return removetooltip();});

To this:

.on("mouseover", addtooltip)
.on("mouseout", removetooltip);

Mike

Bharat Bhole

unread,
Feb 28, 2012, 7:51:34 AM2/28/12
to d3...@googlegroups.com
Hi Mike,

I changed the lines exactly as you suggested. But now the tooltip fails to show. The function addtooltip is not even called when I hover the mouse over the yellow rectangles.

Thanks for responding. Hope you or someone else can help with this.


--
Bharat Bhole
Associate Professor
Department of Economics
Rochester Institute of Technology
Rochester, NY
Email: bharat...@rit.edu


Mike Bostock

unread,
Feb 28, 2012, 12:35:39 PM2/28/12
to d3...@googlegroups.com
> But now the tooltip fails to show.

And why was that? Presumably your browser gave you an error which
might help you debug the problem. I'll give you a hint. What is the
difference between these two bits of code?

#1

var addtooltip = function(d) {
// show tooltip here
};

#2

function addtooltip(d) {
// show tooltip here
}

Mike

Curiouslearn

unread,
Feb 28, 2012, 8:24:23 PM2/28/12
to d3...@googlegroups.com
Hi Mike,

Thanks for your response. I did look for error in the Chrome console,
but it did not show any error.

Anyhow, I changed the function definition from #1 to #2, and it now
works. Next, I need to go and understand properly the difference
between these two ways of defining the function. I don't know much
javascript and I appreciate you pointing me in the right direction.

Mike Bostock

unread,
Feb 28, 2012, 8:34:52 PM2/28/12
to d3...@googlegroups.com
> Next, I need to go and understand properly the difference
> between these two ways of defining the function.

There's a detailed explanation here:

http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

Mike

Abhishek Chavan

unread,
Jun 19, 2012, 2:37:34 AM6/19/12
to d3...@googlegroups.com
Thanks a lot for this link.
Reply all
Reply to author
Forward
0 new messages