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

81
demandé sur sollniss 2013-05-23 01:03:41

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.

109
répondu Sergiu Dumitriu 2016-08-22 19:51:58

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.

17
répondu Kristīne Glode 2013-10-25 11:57:45

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);
      }
    }
  });
}
10
répondu steco 2015-02-17 01:48:24

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.

8
répondu Peter Collingridge 2013-05-23 11:34:10

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);
      }
    }
  });
}
0
répondu loretoparisi 2018-02-28 16:32:09