Empaquetage automatique des lignes dans SVG text

je voudrais afficher un <text> dans SVG ce qui serait Auto-Line-wrap pour le conteneur <rect> de la même manière que le texte HTML remplit les éléments <div> . Est-il un moyen de le faire? Je ne veux pas positionner les lignes de façon éparse en utilisant <tspan> s.

79
demandé sur tillda 2011-02-14 13:40:32

8 réponses

habillage du Texte n'est pas une partie de SVG1.1, qui est actuellement mis en œuvre spec. Vous devriez plutôt utiliser HTML via l'élément <foreignObject/> .

<svg ...>

<switch>
<foreignObject x="20" y="90" width="150" height="200">
<p xmlns="http://www.w3.org/1999/xhtml">Text goes here</p>
</foreignObject>

<text x="20" y="20">Your SVG viewer cannot display html.</text>
</switch>

</svg>
69
répondu Tangui 2012-04-16 08:56:44

Voici une alternative:

<svg ...>
  <switch>
    <g requiredFeatures="http://www.w3.org/Graphics/SVG/feature/1.2/#TextFlow">
      <textArea width="200" height="auto">
       Text goes here
      </textArea>
    </g>
    <foreignObject width="200" height="200" 
     requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
      <p xmlns="http://www.w3.org/1999/xhtml">Text goes here</p>
    </foreignObject>
    <text x="20" y="20">No automatic linewrapping.</text>
  </switch>
</svg>

notant que même si foreignObject peut être signalé comme étant supporté avec ce featurestring, il n'y a aucune garantie que HTML puisse être affiché parce que ce n'est pas requis par la spécification SVG 1.1. Il n'y a pas de featurestring pour le support html-in-foreignobject pour le moment. Cependant, il est encore pris en charge dans de nombreux navigateurs, il est donc susceptible de devenir nécessaire à l'avenir, peut-être avec un correspondant featurestring.

notez que L'élément 'textArea' dans SVG Tiny 1.2 supporte toutes les fonctionnalités standard de svg, E. g remplissage avancé etc, et que vous pouvez spécifier la largeur ou la hauteur comme auto, ce qui signifie que le texte peut circuler librement dans cette direction. ForeignObject agit en tant que clipping viewport.

Note: alors que L'exemple ci-dessus est valide SVG 1.1 content, dans SVG 2 l'attribut "requiredFeatures" a supprimé, ce qui signifie que l'élément "switch" essaiera de rendre le premier élément "g", même si SVG 1.2 supporte les éléments "textArea". Voir SVG2 elément de commutation spec .

58
répondu Erik Dahlström 2018-05-28 07:14:03

le chemin de texte peut être bon pour certains cas.

<svg width="200" height="200"
    xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
  <!-- define lines for text lies on -->
  <path id="path1" d="M10,30 H190 M10,60 H190 M10,90 H190 M10,120 H190"></path>
 </defs>
 <use xlink:href="#path1" x="0" y="35" stroke="blue" stroke-width="1" />
 <text transform="translate(0,35)" fill="red" font-size="20">
  <textPath xlink:href="#path1">This is a long long long text ......</textPath>
 </text>
</svg>
8
répondu user2856765 2013-10-08 01:53:37

cette fonctionnalité peut également être ajoutée en utilisant JavaScript. Carto.net a un exemple:

http://old.carto.net/papers/svg/textFlow /

quelque chose d'autre qui pourrait également être utile pour êtes-vous des zones de texte modifiables:

http://old.carto.net/papers/svg/gui/textbox /

8
répondu jbeard4 2017-08-09 15:33:31

en me basant sur le code de @Mike Gledhill, j'ai fait un pas de plus et j'ai ajouté plus de paramètres. Si vous avez un SVG RECT et que vous voulez que le texte s'enroule à l'intérieur, cela peut être pratique:

