Comment saut de ligne un texte svg dans javascript?
Voici Donc 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 texte d'info-bulle très long n'a pas de saut de ligne, même si si j'utilise alert(); cela me montre que le texte a en fait deux lignes. (Il contient un "" cependant, Comment puis-je supprimer celui-ci au fait?)
Je ne peux pas faire travailler CDATA n'importe où.
5 réponses
Ce N'est pas quelque chose que SVG 1.1 prend en charge. SVG 1.2 A l'élément textArea
, avec un habillage automatique des mots, mais il n'est pas implémenté dans tous les navigateurs. SVG 2 ne prévoit pas de mettre en œuvre textArea
, mais il a texte auto-enveloppé .
Cependant, étant donné que vous savez déjà où vos sauts de ligne devraient se produire, vous pouvez diviser votre texte en plusieurs <tspan>
s, chacun avec x="0"
et dy="1.4em"
pour simuler des 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, puisque 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 cherche une solution similaire, cela a fonctionné 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ù mettre vos sauts de ligne: vous pouvez utiliser cette belle fonction, que j'ai trouvée ici: http://bl.ocks.org/mbostock/7555321
Qui fait automatiquement des 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 vous voulez:
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 un tspan. Ensuite, il calcule la taille de la boîte requise en fonction de la plus longue longueur de texte et du nombre de lignes. Vous devrez également modifier l'élément de texte de l'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'avez 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 par @steco, en supprimant la dépendance de d3
et en ajoutant le height
de l'élément text 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);
}
}
});
}