web-dev-qa-db-ja.com

SVGテキストの自動行折り返し

HTMLテキストが<text>要素を埋めるのと同じ方法で、コンテナに<rect>自動折り返しする<div>をSVGで表示したいと思います。それを行う方法はありますか? <tspan>sを使用して行を慎重に配置したくありません。

94
tillda

テキストの折り返しは、現在実装されている仕様である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>
77
Tangui

代替手段は次のとおりです。

<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がその機能文字列でサポートされていると報告されたとしても、SVG 1.1仕様では必要ないため、HTMLを表示できる保証はありません。現時点では、html-in-foreignobjectサポートの機能文字列はありません。ただし、多くのブラウザで引き続きサポートされているため、将来的には対応する機能文字列が必要になる可能性があります。

SVG Tiny 1.2の 'textArea' element は、高度な塗りつぶしなどのすべての標準svg機能をサポートし、幅または高さのいずれかをautoとして指定できることに注意してください。つまり、テキストは自由に流れることができますその方向に。 ForeignObjectはクリッピングビューポートとして機能します。

注:上記の例は有効なSVG 1.1コンテンツですが、SVG 2では 'requiredFeatures'属性が削除されました。つまり、 'switch'要素はSVG 1.2の「textArea」要素のサポートに関係なく、最初の「g」要素をレンダリングしてみてください。 SVG2 switch element spec を参照してください。

63
Erik Dahlström

場合によっては、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>
13
user2856765

@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

};
9
MSC

この機能は、JavaScriptを使用して追加することもできます。 Carto.netには例があります。

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

あなたが編集可能なテキストエリアである場合にも役立つかもしれない他の何か:

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

8
jbeard4

次のコードは正常に動作しています。コードスニペットを実行します。

たぶん、クリーンアップするか、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>
5
Peter

D3.jsを使用する場合、これが役立つ可能性があります。 https://bl.ocks.org/mbostock/7555321

5
zenw0lf

ここで、SVGの「テキスト」要素に偽のWordラッピングを追加するための次のチュートリアルを投稿しました。

SVGワードラップ-ストッパーを表示しますか?

単純なJavaScript関数を追加するだけで、文字列が短い「tspan」要素に分割されます。以下に例を示します。

Example SVG

お役に立てれば !

4
Mike Gledhill