How to create a simple tooltip in d3

A common question I see on stackoverflow a lot is around Tooltips.
There are a bunch of examples out there but people sometimes confuse their intention.
So I thought I create a short post about Tooltips for d3.

Goal of a tooltip

The goal of the tooltip is to show information on things when you hover over them.
And in our specific case we want the tooltip to follow the mouse.

How do I create a tooltip in d3

First off let’s add a new element to the page.

d3.select('body').append('div');

Important here: 
Add it to the body or an div outside your SVG/Canvas. This is important!

Why?

We use the mouse position to change the position of the tooltip with d3.event but it gives you the absolute position of the mouse on the screen not within your SVG.

d3.select('body')
.append('div')
.attr('id', 'tooltip')
.attr('style', 'position: absolute; opacity: 0;');

We also set the position of the element to absolute so that it is outside of the flow of the document and can overlap other elements. We set the opacity to 0 to not show the tooltip by default.

How to hook up the tooltip to your element

Let‘s use a circle as an example.
And let our data be ['a','b','c'].
We use three events to handle the tooltip.
mouseover is used to handle the initial event. This is where we show the tooltip and change the content of the tooltip.

mouseout is used to hide the tooltip once the mouse is out of the Element.

mousemove is used to move the tooltip with the mouse.

d3.select('svg').selectAll('circle').data(data)
.join('circle')
.attr('r', 3)
.on('mouseover', function(e) {
})
.on('mouseout', function(e) {
})
.on('mousemove', function(e) {
})

Let‘s look first at the mouseover:

on('mouseover', function(d) {
d3.select('#tooltip').style('opacity', 1).text(d)
})

We‘re showing the tooltip element and setting the text to be the text of the data element that we‘re hovering over.
In our example, if we hover over the first element the tooltip would have a as its text.
You could even do it more smoothly using transition

on('mouseover', function(d) {
d3.select('#tooltip').transition().duration(200).style('opacity', 1).text(d)
})

What this will accomplish is, that the tooltip will fade in instead of appear right away.

Next up is the mouseout:

on('mouseout', function() {
d3.select('#tooltip').style('opacity', 0)
})

We‘re going to hide the tooltip once we leave that element.

And finally (which is optional) we look at mousemove:

on('mousemove', function() {
d3.select('#tooltip')
.style('left', d3.event.pageX + 'px')
.style('top', d3.event.pageY + 'px')
})

On the mousemove event we change the position of the tooltip to follow the mouse. Sometimes you want this, sometimes you don‘t. That‘s why it‘s optional. I usually add some padding to the position of the tooltip so that the cursor is not within the tooltip and the tooltip does not hide the element were looking at.

on('mousemove', function() {
d3.select('#tooltip')
.style('left', (d3.event.pageX+10) + 'px')
.style('top', (d3.event.pageY+10) + 'px')
})

This is the complete code and you can see the result below. Play around with it. It is interactive!

See Also

SVG Basics for d3

Three basic elements of SVG you should know if you want to create maps with d3.