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


108

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

回答:


89

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

5
これはスイッチを使用する間違った方法です。svg仕様で定義されている機能文字列の1つを使用する必要があります。この例では、フォールバックは使用されません。w3.org/TR/SVG11/feature.htmlおよびw3.org/TR/SVG11/struct.html#SwitchElementを参照してください。
ErikDahlström11年

22
また、IEでは<foreignObject />はサポートされていません
Doug Amos

3
ただし、すべてのエンジンがforeignObjectsをレンダリングできるわけではないことに注意してください。特に、バティックはそうではありません。
hrabinowitz 14

69

ここに代替があります:

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

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

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


1
私はFFでこのコードをテストしていましたが、ブラウザーはtextArea要素もforeignObject子も表示しませんでした。次に、仕様を読んだ後、requiredFeatures属性が動作し、そのリストがfalseに評価されると、requiredFeatures属性を持つ要素とその子は処理されないことがわかりました。したがって、スイッチ要素は必要ありません。switch要素を削除した後、foreignObjectキッズが表示されました(私のブラウザー(FF、8.01)がsvg1.1をサポートしているため)。したがって、ここではスイッチ要素は必要ないと思います。私にお知らせください。
Rajkamal Subramanian 2012

<g>要素を使用するように更新されました。svg仕様では、不明な要素の「requiredFeatures」を確認するようビューアに指示していなかったため、意図したとおりに機能するには、既知のsvg要素を使用する必要があります。
エリックダールストロム2012

ありがとう!のxhtml:div代わりにを使用する必要divがありましたが、それはd3.jsが原因である可能性があります。TextFlowに関する有用な参照を見つけることができませんでした。それは(まだ)存在しますか、それともいくつかのドラフトだけでしたか?
johndodo 2013

2
textareaは今後サポートされないようです。bugzilla.mozilla.org/ show_bug.cgi
George Mauer

1
例はChromeでは機能しません。他のブラウザでテストしていない。
posfan12

15

場合によっては、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
中間単語のラップ(ハイフネーションは不可)が許容される場合のみ。アートプロジェクト以外で問題ないケースは多くありません。http://jsfiddle.net/nilloc/vL3zj/
Nilloc 14年

4
@Nillocすべての人が英語を使用するわけではありません。この方法は、中国語、日本語、韓国語でまったく問題ありません。
Zang MingJie

@ZangMingJie文字ベース(ロゴ)言語のラッピングは、単語の分割とはまったく異なる使用例のようです。これは、すべてのロマンチック/ラテン語/キリル語/アラビア語(表音)言語で重要です。
Nilloc

11

@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

};

ありがとう。これはChromeで完全に機能します。ただし、Firefoxでは機能しません。デモリンクに書いてあります。予期しない値のNaN解析dy属性。svgtext_clean2.htm:117回避策を見つけようとしています。
akshayb 2014

その後、Firefoxで動作させました。ここに行きます:
MSC

1
(今すぐEnterキーを押しすぎました。)その後、FirefoxとIEで動作させました。ヘルプが必要な場合は、democra.me/wrap_8_may_2014.htmをご覧ください。コードにFirefoxに関するコメントがあります。
MSC、

ご覧のとおり、コードを大幅に拡張して、境界ボックスを上下に縮小したり、省略記号を使用して適切な場所で省略したりしています。
MSC

MSCのコードで行を変更します。はboxwidth = parseInt(boxObject.getAttribute('width'))、ピクセル単位の幅を受け入れるだけですがboxwidth = parseInt(boxObject.getBBox().width)、は、あらゆるタイプの測定単位を受け入れます
Massimiliano Caniparoli


7

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

多分それをクリーンアップするか、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>


1
SVGテキストでの自動行折り返し:)テキストが長すぎる場合、私のJavaScriptコードは行を作成します。SVG内のすべてのテキストタグで作業すると便利です。JavaScriptのid = ""を変更せずに自動。悪いSVGには、それ自体で複数行があります。
Peter

いい解決策ですが、中央に揃えることができますか?
KrešimirGalić

tbhの回答を受け入れる必要があります。JavaScriptソリューションは十分に最小限であり、理にかなっています。
ザック

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.