Skip to content

Instantly share code, notes, and snippets.

@biovisualize
Created June 9, 2011 14:42
Show Gist options
  • Save biovisualize/1016860 to your computer and use it in GitHub Desktop.
Save biovisualize/1016860 to your computer and use it in GitHub Desktop.
Simple D3 tooltip
<!DOCTYPE html>
<html >
<head>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
</head>
<body>
<div class="example_div"></div>
<script type="text/javascript">
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
var sampleSVG = d3.select(".example_div")
.append("svg:svg")
.attr("class", "sample")
.attr("width", 300)
.attr("height", 300);
d3.select(".example_div svg")
.append("svg:circle")
.attr("stroke", "black")
.attr("fill", "aliceblue")
.attr("r", 50)
.attr("cx", 52)
.attr("cy", 52)
.on("mouseover", function(){return tooltip.style("visibility", "visible");})
.on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
</script>
</body>
</html>
@ilyabo
Copy link

ilyabo commented Nov 4, 2011

Another way is to use the SVG title element: https://gist.github.com/1339996

@biovisualize
Copy link
Author

Yes, but the SVG specification leaves it to the user agent to provide the title element as a tooltip ( http://www.w3.org/TR/2000/CR-SVG-20001102/struct.html#DescriptionAndTitleElements ). It is not meant to be. And that's why it's often non-existant, is not stylable, can appear out of the window, etc. But it's simpler to use and be can controlled with plugins. There's a discussion about the title attribute here: https://groups.google.com/d/topic/d3-js/gii2ZTS-BDM/discussion

@ilyabo
Copy link

ilyabo commented Nov 4, 2011

I see. Thanks for the link!

@pixeline
Copy link

Nice!
It would be awesome if the tooltip would reposition itself if the mouse is close to a border. I 'll have a go at it and send you a patch.

@biovisualize
Copy link
Author

I use this old barebone code example as a template to build more sophisticated one. I can integrate your patch and share a reusable version soon.

@pixeline
Copy link

Here it is (Note that i'm using jquery here).

    function positionTooltip(mouse, scene, tooltip)
    {
        //Distance of element from the right edge of viewport
        if (scene.width - (mouse.x + tooltip.width) < 20)
        { //If tooltip exceeds the X coordinate of viewport
            mouse.x = mouse.x - tooltip.width - 20;
        }
        //Distance of element from the bottom of viewport
        if (scene.height - (mouse.y + tooltip.height) < 20)
        { //If tooltip exceeds the Y coordinate of viewport
            mouse.y = mouse.y - tooltip.height - 20;
        }
        return {
            top: mouse.y,
            left: mouse.x
        };
    }

usage:

// Early in the code
    var w = $(window).width();
    var h = $(window).height();
    var margin = {
        x: 10,
        y: 10
    };
    var padding = {
        x: 10,
        y: 10
    };
var tooltip = {
        width: $('.tooltip').width(),
        height: $('.tooltip').height(),
    }
    var scene = {
        x: margin.x + padding.x,
        y: margin.y + padding.y,
        width: w - (margin.x * 2) - (padding.x * 2),
        height: h - (margin.y * 2) - (padding.y * 2)
    }

// then, when defining the tooltip div events...

.on("mouseover", function(d)
        {
            div.transition().duration(200).style("opacity", 1);
            //div.html(popupHtml(d)).style("left", (d3.event.pageX + 10) + "px").style("top", (d3.event.pageY - 10) + "px");
            div.html(popupHtml(d)).style("left", function()
            {
                var pos = positionTooltip(
                {
                    x: d3.event.pageX,
                    y: d3.event.pageY
                }, scene, tooltip);
                return (pos.left + 10) + 'px';
            }).style("top", function()
            {
                var pos = positionTooltip(
                {
                    x: d3.event.pageX,
                    y: d3.event.pageY
                }, scene, tooltip);
                return (pos.top - 10) + 'px';
            });
        }).on("mousemove", function(d)
        {
            //div.style("left", (d3.event.pageX + 10) + "px").style("top", (d3.event.pageY - 10) + "px");
            div.style("left", function()
            {
                var pos = positionTooltip(
                {
                    x: d3.event.pageX,
                    y: d3.event.pageY
                }, scene, tooltip);
                return (pos.left + 10) + 'px';
            }).style("top", function()
            {
                var pos = positionTooltip(
                {
                    x: d3.event.pageX,
                    y: d3.event.pageY
                }, scene, tooltip);
                return (pos.top - 10) + 'px';
            });
        }).on("mouseout", function(d)
        {
            div.transition().duration(500).style("opacity", 0);
        });

@Letty
Copy link

Letty commented Jul 24, 2013

Nice example. But if you try this on firefox your tooltip is under the circle. You should change event.page to d3.event.pageX/Y like in the example from pixeline.

@caged
Copy link

caged commented Sep 10, 2013

I've created a simple library for dealing with tooltips in d3 if anyone is interested.

@deanmalmgren
Copy link

@caged Thanks! this is really helpful +1

@cazzer
Copy link

cazzer commented Dec 3, 2013

If anyone else is getting event is not defined or similar add d3. to the events:

return tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");

@nileshtrivedi
Copy link

svg:title does work as a tooltip in Firefox 37 and Chrome 42. That's good enough for me! :)

@srinivmw
Copy link

Can we apply anything instead of

    .style("left", (d3.event.pageX - 34) + "px")
    .style("top", (d3.event.pageY - 12) + "px"); 

because when i use this the tooltip is not displaying in its position correctly.....

Below two things also not working:
1)

      .style("left", d3.select(this).attr("cx") + "px")     
      .style("top", d3.select(this).attr("cy") + "px");
       .style("left", dx + "px")     
  .style("top", dy + "px");

Can i have good solution for this?

@billwestfall
Copy link

brilliant and simple, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment