JavaScript内でSVGテキストを改行する方法は?


107

だからここに私が持っているものがあります:

<path class="..." onmousemove="show_tooltip(event,'very long text 
    \\\n I would like to linebreak')" onmouseout="hide_tooltip()" d="..."/>

<rect class="tooltip_bg" id="tooltip_bg" ... />
<text class="tooltip" id="tooltip" ...>Tooltip</text>

<script>
<![CDATA[
function show_tooltip(e,text) {
    var tt = document.getElementById('tooltip');
    var bg = document.getElementById('tooltip_bg');

    // set position ...

    tt.textContent=text;

    bg.setAttribute('width',tt.getBBox().width+10);
    bg.setAttribute('height',tt.getBBox().height+6);

    // set visibility ...
}
...

これで、alert()を使用しても、非常に長いツールチップテキストには改行がありません。それは、テキストが実際には2行あることを示しています。(ただし、「\」が含まれていますが、どうすれば削除
できますか?)CDATAをどこでも機能させることができません。


2
このsvgjs.com/textflowがツールチップに役立つ可能性はありますか?
Alvin K.

@AlvinK。リンクが壊れています。新しい場所を見つけようとしましたが、失敗しました。
guettli

回答:


150

これはSVG 1.1がサポートするものではありません。SVG 1.2にはtextArea要素があり、自動ワードラップが行われますが、すべてのブラウザに実装されているわけではありません。SVG 2 は実装を計画しtextAreaていませんが、自動折り返しテキストがあります

しかし、あなたはすでにあなたの改行が発生した場所を知っていることを考えると、あなたは複数にあなたのテキストを破ることができる<tspan>と、sのそれぞれをx="0"し、dy="1.4em"テキストの実際の行をシミュレートします。例えば:

<g transform="translate(123 456)"><!-- replace with your target upper left corner coordinates -->
  <text x="0" y="0">
    <tspan x="0" dy="1.2em">very long text</tspan>
    <tspan x="0" dy="1.2em">I would like to linebreak</tspan>
  </text>
</g>

もちろん、それをJavaScriptから行いたいので、手動で各要素を作成してDOMに挿入する必要があります。


2
そして、どこに置くべきかをどうやって認識し<tspan>sますか?置き換えますか?スプリット?
ソルニス2013年

2
試してみましたvar tspan = document.createElement('tspan') tspan.setAttribute('x','0'); tspan.setAttribute('dy','1.2em'); tspan.textContent = text; tt.appendChild(tspan); が、テキストはまったく表示され ません。
ソルニス2013年

2
x = '0' dy = '1.2em'が必要な理由を詳しく説明していただけますか?それは確かに、あなたが言ったように機能します。ただし、これらの属性がなくても機能することを期待していました。代わりに、何も表示されません...また、改行が発生する理由が完全にわかりません。コンテナの幅を修正するために設定したのではなく、改行が発生する可能性がありますね。
Konrad Viltersten、2016年

4
x=0は絶対座標です。テキストフラグメントを現在の座標系の原点に移動します。要素のtransform属性gは新しい現在の座標系を定義し、テキストが左揃えであると想定して、tspanは左に移動します。これは、復帰命令のように機能します。 dy=1.2emされる相対座標:現在テキスト断片に対して、この量によってテキスト断片を移動させます。これは、改行命令のように機能します。結合すると、CR / LFを取得します。
Sergiu Dumitriu 2016年

まだ試していない:グループなしでこれを行うこともできますか?<text x = "100" y = "100"> <tspan x = "100" y = "100">非常に長いテキスト</ tspan> <tspan x = "100" y = "115">したい改行</ tspan> </ text> ??
Richard

25

私はあなたがすでにそれを解決できたと思いますが、誰かが同様の解決策を探しているなら、これは私にとってうまくいきました:

 g.append('svg:text')
  .attr('x', 0)
  .attr('y', 30)
  .attr('class', 'id')
  .append('svg:tspan')
  .attr('x', 0)
  .attr('dy', 5)
  .text(function(d) { return d.name; })
  .append('svg:tspan')
  .attr('x', 0)
  .attr('dy', 20)
  .text(function(d) { return d.sname; })
  .append('svg:tspan')
  .attr('x', 0)
  .attr('dy', 20)
  .text(function(d) { return d.idcode; })

改行で区切られた3行です。


21
FWIW:OPが純粋なJavaScriptを使用していたようです。この答えはD3を利用しているようです。
Ben Mosher 2014

私はD3を使用しており、あなたのアプローチは私にとってうまくいきました。投稿いただきありがとうございます。次のように、新しいtspanを追加する前に、まず古いtspanを削除する必要があることがわかりました。focus.selectAll( "tspan")。remove();
Darren Parker

1
.append()をチェーンするため、このアプローチでは<tspan>タグがネストされることに注意してください。これは、何をしたいかに応じて、CSSでいくつかの小さな頭痛を引き起こす可能性があります。
Seneyr 2017

@seneyrによって記述されたネストを回避するアプローチについては、ここを参照してください
bszom

16

tspanソリューションを使用して、改行する場所が事前にわからない場合を考えてみましょう。ここで見つけたこの素晴らしい関数を使用できます。 。http //bl.ocks.org/mbostock/7555321

これは、ピクセルで指定された幅の長いテキストsvgの改行を自動的に行います。

function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
    while (word = words.pop()) {
      line.push(word);
      tspan.text(line.join(" "));
      if (tspan.node().getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(" "));
        line = [word];
        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}

9

私はこれがあなたが望むことをすると思います:

function ShowTooltip(evt, mouseovertext){
    // Make tooltip text        
    var tooltip_text = tt.childNodes.item(1);
    var words = mouseovertext.split("\\\n");
    var max_length = 0;

    for (var i=0; i<3; i++){
        tooltip_text.childNodes.item(i).firstChild.data = i<words.length ?  words[i] : " ";
        length = tooltip_text.childNodes.item(i).getComputedTextLength();
        if (length > max_length) {max_length = length;}
    }

    var x = evt.clientX + 14 + max_length/2;
    var y = evt.clientY + 29;
    tt.setAttributeNS(null,"transform", "translate(" + x + " " + y + ")")

    // Make tooltip background
    bg.setAttributeNS(null,"width", max_length+15);
    bg.setAttributeNS(null,"height", words.length*15+6);
    bg.setAttributeNS(null,"x",evt.clientX+8);
    bg.setAttributeNS(null,"y",evt.clientY+14);

    // Show everything
    tt.setAttributeNS(null,"visibility","visible");
    bg.setAttributeNS(null,"visibility","visible");
}

テキストを分割し、\\\nそれぞれのフラグメントをtspanに配置します。次に、テキストの最長の長さと行数に基づいて、必要なボックスのサイズを計算します。また、ツールチップのテキスト要素を3つのtspanを含むように変更する必要があります。

<g id="tooltip" visibility="hidden">
    <text><tspan>x</tspan><tspan x="0" dy="15">x</tspan><tspan x="0" dy="15">x</tspan></text>
</g>

これは、4行を超えることはないと想定しています。4行以上必要な場合は、tspanを追加して、forループの長さを増やすことができます。


それ"\\\n"はなぜ"\n"ですか?
ラリアン

2

@stecoによるソリューションを少し調整して、依存関係をからd3に切り替え、テキスト要素のをパラメーターとしてjquery追加しましたheight

function wrap(text, width, height) {
  text.each(function(idx,elem) {
    var text = $(elem);
    text.attr("dy",height);
        var words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat( text.attr("dy") ),
        tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
    while (word = words.pop()) {
      line.push(word);
      tspan.text(line.join(" "));
      if (elem.getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(" "));
        line = [word];
        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}

2

JavaScriptの代わりにHTMLを使用する

<html>
  <head><style> * { margin: 0; padding: 0; } </style></head>
  <body>
    <h1>svg foreignObject to embed html</h1>

    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 300 300"
      x="0" y="0" height="300" width="300"
    >

      <circle
        r="142" cx="150" cy="150"
        fill="none" stroke="#000000" stroke-width="2"
      />

      <foreignObject
        x="50" y="50" width="200" height="200"
      >
        <div
          xmlns="http://www.w3.org/1999/xhtml"
          style="
            width: 196px; height: 196px;
            border: solid 2px #000000;
            font-size: 32px;
            overflow: auto; /* scroll */
          "
        >
          <p>this is html in svg 1</p>
          <p>this is html in svg 2</p>
          <p>this is html in svg 3</p>
          <p>this is html in svg 4</p>
        </div>
      </foreignObject>

    </svg>

</body></html>


「JavaScriptの代わりにSVGを使用する」という意味だと思います
Valerio Bozz

それは「SVGのHTML」であり、私にとって最良のソリューションです。
KEVIN Berthommier
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.