public
Last active

Simple D3 tooltip

  • Download Gist
index.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
<!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>

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

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

I see. Thanks for the 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.

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.

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);
        });

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.

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

@Caged Thanks! this is really helpful +1

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");

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.