Alors voici ce que j'ai:
<path class="..." onmousemove="show_tooltip(event,'very long text
\\\n I would like to linebreak')" onmouseout="hide_tooltip()" d="..."/>
<rect class="tooltip_bg" id="tooltip_bg" ... />
<text class="tooltip" id="tooltip" ...>Tooltip</text>
<script>
<![CDATA[
function show_tooltip(e,text) {
var tt = document.getElementById('tooltip');
var bg = document.getElementById('tooltip_bg');
// set position ...
tt.textContent=text;
bg.setAttribute('width',tt.getBBox().width+10);
bg.setAttribute('height',tt.getBBox().height+6);
// set visibility ...
}
...
Maintenant, mon très long texte d'info-bulle n'a pas de saut de ligne, même si j'utilise alert (); cela me montre que le texte a réellement deux lignes. (Il contient cependant un "\", comment puis-je le supprimer?)
Je ne parviens pas à faire fonctionner CDATA n’importe où.
Ce n'est pas quelque chose que SVG 1.1 supporte. SVG 1.2 contient l’élément textArea
, avec le retour automatique à la ligne, mais il n’est pas implémenté dans tous les navigateurs. SVG 2 ne prévoit pas d'implémenter textArea
, mais il possède texte automatiquement mis en cache .
Cependant, étant donné que vous savez déjà où vos sauts de ligne doivent se produire, vous pouvez diviser votre texte en plusieurs <tspan>
s, chacun avec x="0"
et dy="1.4em"
pour simuler les lignes de texte réelles. Par exemple:
<g transform="translate(123 456)"><!-- replace with your target upper left corner coordinates -->
<text x="0" y="0">
<tspan x="0" dy="1.2em">very long text</tspan>
<tspan x="0" dy="1.2em">I would like to linebreak</tspan>
</text>
</g>
Bien sûr, comme vous voulez le faire à partir de JavaScript, vous devrez créer et insérer manuellement chaque élément dans le DOM.
Je suppose que vous avez déjà réussi à le résoudre, mais si quelqu'un recherche une solution similaire, cela fonctionne pour moi:
g.append('svg:text')
.attr('x', 0)
.attr('y', 30)
.attr('class', 'id')
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 5)
.text(function(d) { return d.name; })
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 20)
.text(function(d) { return d.sname; })
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 20)
.text(function(d) { return d.idcode; })
Il y a 3 lignes séparées par un saut de ligne.
Avec la solution tspan, disons que vous ne savez pas à l'avance où placer vos sauts de ligne: vous pouvez utiliser cette fonction Nice, que j'ai trouvée ici: http://bl.ocks.org/mbostock/7555321
Cela fait automatiquement les sauts de ligne pour le texte long svg pour une largeur donnée en pixel.
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
Word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (Word = words.pop()) {
line.Push(Word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [Word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(Word);
}
}
});
}
Je pense que cela fait ce que tu veux:
function ShowTooltip(evt, mouseovertext){
// Make tooltip text
var tooltip_text = tt.childNodes.item(1);
var words = mouseovertext.split("\\\n");
var max_length = 0;
for (var i=0; i<3; i++){
tooltip_text.childNodes.item(i).firstChild.data = i<words.length ? words[i] : " ";
length = tooltip_text.childNodes.item(i).getComputedTextLength();
if (length > max_length) {max_length = length;}
}
var x = evt.clientX + 14 + max_length/2;
var y = evt.clientY + 29;
tt.setAttributeNS(null,"transform", "translate(" + x + " " + y + ")")
// Make tooltip background
bg.setAttributeNS(null,"width", max_length+15);
bg.setAttributeNS(null,"height", words.length*15+6);
bg.setAttributeNS(null,"x",evt.clientX+8);
bg.setAttributeNS(null,"y",evt.clientY+14);
// Show everything
tt.setAttributeNS(null,"visibility","visible");
bg.setAttributeNS(null,"visibility","visible");
}
Il divise le texte sur \\\n
et pour chacun met chaque fragment dans une tspan. Ensuite, il calcule la taille de la boîte requise en fonction de la longueur maximale du texte et du nombre de lignes. Vous devrez également modifier l'élément de texte info-bulle pour qu'il contienne trois tspans:
<g id="tooltip" visibility="hidden">
<text><tspan>x</tspan><tspan x="0" dy="15">x</tspan><tspan x="0" dy="15">x</tspan></text>
</g>
Cela suppose que vous n’ayez jamais plus de trois lignes. Si vous voulez plus de trois lignes, vous pouvez ajouter plus de tspans et augmenter la longueur de la boucle for.
J'ai un peu adapté la solution de @steco, en commutant la dépendance de d3
à jquery
et à ajouter le height
de l'élément de texte en tant que paramètre
function wrap(text, width, height) {
text.each(function(idx,elem) {
var text = $(elem);
text.attr("dy",height);
var words = text.text().split(/\s+/).reverse(),
Word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat( text.attr("dy") ),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (Word = words.pop()) {
line.Push(Word);
tspan.text(line.join(" "));
if (elem.getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [Word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(Word);
}
}
});
}