How to add a tooltip to an svg graphic?

JavascriptSvgd3.jsTooltip

Javascript Problem Overview


I have a series of svg rectangles (using D3.js) and I want to display a message on mouseover, the message should be surrounded by a box that acts as background. They should both be perfectly aligned to each other and to the rectangle (on top and centered). What is the best way to do this?

I tried adding an svg text using the "x", "y", "width" and "height" attributes, and then prepending an svg rect. The problem is that the reference point for the text is in the middle (since I want it centered aligned I used text-anchor: middle), but for the rectangle it's the top left coordinate, plus I wanted a bit of margin around the text which makes it kind of a pain.

The other option was using an html div, which would be nice, because I can add the text and padding directly but I don't know how to get the absolute coordinates for each rectangle. Is there a way to do this?

Javascript Solutions


Solution 1 - Javascript

Can you use simply the SVG <title> element and the default browser rendering it conveys? (Note: this is not the same as the title attribute you can use on div/img/spans in html, it needs to be a child element named title)

rect {
  width: 100%;
  height: 100%;
  fill: #69c;
  stroke: #069;
  stroke-width: 5px;
  opacity: 0.5
}

<p>Mouseover the rect to see the tooltip on supporting browsers.</p>

<svg xmlns="http://www.w3.org/2000/svg">
  <rect>
    <title>Hello, World!</title>
  </rect>
</svg>

Alternatively, if you really want to show HTML in your SVG, you can embed HTML directly:

rect {
  width: 100%;
  height: 100%;
  fill: #69c;
  stroke: #069;
  stroke-width: 5px;
  opacity: 0.5
}

foreignObject {
  width: 100%;
}

svg div {
  text-align: center;
  line-height: 150px;
}

<svg xmlns="http://www.w3.org/2000/svg">
  <rect/>
  <foreignObject>
    <body xmlns="http://www.w3.org/1999/xhtml">
      <div>
        Hello, <b>World</b>!
      </div>
    </body>      
  </foreignObject>
</svg>

…but then you'd need JS to turn the display on and off. As shown above, one way to make the label appear at the right spot is to wrap the rect and HTML in the same <g> that positions them both together.

To use JS to find where an SVG element is on screen, you can use getBoundingClientRect(), e.g. http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

Solution 2 - Javascript

The only good way I found was to use Javascript to move a tooltip <div> around. Obviously this only works if you have SVG inside an HTML document - not standalone. And it requires Javascript.

function showTooltip(evt, text) {
  let tooltip = document.getElementById("tooltip");
  tooltip.innerHTML = text;
  tooltip.style.display = "block";
  tooltip.style.left = evt.pageX + 10 + 'px';
  tooltip.style.top = evt.pageY + 10 + 'px';
}

function hideTooltip() {
  var tooltip = document.getElementById("tooltip");
  tooltip.style.display = "none";
}

#tooltip {
  background: cornsilk;
  border: 1px solid black;
  border-radius: 5px;
  padding: 5px;
}

<div id="tooltip" display="none" style="position: absolute; display: none;"></div>

<svg>
  <rect width="100" height="50" style="fill: blue;" onmousemove="showTooltip(evt, 'This is blue');" onmouseout="hideTooltip();" >
  </rect>
</svg>

Solution 3 - Javascript

You can use the title element as Phrogz indicated. There are also some good tooltips like jQuery's Tipsy http://onehackoranother.com/projects/jquery/tipsy/ (which can be used to replace all title elements), Bob Monteverde's nvd3 or even the Twitter's tooltip from their Bootstrap http://twitter.github.com/bootstrap/

Solution 4 - Javascript

On svg, the right way to write the title

<svg>
  <title id="unique-id">Checkout</title>
</svg>

check here for more details https://css-tricks.com/svg-title-vs-html-title-attribute/

Solution 5 - Javascript

I came up with something using HTML + CSS only. Hope it works for you

.mzhrttltp {
  position: relative;
  display: inline-block;
}
.mzhrttltp .hrttltptxt {
  visibility: hidden;
  width: 120px;
  background-color: #040505;
  font-size:13px;color:#fff;font-family:IranYekanWeb;
  text-align: center;
  border-radius: 3px;
  padding: 4px 0;
  position: absolute;
  z-index: 1;
  top: 105%;
  left: 50%;
  margin-left: -60px;
}

.mzhrttltp .hrttltptxt::after {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: transparent transparent #040505 transparent;
}

.mzhrttltp:hover .hrttltptxt {
  visibility: visible;
}

<div class="mzhrttltp"><svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 24 24" fill="none" stroke="#e2062c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg><div class="hrttltptxt">علاقه&zwnj;مندی&zwnj;ها</div></div>

Solution 6 - Javascript

I always go with the generic css title with my setup. I'm just building analytics for my blog admin page. I don't need anything fancy. Here's some code...

let comps = g.selectAll('.myClass')
   .data(data)
   .enter()
   .append('rect')
   ...styling...
   ...transitions...
   ...whatever...

g.selectAll('.myClass')
   .append('svg:title')
   .text((d, i) => d.name + '-' + i);

And a screenshot of chrome...

enter image description here

Solution 7 - Javascript

I use heroicons for the project I am working on. (This is JSX format) I will handle the tooltip issue with this code.

<svg className="h-6 w-6">
        <title>{reasons.join(" ")}</title>
        <QuestionMarkCircleIcon className={style} />
      </svg>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnachocabView Question on Stackoverflow
Solution 1 - JavascriptPhrogzView Answer on Stackoverflow
Solution 2 - JavascriptTimmmmView Answer on Stackoverflow
Solution 3 - JavascriptpaxRomanView Answer on Stackoverflow
Solution 4 - JavascriptImtiaz PabelView Answer on Stackoverflow
Solution 5 - JavascriptmhdiView Answer on Stackoverflow
Solution 6 - JavascriptVocoJaxView Answer on Stackoverflow
Solution 7 - JavascriptGünay GültekinView Answer on Stackoverflow