Como adicionar uma dica de ferramenta a um gráfico SVG?

89

Eu tenho uma série de retângulos SVG (usando D3.js) e quero exibir uma mensagem ao passar o mouse, a mensagem deve estar cercada por uma caixa que atua como plano de fundo. Eles devem estar perfeitamente alinhados entre si e com o retângulo (na parte superior e centralizado). Qual é a melhor maneira de fazer isso?

Tentei adicionar um texto svg usando os atributos "x", "y", "largura" e "altura" e, em seguida, prefixar um rect svg. O problema é que o ponto de referência para o texto está no meio (já que eu o quero centralizado, usei text-anchor: middle), mas para o retângulo é a coordenada superior esquerda, além disso, eu queria um pouco de margem ao redor do texto, o que o torna meio uma dor.

A outra opção era usar um div html, o que seria bom, porque posso adicionar o texto e o preenchimento diretamente, mas não sei como obter as coordenadas absolutas de cada retângulo. Existe uma maneira de fazer isso?

nachocab
fonte
Se não houver outra maneira, eu acho
nachocab
Isso é um problema, usar marcação para o que foi projetado?
Phrogz
É que não parece tão bom, mas agradeço sua resposta
nachocab

Respostas:

169

Você pode usar simplesmente o elemento SVG<title> e a renderização do navegador padrão que ele transmite? (Nota: este não é o mesmo que o titleatributo que você pode usar em div / img / spans em html, ele precisa ser um elemento filho chamado 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>

Como alternativa, se você realmente deseja mostrar HTML em seu SVG, pode incorporar HTML diretamente:

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>

... mas então você precisaria de JS para ligar e desligar a tela. Como mostrado acima, uma maneira de fazer o rótulo aparecer no lugar certo é envolver o retângulo e o HTML na mesma <g>posição que os posiciona juntos.

Para usar JS para descobrir onde um elemento SVG está na tela, você pode usar getBoundingClientRect(), por exemplo, http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

Phrogz
fonte
Funciona bem para inserir um título em um elemento SVG!
Shivam Aggarwal
2
Boa resposta. Mas observe que foreignObject não é compatível com Internet Explorer
Rehban Khatri
No Firefox, o SVG tem tamanho 0x0? Parece que você precisa especificar a largura e a altura, como<rect width="200" height="50"></rect>
Franklin Yu
1
Infelizmente <title>não tem efeito em dispositivos móveis.
jengeb,
Quando estou tentando adicionar o título usando js e anexando título como o elemento filho. A dica de ferramenta não está aparecendo :(
Ankur Marwaha
32

A única maneira boa que encontrei foi usar Javascript para mover uma dica de ferramenta <div>. Obviamente, isso só funciona se você tiver SVG dentro de um documento HTML - não autônomo. E requer 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
fonte
3

Eu sempre uso o título css genérico com minha configuração. Estou apenas criando análises para a página de administração do meu blog. Eu não preciso de nada sofisticado. Aqui está um 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);

E uma captura de tela do cromo ...

insira a descrição da imagem aqui

VocoJax
fonte
0

Eu inventei algo usando apenas HTML + CSS. espero que funcione para você

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

Mahdi
fonte