【问题标题】:How to add a tooltip to an svg graphic?如何将工具提示添加到 svg 图形?
【发布时间】:2025-12-09 19:40:01
【问题描述】:

我有一系列 svg 矩形(使用 D3.js),我想在鼠标悬停时显示一条消息,该消息应该被一个用作背景的框包围。它们都应该彼此完美对齐,并与矩形(顶部和居中)对齐。最好的方法是什么?

我尝试使用“x”、“y”、“width”和“height”属性添加 svg 文本,然后添加 svg rect。问题是文本的参考点在中间(因为我希望它居中对齐,所以我使用了text-anchor: middle),但对于矩形,它是左上角坐标,加上我想要在文本周围留一点边距,这使得有点痛。

另一个选项是使用 html div,这很好,因为我可以直接添加文本和填充,但我不知道如何获取每个矩形的绝对坐标。有没有办法做到这一点?

【问题讨论】:

  • 如果没有别的办法,我猜
  • 这是个问题吗,为它的设计目的使用标记?
  • 只是看起来不太好看,不过很感谢你的回答

标签: javascript svg d3.js tooltip


【解决方案1】:

你能简单地使用SVG <title> element 和它所传达的默认浏览器渲染吗? (注意:这与您可以在 html 中的 div/img/spans 上使用的 title 属性相同,它需要是一个名为 @987654326 的子 元素 @)

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>

或者,如果你真的想在你的 SVG 中显示 HTML,你可以直接嵌入 HTML:

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>

...但是你需要 JS 来打开和关闭显示。如上所示,使标签出现在正确位置的一种方法是将 rect 和 HTML 包装在同一个 &lt;g&gt; 中,将它们放在一起。

要使用 JS 查找 SVG 元素在屏幕上的位置,您可以使用 getBoundingClientRect(),例如http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

【讨论】:

  • 非常适合我将标题插入 svg 元素!
  • 不错的答案。但请注意foreignObjectis not supported in Internet Explorer
  • 在 Firefox 上,SVG 的大小为 0x0?似乎您必须指定宽度和高度,例如&lt;rect width="200" height="50"&gt;&lt;/rect&gt;
  • 很遗憾&lt;title&gt; 对移动设备没有影响。
  • 我在 Chrome 80 中看不到您的第二个示例的任何工具提示
【解决方案2】:

我发现的唯一好方法是使用 Javascript 移动工具提示 &lt;div&gt;。显然,这只有在 HTML 文档中有 SVG 时才有效——不是独立的。而且它需要 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>

【讨论】:

    【解决方案3】:

    您可以按照 Phrogz 的说明使用 title 元素。还有一些不错的工具提示,例如 jQuery 的 Tipsy http://onehackoranother.com/projects/jquery/tipsy/(可用于替换所有标题元素)、Bob Monteverde 的 nvd3 甚至 Twitter 的 Bootstrap 中的工具提示 http://twitter.github.com/bootstrap/

    【讨论】:

      【解决方案4】:

      在svg上,标题的正确写法

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

      点击这里了解更多详情https://css-tricks.com/svg-title-vs-html-title-attribute/

      【讨论】:

        【解决方案5】:

        我的设置总是使用通用的 CSS 标题。我只是为我的博客管理页面构建分析。我不需要任何花哨的东西。这是一些代码...

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

        还有chrome的截图……

        【讨论】:

          【解决方案6】:

          我想出了一些只使用 HTML + CSS 的东西。希望对你有用

          .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;
          }
          &lt;div class="mzhrttltp"&gt;&lt;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"&gt;&lt;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"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;div class="hrttltptxt"&gt;علاقه&amp;zwnj;مندی&amp;zwnj;ها&lt;/div&gt;&lt;/div&gt;

          【讨论】: