¿Cómo agregar una información sobre herramientas a un gráfico svg?

92

Tengo una serie de rectángulos svg (usando D3.js) y quiero mostrar un mensaje al pasar el mouse, el mensaje debe estar rodeado por un cuadro que actúa como fondo. Ambos deben estar perfectamente alineados entre sí y con el rectángulo (arriba y centrado). ¿Cuál es la mejor manera de hacer esto?

Intenté agregar un texto svg usando los atributos "x", "y", "ancho" y "alto", y luego anteponiendo un rect svg. El problema es que el punto de referencia para el texto está en el medio (ya que lo quiero alineado centrado lo usé text-anchor: middle), pero para el rectángulo es la coordenada superior izquierda, además quería un poco de margen alrededor del texto, lo que lo convierte en una especie de un dolor.

La otra opción era usar un div html, lo cual sería bueno, porque puedo agregar el texto y el relleno directamente, pero no sé cómo obtener las coordenadas absolutas para cada rectángulo. ¿Hay alguna forma de hacer esto?

nachocab
fuente
Si no hay otra manera, supongo
nachocab
¿Es eso un problema, usar el marcado para lo que fue diseñado?
Phrogz
Es solo que no se ve tan bien, pero agradezco tu respuesta
nachocab

Respuestas:

175

¿Puede usar simplemente el elemento SVG<title> y la representación predeterminada del navegador que transmite? (Nota: esto no es lo mismo que el titleatributo que puede usar en div / img / spans en html, debe ser un elemento secundario llamado 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>

Alternativamente, si realmente desea mostrar HTML en su SVG, puede incrustar HTML directamente:

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>

… Pero luego necesitaría JS para encender y apagar la pantalla. Como se muestra arriba, una forma de hacer que la etiqueta aparezca en el lugar correcto es envolver el rect y el HTML en el mismo lugar <g>que los coloca a ambos juntos.

Para usar JS para encontrar dónde está un elemento SVG en la pantalla, puede usar getBoundingClientRect(), por ejemplo, http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

Phrogz
fuente
¡Me funciona muy bien para insertar el título en un elemento svg!
Shivam Aggarwal
2
Buena respuesta. Pero tenga en cuenta que foreignObject no es compatible con Internet Explorer
Rehban Khatri
En Firefox, ¿el SVG tiene un tamaño 0x0? Parece que tiene que especificar el ancho y la altura como<rect width="200" height="50"></rect>
Franklin Yu
2
Lamentablemente, <title>no tiene ningún efecto en los dispositivos móviles.
jengeb
Cuando intento agregar el título usando js y agregando el título como elemento secundario. La información sobre herramientas no aparece :(
Ankur Marwaha
36

La única buena forma que encontré fue usar Javascript para mover una información <div>sobre herramientas . Obviamente, esto solo funciona si tiene SVG dentro de un documento HTML, no de forma independiente. Y requiere 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
fuente
3

Siempre utilizo el título CSS genérico con mi configuración. Solo estoy construyendo análisis para la página de administración de mi blog. No necesito nada lujoso. Aquí hay un código ...

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

Y una captura de pantalla de Chrome ...

ingrese la descripción de la imagen aquí

VocoJax
fuente
0

Se me ocurrió algo usando solo HTML + CSS. Espero que funcione para ti

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