function wraptorect(textnode, boxObject, padding, linePadding) {

    var x_pos = parseInt(boxObject.getAttribute('x')),
    y_pos = parseInt(boxObject.getAttribute('y')),
    boxwidth = parseInt(boxObject.getAttribute('width')),
    fz = parseInt(window.getComputedStyle(textnode)['font-size']);  // We use this to calculate dy for each TSPAN.

    var line_height = fz + linePadding;

// Clone the original text node to store and display the final wrapping text.

   var wrapping = textnode.cloneNode(false);        // False means any TSPANs in the textnode will be discarded
   wrapping.setAttributeNS(null, 'x', x_pos + padding);
   wrapping.setAttributeNS(null, 'y', y_pos + padding);

// Make a copy of this node and hide it to progressively draw, measure and calculate line breaks.

   var testing = wrapping.cloneNode(false);
   testing.setAttributeNS(null, 'visibility', 'hidden');  // Comment this out to debug

   var testingTSPAN = document.createElementNS(null, 'tspan');
   var testingTEXTNODE = document.createTextNode(textnode.textContent);
   testingTSPAN.appendChild(testingTEXTNODE);

   testing.appendChild(testingTSPAN);
   var tester = document.getElementsByTagName('svg')[0].appendChild(testing);

   var words = textnode.textContent.split(" ");
   var line = line2 = "";
   var linecounter = 0;
   var testwidth;

   for (var n = 0; n < words.length; n++) {

      line2 = line + words[n] + " ";
      testing.textContent = line2;
      testwidth = testing.getBBox().width;

      if ((testwidth + 2*padding) > boxwidth) {

        testingTSPAN = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
        testingTSPAN.setAttributeNS(null, 'x', x_pos + padding);
        testingTSPAN.setAttributeNS(null, 'dy', line_height);

        testingTEXTNODE = document.createTextNode(line);
        testingTSPAN.appendChild(testingTEXTNODE);
        wrapping.appendChild(testingTSPAN);

        line = words[n] + " ";
        linecounter++;
      }
      else {
        line = line2;
      }
    }

    var testingTSPAN = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
    testingTSPAN.setAttributeNS(null, 'x', x_pos + padding);
    testingTSPAN.setAttributeNS(null, 'dy', line_height);

    var testingTEXTNODE = document.createTextNode(line);
    testingTSPAN.appendChild(testingTEXTNODE);

    wrapping.appendChild(testingTSPAN);

    testing.parentNode.removeChild(testing);
    textnode.parentNode.replaceChild(wrapping,textnode);

    return linecounter;
}

document.getElementById('original').onmouseover = function () {

    var container = document.getElementById('destination');
    var numberoflines = wraptorect(this,container,20,1);
    console.log(numberoflines);  // In case you need it

};
7
répondu MSC 2016-07-06 00:21:40

si vous deviez utiliser d3.js, ça pourrait aider: https://bl.ocks.org/mbostock/7555321

6
répondu zenw0lf 2016-10-12 12:50:10

j'ai posté la walkthrough suivante pour avoir ajouté un faux mot-wrapping à un élément SVG "text" ici:

SVG Word Wrap-Show stopper?

vous avez juste besoin d'ajouter une fonction JavaScript simple, qui divise votre chaîne en éléments plus courts" tspan". Voici un exemple de ce à quoi il ressemble:

Example SVG

Espérons que cette aide !

4
répondu Mike Gledhill 2017-05-23 12:34:27

le code suivant fonctionne très bien. Lancez le code snippet ce qu'il fait.

peut-être qu'il peut être nettoyé ou faire fonctionner automatiquement avec toutes les balises de texte dans SVG.

function svg_textMultiline() {

  var x = 0;
  var y = 20;
  var width = 360;
  var lineHeight = 10;
  
  

  /* get the text */
  var element = document.getElementById('test');
  var text = element.innerHTML;

  /* split the words into array */
  var words = text.split(' ');
  var line = '';

  /* Make a tspan for testing */
  element.innerHTML = '<tspan id="PROCESSING">busy</tspan >';

  for (var n = 0; n < words.length; n++) {
    var testLine = line + words[n] + ' ';
    var testElem = document.getElementById('PROCESSING');
    /*  Add line in testElement */
    testElem.innerHTML = testLine;
    /* Messure textElement */
    var metrics = testElem.getBoundingClientRect();
    testWidth = metrics.width;

    if (testWidth > width && n > 0) {
      element.innerHTML += '<tspan x="0" dy="' + y + '">' + line + '</tspan>';
      line = words[n] + ' ';
    } else {
      line = testLine;
    }
  }
  
  element.innerHTML += '<tspan x="0" dy="' + y + '">' + line + '</tspan>';
  document.getElementById("PROCESSING").remove();
  
}


svg_textMultiline();
body {
  font-family: arial;
  font-size: 20px;
}
svg {
  background: #dfdfdf;
  border:1px solid #aaa;
}
svg text {
  fill: blue;
  stroke: red;
  stroke-width: 0.3;
  stroke-linejoin: round;
  stroke-linecap: round;
}
<svg height="300" width="500" xmlns="http://www.w3.org/2000/svg" version="1.1">

  <text id="test" y="0">GIETEN - Het college van Aa en Hunze is in de fout gegaan met het weigeren van een zorgproject in het failliete hotel Braams in Gieten. Dat stelt de PvdA-fractie in een brief aan het college. De partij wil opheldering over de kwestie en heeft schriftelijke
    vragen ingediend. Verkeerde route De PvdA vindt dat de gemeenteraad eerst gepolst had moeten worden, voordat het college het plan afwees. "Volgens ons is de verkeerde route gekozen", zegt PvdA-raadslid Henk Santes.</text>

</svg>
4
répondu Peter 2016-07-04 05:49:28