Tooltip

After writing a general SVG mouseover post, I thought I'd write a more specific tutorial, describing how to use the mouseover effect to achieve something useful: mouseover text, otherwise known as a tooltip. I've tested the result in Chrome and Firefox. As I've mentioned before Internet Explore (before IE9) doesn't support SVGs at all.

You can view the code for any of SVG examples by right clicking on the image and selecting View Frame Source (or something similar). Alternatively, I've attached all the SVGs at the bottom of this post so you can download them.

1. Getting Started

As usual, we'll start with two passive squares.

The first step is to add the text, which should be added to the end of the SVG, after all the other elements, so it will be drawn on top of them:

<text class="tooltip" id="tooltip"
      x="0" y="0" visibility="hidden">Tooltip</text>

The text reads 'Tooltip' and is currently positioned at coordinates (0,0), though the position is unimportant as the text is hidden. I've given the text element the id "tooltip" which allows us to select it easily; I've also set its class to "tooltip", which will make it easy to style with CSS later.

2. Selecting the Tooltip Element

In order to change the position and visibility of the tooltip <text> element, we have to be able to refer to it. We can refer to it using getElementById but before that we need to be able to refer to the SVG document itself. We do this by calling a function at the beginning of the SVG. The function, init, defines a variable for the SVG itself, which allows us to get elements within it (such as the tooltip text) by their ID. This function goes within a <script> element and within CDATA[ ] brackets. I've written more about SVG scripting here.

<script type="text/ecmascript">
<![CDATA[
  function init(evt)
  {
    if ( window.svgDocument == null )
    {
      svgDocument = evt.target.ownerDocument;
    }
    tooltip = svgDocument.getElementById('tooltip');
  }
]]></script>

Now we add the onload event into the <SVG> element (last line below).

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="80"
onload="init(evt)">

3. Displaying the tooltip

Now we have a tooltip variable, we can alter the tooltip text element's properties when we mouseover other objects. Within the CDATA, we define two functions: ShowTooltip to make the tooltip text visible and to position it correctly relative to the mouse, and HideTooltip to hide it again. We use evt.clientX and evt.clientY to get the current position of the cursor within the browser, then set to the tooltip's x, and y positions relative to this. You can play around with the position, unfortunately, it depends a lot on your browser and screen resolution as to how it looks.

function ShowTooltip(evt)
{
  tooltip.setAttributeNS(null,"x",evt.clientX-8);
  tooltip.setAttributeNS(null,"y",evt.clientY-5);
  tooltip.setAttributeNS(null,"visibility","visible");
}

function HideTooltip()
{
  tooltip.setAttributeNS(null,"visibility","hidden");
}

We can now add the tooltip effect to any SVG element, such as our two passive boxes. For example:

<rect id="rect1" x="160" y="10"
   width="60" height="60" fill="blue"
   onmousemove="ShowTooltip(evt)"
    onmouseout="HideTooltip()"/>

Note that I've used onmousemove rather than onmouseover so the position of the text is constantly updated.

After adding the function calls to both boxes, the final result should look something like this:

4. Changing the tooltip text

It's not very useful to display the same text no matter which element is mouseovered. We change the text by changing firstChild.data. For example, we can change the mouseover text to display the colour of the square:

tooltip.firstChild.data = evt.target.getAttributeNS(null,"fill") + " square";

This method works when you want the mouseover text to display an attribute of elements, but often this won't be the case. For more complex cases, we can change the ShowTooltip function to take a second parameter, the tooltip text:

function ShowTooltip(evt, mouseovertext)
{
  tooltip.setAttributeNS(null,"x",evt.clientX+11);
  tooltip.setAttributeNS(null,"y",evt.clientY+27);
  tooltip.firstChild.data = mouseovertext;
  tooltip.setAttributeNS(null,"visibility","visible");
}

And then change the function calls as required:

onmousemove="ShowTooltip(evt, 'Left box')"
onmousemove="ShowTooltip(evt, 'Right box')"

We might as well style the text now too with a bit of CSS:

<style>
  .tooltip{
    font-size: 12px;
  }
</style>

The result of all this should be something like this:

5. Adding a background

Since it's hard to read the mouseover text on dark backgrounds, such as the blue box, it makes sense to display the text in its own box. We can add a box in the same way we added the text. First we add a <rect> element just before the tooltip <text> element so it's drawn on top of all the elements except the text:

