Jak dodać podpowiedź do grafiki SVG?

92

Mam serię prostokątów svg (używając D3.js) i chcę wyświetlić komunikat po najechaniu myszą, wiadomość powinna być otoczona ramką, która działa jako tło. Powinny być idealnie wyrównane względem siebie i prostokąta (na górze i na środku). Jaki jest najlepszy sposób, aby to zrobić?

Próbowałem dodać tekst svg, używając atrybutów „x”, „y”, „szerokość” i „wysokość”, a następnie wstawiłem na początku prostokąt svg. Problem polega na tym, że punkt odniesienia dla tekstu znajduje się pośrodku (ponieważ chcę, aby był wyśrodkowany, użyłem text-anchor: middle), ale dla prostokąta jest to współrzędna górna lewa, plus chciałem trochę marginesu wokół tekstu, co sprawia, że ​​jest trochę ból.

Inną opcją było użycie elementu div html, co byłoby fajne, ponieważ mogę bezpośrednio dodać tekst i wypełnienie, ale nie wiem, jak uzyskać bezwzględne współrzędne dla każdego prostokąta. Czy jest na to sposób?

nachocab
źródło
Jeśli nie ma innego wyjścia, jak sądzę
nachocab
Czy to problem, używając znaczników do tego, do czego został zaprojektowany?
Phrogz
Po prostu nie wygląda to tak ładnie, ale doceniam twoją odpowiedź
nachocab

Odpowiedzi:

175

Czy możesz użyć po prostu elementu SVG<title> i domyślnej przeglądarki, którą on przekazuje? (Uwaga: to nie to samo, co titleatrybut, którego możesz użyć w div / img / spans w html, musi to być element podrzędny o nazwie 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>

Alternatywnie, jeśli naprawdę chcesz wyświetlić HTML w swoim SVG, możesz bezpośrednio osadzić 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>

… Ale wtedy do włączania i wyłączania wyświetlacza potrzebny byłby JS. Jak pokazano powyżej, jednym ze sposobów umieszczenia etykiety we właściwym miejscu jest umieszczenie prostego i HTML w tym samym <g>miejscu, które ustawia je razem.

Aby użyć JS do znalezienia, gdzie na ekranie znajduje się element SVG, możesz użyć getBoundingClientRect()np. Http://phrogz.net/svg/html_location_in_svg_in_html.xhtml

Phrogz
źródło
Dobrze mi pasuje wstawianie tytułu do elementu svg!
Shivam Aggarwal
2
Niezła odpowiedź. Należy jednak pamiętać, że foreignObject nie jest to obsługiwane w przeglądarce Internet Explorer
Rehban Khatri
W przeglądarce Firefox plik SVG ma rozmiar 0x0? Wygląda na to, że musisz określić szerokość i wysokość, na przykład<rect width="200" height="50"></rect>
Franklin Yu
2
Niestety <title>nie ma to wpływu na urządzenia mobilne.
jengeb
Kiedy próbuję dodać tytuł za pomocą js i dołączając tytuł jako element podrzędny. Opis się nie pojawia :(
Ankur Marwaha,
36

Jedynym dobrym sposobem, jaki znalazłem, było użycie Javascript do przesuwania podpowiedzi <div>. Oczywiście działa to tylko wtedy, gdy w dokumencie HTML znajduje się SVG - a nie samodzielny. I wymaga 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
źródło
3

Zawsze używam ogólnego tytułu CSS w mojej konfiguracji. Po prostu tworzę statystyki dla mojej strony administratora bloga. Nie potrzebuję niczego wymyślnego. Oto kod ...

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

I zrzut ekranu z chrome ...

wprowadź opis obrazu tutaj

VocoJax
źródło
0

Wymyśliłem coś, używając tylko HTML + CSS. Mam nadzieję, że to działa dla Ciebie

.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
źródło