web-dev-qa-db-ja.com

D3チャートのラベルに改行を含めるにはどうすればよいですか?

D3を使用して棒グラフを生成しています( この例 のコードを適合させました)。 x-軸で使用しているラベルはそれぞれ2語の長さであり、これによりすべてのラベルが重複するため、分割する必要がありますこれらのラベルは行をまたいでいます。 (各ラベルのすべてのスペースを改行で置き換えることができれば問題ありません。)

私はもともと、スペースをリテラル改行(&#xA;)に置き換え、ラベルのxml:space="preserve"要素に<text>を設定してこれを試しました。残念ながら、SVGはこのプロパティを尊重していません。次に、各ワードを後でスタイルできるように<tspan>でラップしようとしました。このラベルを各関数に渡しました:

function (text) {
    return '<tspan>' + text.replace(/ /g, '</tspan><tspan>') + '</tspan>';
}

しかし、これはリテラル<tspan>sを出力に入れるだけです。ラベルが重ならないように、テキストラベルをtspansでラップ(または他の何かを行う)するにはどうすればよいですか?

62
bdesham

私は次のコードを使用して、各x-axisラベルを行に分割しました:

_var insertLinebreaks = function (d) {
    var el = d3.select(this);
    var words = d.split(' ');
    el.text('');

    for (var i = 0; i < words.length; i++) {
        var tspan = el.append('tspan').text(words[i]);
        if (i > 0)
            tspan.attr('x', 0).attr('dy', '15');
    }
};

svg.selectAll('g.x.axis g text').each(insertLinebreaks);
_

これは、ラベルがすでに作成されていることを前提としていることに注意してください。 ( 標準的なヒストグラムの例 に従うと、ラベルは必要な方法で設定されます。)また、実際の改行ロジックは存在しません。この関数は、すべてのスペースを改行に変換します。これは私の目的に合っていますが、split()行を編集して、文字列の一部を行に分割する方法をより賢くする必要があるかもしれません。

86
bdesham

SVGテキスト要素はテキストの折り返しをサポートしていないため、2つのオプションがあります。

  • テキストを複数のSVGテキスト要素に分割します
  • sVGの上にオーバーレイHTML divを使用します

これに関するMike Bostockのコメントを参照してください here

7
Ilya Boyandin

私が有用だとわかったのは、テキストまたはtspan要素の代わりに 'foreignObject'タグを使用することです。これにより、HTMLの簡単な埋め込みが可能になり、単語が自然に壊れるようになります。警告は、特定のニーズを満たすオブジェクトの全体的な寸法です。

var myLabel = svg.append('foreignObject')
    .attr({
        height: 50,
        width: 100, // dimensions determined based on need
        transform: 'translate(0,0)' // put it where you want it...
     })
     .html('<div class"style-me"><p>My label or other text</p></div>');

このオブジェクト内に配置した要素は、後でd3.select/selectAllを使用して取得し、テキスト値を動的に更新することもできます。

6
chrisjordanme

周りを見てみると、Mike Bostockがテキストを折り返すことができるソリューションを提供していることがわかりました。

http://bl.ocks.org/mbostock/7555321

コードに実装するには(折りたたまれたツリーダイアグラムを使用しています)。 「ラップ」メソッドをコピーしただけです。

次に、以下を追加しました

    // Standard code for a node    
    nodeEnter.append("text")
        .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
        .attr("dy", ".35em")
        .text(function(d) { return d.text; })
        // New added line to call the function to wrap after a given width
        .call(wrap, 40);

強制指向、バー、またはその他のパタ​​ーンに対してこれが機能しない理由がわからない

修正:

これを読んで共同グラフを使用している人のために、ラップ関数を次のように変更しました。 「x」属性の変更により、アライメントが正しく設定され、元のコードで問題が指摘され、「y」がゼロにハード設定されたため、行番号の増分が別の行で実行されました。各行。

function wrap(text, width) {
    text.each(function() {
        var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        Word,
        line = [],
        lineNumber = 0,
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        lineHeight = 1.1, // ems
        tspan = text.text(null).append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", y).attr("dy", dy + "em");     
        while (Word = words.pop()) {
            line.Push(Word);
            tspan.text(line.join(" "));
            var textWidth = tspan.node().getComputedTextLength();
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [Word];
                ++lineNumber;
                tspan = text.append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", 0).attr("dy", lineNumber * lineHeight + dy + "em").text(Word);
            }
        }
    });
}
3
John Duskin

this 長いラベルのラッピングに関する回答もあります。

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.bar {
  fill: steelblue;
}

.bar:hover {
  fill: brown;
}

.title {
  font: bold 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.axis {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: none;
}

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var margin = {top: 80, right: 180, bottom: 80, left: 180},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1, .3);

var y = d3.scale.linear()
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(8, "%");

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.tsv("data.tsv", type, function(error, data) {
  x.domain(data.map(function(d) { return d.name; }));
  y.domain([0, d3.max(data, function(d) { return d.value; })]);

  svg.append("text")
      .attr("class", "title")
      .attr("x", x(data[0].name))
      .attr("y", -26)
      .text("Why Are We Leaving Facebook?");

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .selectAll(".tick text")
      .call(wrap, x.rangeBand());

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

  svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.name); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); });
});

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);
      }
    }
  });
}

function type(d) {
  d.value = +d.value;
  return d;
}

</script>

データファイル「data.tsv」:

name    value
Family in feud with Zuckerbergs .17
Committed 671 birthdays to memory   .19
Ex is doing too well    .10
High school friends all dead now    .15
Discovered how to “like” things mentally    .27
Not enough politics .12
0
Nav