web-dev-qa-db-fra.com

Comment ajouter une info-bulle à un graphique svg?

J'ai une série de rectangles svg (à l'aide de D3.js) et je souhaite afficher un message au passage de la souris, le message doit être entouré d'un champ servant d'arrière-plan. Ils doivent tous deux être parfaitement alignés l'un sur l'autre et sur le rectangle (supérieur et centré). 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 du texte est au milieu (étant donné que je veux le centrer, j’ai utilisé text-anchor: middle), mais pour le rectangle, il s’agit de la coordonnée en haut à gauche. De plus, je voulais un peu de marge autour du texte, ce qui en fait un peu pénible.

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?

79
nachocab

Vous pouvez utiliser l'élément title comme indiqué par Phrogz. Il existe également de bonnes infobulles, telles que Tipsy de jQuery http://onehackoranother.com/projects/jquery/tipsy/ (qui peut remplacer tous les titres). éléments), le nvd3 de Bob Monteverde ou même l'infobulle de Twitter de leur Bootstrap http://Twitter.github.com/bootstrap/

12
paxRoman

Pouvez-vous utiliser simplement l'élément SVG <title> et le navigateur par défaut le rendant? (Remarque: ceci est pas identique à l'attribut title que vous pouvez utiliser sur div/img/spans en html, il doit être un enfant élément 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>

Sinon, si vous voulez vraiment afficher du HTML dans votre SVG, vous pouvez incorporer directement du 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>

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

Pour utiliser JS afin de localiser un élément SVG à l'écran, vous pouvez utiliser getBoundingClientRect(), par exemple. http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

134
Phrogz

Le seul bon moyen que j’ai trouvé est d’utiliser Javascript pour déplacer une info-bulle <div> environ. Évidemment, 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>
14
Timmmm

Je vais toujours avec le titre générique css avec ma configuration. Je suis en train de construire des analyses pour la page d'administration de mon blog. Je n'ai besoin de rien d'extraordinaire. Voici du 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 ...

enter image description here

1
VocoJax