137 votes

Comment faire un saut de ligne dans un texte svg en 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 très long texte d'infobulle n'a pas de saut de ligne, même si j'utilise alert() ; qui me montre que le texte a en fait deux lignes. (Il contient cependant un "\", comment puis-je le supprimer d'ailleurs ?)
Je n'arrive pas à faire fonctionner les CDATA.

183voto

Sergiu Dumitriu Points 5959

Ce n'est pas quelque chose que SVG 1.1 supporte. SVG 1.2 dispose de la fonction textArea avec 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 doivent se produire, vous pouvez diviser votre texte en de multiples <tspan> s, chacun avec x="0" y 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 faire cela à partir de JavaScript, vous devrez créer et insérer manuellement chaque élément dans le DOM.

33voto

Kristīne Glode Points 1379

Je suppose que vous avez déjà réussi à le résoudre, mais si quelqu'un cherche une solution similaire, voici ce qui 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.

19voto

steco Points 195

Avec la solution tspan, disons que vous ne savez pas à l'avance où placer vos sauts de ligne : vous pouvez utiliser cette jolie fonction, que j'ai trouvée ici : http://bl.ocks.org/mbostock/7555321

Cela permet de faire automatiquement des sauts de ligne pour les longs textes 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")) || 0,
        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);
      }
    }
  });
}

13voto

Mila Nautikus Points 31

Utiliser le HTML au lieu du javascript

limitation : le moteur de rendu SVG doit supporter le rendu HTML

par exemple, inkscape ne peut pas rendre de tels fichiers SVG

<html>
  <head><style> * { margin: 0; padding: 0; } </style></head>
  <body>
    <h1>svg foreignObject to embed html</h1>

    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 300 300"
      x="0" y="0" height="300" width="300"
    >

      <circle
        r="142" cx="150" cy="150"
        fill="none" stroke="#000000" stroke-width="2"
      />

      <foreignObject
        x="50" y="50" width="200" height="200"
      >
        <div
          xmlns="http://www.w3.org/1999/xhtml"
          style="
            width: 196px; height: 196px;
            border: solid 2px #000000;
            font-size: 32px;
            overflow: auto; /* scroll */
          "
        >
          <p>this is html in svg 1</p>
          <p>this is html in svg 2</p>
          <p>this is html in svg 3</p>
          <p>this is html in svg 4</p>
        </div>
      </foreignObject>

    </svg>

</body></html>

10voto

Peter Collingridge Points 4037

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. Il calcule ensuite 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 de l'infobulle 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X