<rect class="tooltip_bg" id="tooltip_bg"
 x="0" y="0" rx="4" ry="4"
 width="52" height="16" visibility="hidden"/>

As before, I've included an class so we can style the box and an id so we can easily select it. The rx and ry values give the rectangle rounded corners.

Then we select the <rect> in the init function:

tooltip_bg = svgDocument.getElementById('tooltip_bg');

And then change its visibility and position in the ShowTooltip and HideTooltip functions:

tooltip_bg.setAttributeNS(null,"x",evt.clientX+8);
tooltip_bg.setAttributeNS(null,"y",evt.clientY+16);
tooltip_bg.setAttributeNS(null,"visibility","visible");
tooltip_bg.setAttributeNS(null,"visibility","hidden");

Finally you can style the box however you like using CSS. For example:

.tooltip_bg{
  fill: white;
  stroke: black;
  stroke-width: 1;
  opacity: 0.85;
}

Which will create a tooltip that looks like this:

7. Changing the tooltip length

As it stands, the width of the box is fixed, so if the tooltip text is too long it will go over the edges. To fix this we calculate the length of the tooltip text with getComputedTextLength() and use this to determine the width of the box:

length = tooltip.getComputedTextLength();
tooltip_bg.setAttributeNS(null,"width",length+8);

If you want multi-line mouseover text and word wrapping then that's more complex and requires multiple text elements. I'll leave that as an exercise for the reader.

AttachmentSize
svg_two_squares2.svg578 bytes
tooltip_colour.svg1.48 KB
tooltip_position.svg1.52 KB
tooltip_basic.svg1.4 KB
tooltip_bg.svg2.01 KB
tooltip_final.svg2.12 KB

Comments

Thank you, thank you, thank you.  Saved me a couple of hours finding all of the info I needed to do this.  I wish the Firefox SVG renderer would just show title elements as tooltips.  Goodness, how many years has it been?

Well thank you. I'm glad you found it helpful.

Dang! This is slick and was just what I needed for an SVG-based visualization I was working on.

(I'm glad I procrastinated on the project or I would have had to figure it out myself. :)

Hello Peter,

Thanks for all tutorials, really help me to work with svg. I would like to ask you about svg and android tablets. I know that only works on tablets that have honeycomb, right? is any difference with ipad? Do you know any website where find more information about svg and tablets?

 

Thanks

Viviana

Hi Viviana, I'm afraid I don't know anything about getting SVG to work on tablets, sorry. 

Note that if you are working with large SVG, lines 25 and 26 fail when the user scrolls the SVG/page. The tooltips would appear at the wrong place, depending how much the user scrolls even outside the current view.

Easiest way is to just use "evt.pageX" and "evt.pageY"  instead of clientX/clientY which take into account the scrolling but these may not be cross-browser compatible. There are sites that explain how to do this correctly.

Hi,

I'm having the problems that Ville Ojamo says, my tooltip is at the wrong place, I play around changing the values of clientX and clientY but the position is always the same, and far away from the cursor. I've tried changing also client by page, but nothing change.

Could someone help me with this please?

Thanks a lot

Another Great tutorial!! Many thanks

I sorted it out, I just put negative value on pageX and it worked.

Many thanks for this blog so helpful

Glad you managed to fix your problem Ichi. Ville is right about using pageX and pageY - I keep meaning to update the page.

Hi,

I am new in SVG, these tutorials are very helpful.

My problem is that when I am adding viewbox to svg i am loosing the tooltip:(

Thanks

 

Your tutorial is just GREAT - Thanks a lot!

Hi there is there a way to multipul tooptip boxes that have different colour stokes?

i am doing a task regarding SVG map and your tutorial seriously help me a lot.

thank you very much!

but i have a question, how can we change the tooltip information with image?

for example, it is a world map and when user mouse over at a country then a tooltip with the country's map will shown

Hi Amy,

What you'd have to do would be to draw the images off screen, and when the mouse goes over an area, select the right image and move its display in the same way the tooltip background is moved into place.

Great! That's exactly what I was looking for.

Thank You!

Hi,

Its great and I found what I want but can u tell me how dynamic data show on a mouse move .

i have a problem ; when i point in my map.svg the viewbox  far away from the cursor  ;and i don't understand what does 't mean Ichi.  please give me a script  or any exemple .

Hi

This guide is excellent but I need the tooltip data from a php scripts

Thank

Post new comment

The content of this field is kept private and will not be shown publicly.