SVG文本中的自动换行

时间:2011-02-14 10:40:32

标签: xml text svg linewrap

我想在SVG中显示<text>什么会自动换行到容器<rect>,就像HTML文本填充<div>元素一样。有办法吗?我不想使用<tspan> s。

来定位线条

9 个答案:

答案 0 :(得分:76)

文本换行不是SVG1.1的一部分,SVG1.1是当前实现的规范。您应该通过<foreignObject/>元素使用HTML。

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

答案 1 :(得分:61)

这是另一种选择:

<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可能被报告为支持该featurestring,也不能保证可以显示HTML,因为SVG 1.1规范不需要。目前,html-in-foreignobject支持没有featuretring。但是,它仍然在许多浏览器中得到支持,因此将来很可能需要它,可能还有相应的功能串。

请注意,SVG Tiny 1.2中的'textArea' element支持所有标准svg功能,例如高级填充等,并且您可以将宽度或高度指定为auto,这意味着文本可以在该方向上自由流动。 ForeignObject充当剪切视口。

注意:虽然上面的示例是有效的SVG 1.1内容,但在SVG 2中,'requiredFeatures'属性已被删除,这意味着'switch'元素将尝试渲染第一个'g'元素,无论是否支持SVG 1.2'textArea'元素。请参阅SVG2 switch element spec

答案 2 :(得分:12)

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>

答案 3 :(得分:8)

也可以使用JavaScript添加此功能。 Carto.net有一个例子:

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

您可能有用的其他内容是可编辑的文本区域:

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

答案 4 :(得分:8)

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

};

答案 5 :(得分:5)

如果您使用d3.js,这可能会有所帮助:https://bl.ocks.org/mbostock/7555321

答案 6 :(得分:4)

我已经发布了以下演练,用于在SVG“text”元素中添加一些假的自动换行:

SVG Word Wrap - Show stopper?

您只需添加一个简单的JavaScript函数,它将您的字符串拆分为更短的“tspan”元素。以下是它的外观示例:

Example SVG

希望这有帮助!

答案 7 :(得分:4)

以下代码正常运行。运行代码片段。它的功能。

也许它可以被清理或自动使用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>

答案 8 :(得分:0)

我尝试了所有答案 没有一个对我有用,只有我创建了 noob 解决方案,但它会在没有未知代码行的情况下解决,尝试添加没有内容的附加文本标签并验证文本长度,如果它> 大于最大第一个文本长度添加其余的到另一个文本标签等等。您只需要简单的 JavaScript if 语句并更改文本内容

  if (data['clinic']['cicovidcliniccity'].length > 35 && data['clinic']['cicovidcliniccity'].length < 75) {
    const cname = data['clinic']['cicovidcliniccity'];
    const ctext2_shodow = document.querySelector("#c_text2_shdow");
    ctext2.textContent = cname.substring(1, 35)
    ctext2_shodow.textContent = cname.substring(35, cname.length);

  }

  if (data['clinic']['cicovidcliniccity'].length > 75 && data['clinic']['cicovidcliniccity'].length < 110) {
    const cname1 = data['clinic']['cicovidcliniccity'];
    const ctext2_shodow = document.querySelector("#c_text2_shdow");
    const ctext3_shodow = document.querySelector("#c_text3_shdow");
    ctext2.textContent = cname1.substring(1, 35)
    ctext2_shodow.textContent = cname1.substring(35, 75);
    ctext3_shodow.textContent = cname1.substring(75, cname1.length);

  }