Автоматическая перенос строки в текст SVG - PullRequest
94 голосов
/ 14 февраля 2011

Я хотел бы отобразить <text> в SVG, что бы автоматически переносить строки в контейнер <rect> так же, как HTML-текст заполняет <div> элементы.Есть ли способ сделать это?Я не хочу размещать линии отдельно, используя <tspan> s.

Ответы [ 8 ]

77 голосов
/ 14 февраля 2011

Обтекание текстом не является частью SVG1.1, в настоящее время реализованной спецификации.Вам лучше использовать HTML через элемент <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>
62 голосов
/ 14 февраля 2011

Вот альтернатива:

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

Принимая во внимание, что, несмотря на то, что foreignObject может быть заявлен как поддерживаемый этой строкой функций, нет гарантии, что HTML может быть отображен, потому что это не требуется в спецификации SVG 1.1. В настоящее время нет никакой функциональной строки для поддержки html-in-foreignobject. Тем не менее, он по-прежнему поддерживается во многих браузерах, поэтому он может потребоваться в будущем, возможно, с соответствующей строкой функций.

Обратите внимание, что элемент textArea в SVG Tiny 1.2 поддерживает все стандартные функции svg, например, расширенное заполнение и т. Д., И что вы можете указать либо ширину, либо высоту как авто, что означает, что текст может свободно течь в этом направлении. ForeignObject действует как окно просмотра отсечения.

Примечание: , хотя приведенный выше пример является допустимым содержимым SVG 1.1, в SVG 2 атрибут requiredFeatures был удален, что означает, что элемент «switch» будет пытаться отобразить первый элемент «g» независимо от поддержки SVG 1.2 'textArea' элементов. См. Спецификация переключающего элемента SVG2 .

12 голосов
/ 08 октября 2013

textPath может быть полезным для некоторых случаев.

<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>
9 голосов
/ 03 апреля 2014

Опираясь на код @Mike Gledhill, я сделал еще один шаг и добавил больше параметров. Если у вас есть SVG RECT и вы хотите, чтобы текст был внутри него, это может быть полезно:

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

};
8 голосов
/ 16 февраля 2011

Эта функция также может быть добавлена ​​с помощью JavaScript. Carto.net имеет пример:

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

Что-то еще, что также может быть полезно, если вы редактируемые области текста:

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

5 голосов
/ 07 октября 2016

Если вы используете d3.js, это может помочь: https://bl.ocks.org/mbostock/7555321

5 голосов
/ 02 июля 2016

Следующий код работает нормально.Запустите фрагмент кода, что он делает.

Возможно, его можно очистить или заставить его автоматически работать со всеми текстовыми тегами в 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 голосов
/ 25 июля 2013

Я опубликовал следующее пошаговое руководство по добавлению фальшивых переносов слов в элемент «text» SVG:

SVG Word Wrap - Показать стопор?Вам просто нужно добавить простую функцию JavaScript, которая разбивает вашу строку на более короткие элементы "tspan".Вот пример того, как это выглядит:

Example SVG

Надеюсь, это поможет!

...