Wie füge ich einer SVG-Grafik einen Tooltip hinzu?

87

Ich habe eine Reihe von SVG-Rechtecken (mit D3.js) und möchte beim Mouseover eine Nachricht anzeigen. Die Nachricht sollte von einem Feld umgeben sein, das als Hintergrund dient. Sie sollten beide perfekt zueinander und zum Rechteck (oben und zentriert) ausgerichtet sein. Was ist der beste Weg, dies zu tun?

Ich habe versucht, einen SVG-Text mit den Attributen "x", "y", "width" und "height" hinzuzufügen und dann ein SVG-Rechteck voranzustellen. Das Problem ist, dass der Referenzpunkt für den Text in der Mitte liegt (da ich möchte, dass er zentriert ausgerichtet ist, was ich verwendet habe text-anchor: middle), aber für das Rechteck ist es die obere linke Koordinate, und ich wollte einen kleinen Rand um den Text, der ihn irgendwie macht ein Schmerz.

Die andere Option war die Verwendung eines HTML-Div, was sehr schön wäre, da ich den Text und den Abstand direkt hinzufügen kann, aber nicht weiß, wie ich die absoluten Koordinaten für jedes Rechteck ermitteln kann. Gibt es eine Möglichkeit, dies zu tun?

Nachocab
quelle
Wenn es keinen anderen Weg gibt, denke ich
Nachocab
Ist das ein Problem, Markup für das zu verwenden, wofür es entwickelt wurde?
Phrogz
Es ist nur so, dass es nicht so schön aussieht, aber ich schätze Ihre Antwort
Nachocab

Antworten:

166

Können Sie einfach das SVG- <title>Element und das Standard-Browser-Rendering verwenden, das es vermittelt? (Hinweis: Dies ist nicht dasselbe wie das titleAttribut, das Sie für div / img / spans in HTML verwenden können. Es muss ein untergeordnetes Element mit dem Namen sein. 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>

Wenn Sie HTML wirklich in Ihrem SVG anzeigen möchten, können Sie HTML direkt einbetten:

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>

… Aber dann brauchen Sie JS, um das Display ein- und auszuschalten. Wie oben gezeigt, besteht eine Möglichkeit, das Etikett an der richtigen Stelle erscheinen zu lassen, darin, das Rect und das HTML in dasselbe zu verpacken, das <g>beide zusammen positioniert.

Um mithilfe von JS zu ermitteln, wo sich ein SVG-Element auf dem Bildschirm befindet, können Sie getBoundingClientRect()beispielsweise http://phrogz.net/svg/html_location_in_svg_in_html.xhtml verwenden

Phrogz
quelle
Funktioniert gut für mich, um Titel in ein SVG-Element einzufügen!
Shivam Aggarwal
2
Gute Antwort. Aber bitte beachten Sie, dass foreignObject in Internet Explorer
Rehban Khatri
Auf Firefox hat die SVG Größe 0x0? Es scheint, als müssten Sie Breite und Höhe angeben wie<rect width="200" height="50"></rect>
Franklin Yu
1
Hat leider <title>keine Auswirkungen auf mobile Geräte.
Jengeb
Wenn ich versuche, den Titel mit js hinzuzufügen und den Titel als untergeordnetes Element anzuhängen. Der Tooltip erscheint nicht :(
Ankur Marwaha
32

Der einzige gute Weg, den ich gefunden habe, war die Verwendung von Javascript, um einen Tooltip zu verschieben <div>. Dies funktioniert natürlich nur, wenn Sie SVG in einem HTML-Dokument haben - nicht eigenständig. Und es erfordert 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>

Timmmm
quelle
3

Ich gehe bei meinem Setup immer mit dem generischen CSS-Titel um. Ich erstelle gerade Analysen für meine Blog-Administrationsseite. Ich brauche nichts Besonderes. Hier ist ein 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);

Und ein Screenshot von Chrom ...

Geben Sie hier die Bildbeschreibung ein

VocoJax
quelle