Comment ajouter une info-bulle à un graphique svg?

92

J'ai une série de rectangles svg (en utilisant D3.js) et je veux afficher un message au survol de la souris, le message doit être entouré d'une boîte qui sert d'arrière-plan. Ils doivent tous deux être parfaitement alignés entre eux et avec le rectangle (en haut et centrés). Quelle est la meilleure façon de procéder?

J'ai essayé d'ajouter un texte svg en utilisant les attributs «x», «y», «width» et «height», puis en ajoutant un svg rect. Le problème est que le point de référence pour le texte est au milieu (puisque je veux qu'il soit centré, j'ai utilisé text-anchor: middle), mais pour le rectangle, c'est la coordonnée en haut à gauche, plus je voulais un peu de marge autour du texte, ce qui le rend un peu une douleur.

L'autre option utilisait un div html, ce qui serait bien, car je peux ajouter le texte et le remplissage directement mais je ne sais pas comment obtenir les coordonnées absolues de chaque rectangle. Y a-t-il un moyen de faire cela?

nachocab
la source
S'il n'y a pas d'autre moyen, je suppose
nachocab
Est-ce un problème d'utiliser le balisage pour ce pour quoi il a été conçu?
Phrogz
C'est juste que ça n'a pas l'air aussi beau, mais j'apprécie ta réponse
nachocab

Réponses:

175

Pouvez-vous utiliser simplement l' élément SVG<title> et le navigateur par défaut qui le rend? (Remarque: ce n'est pas le même que l' titleattribut que vous pouvez utiliser sur div / img / spans en html, il doit s'agir d'un élément enfant nommé 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>

Alternativement, si vous voulez vraiment afficher du HTML dans votre SVG, vous pouvez incorporer du HTML directement:

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>

… Mais alors vous auriez besoin de JS pour allumer et éteindre l'affichage. Comme indiqué ci-dessus, une façon de faire apparaître l'étiquette au bon endroit consiste à envelopper le rect et le HTML de la même manière <g>qui les positionne tous les deux ensemble.

Pour utiliser JS pour trouver où se trouve un élément SVG à l'écran, vous pouvez utiliser getBoundingClientRect(), par exemple http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

Phrogz
la source
Fonctionne bien pour moi d'insérer un titre dans un élément svg!
Shivam Aggarwal
2
Bonne réponse. Mais veuillez noter que ce foreignObject n'est pas pris en charge dans Internet Explorer
Rehban Khatri
Sur Firefox, le SVG a la taille 0x0? Il semble que vous deviez spécifier la largeur et la hauteur comme<rect width="200" height="50"></rect>
Franklin Yu
2
N'a malheureusement <title>aucun effet sur les appareils mobiles.
jengeb
Lorsque j'essaie d'ajouter le titre en utilisant js et en ajoutant le titre en tant qu'élément enfant. L'info-bulle n'apparaît pas: (
Ankur Marwaha
36

Le seul bon moyen que j'ai trouvé était d'utiliser Javascript pour déplacer une info-bulle <div>. De toute évidence, cela ne fonctionne que si vous avez SVG dans un document HTML - pas autonome. Et cela nécessite 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
la source
3

J'utilise toujours le titre css générique avec ma configuration. Je ne fais que créer des analyses pour la page d'administration de mon blog. Je n'ai besoin de rien d'extraordinaire. Voici un 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);

Et une capture d'écran de chrome ...

entrez la description de l'image ici

VocoJax
la source
0

J'ai trouvé quelque chose en utilisant uniquement HTML + CSS. J'espère que ça marche pour toi

.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>

mhdi
la source