huruyosi’s blog

プログラミングとかインフラとかのメモです。

d3.jsで作成したグラフの項目名を折り返す

Diverging Stacked Bar Chart

を参考にして横方向の積み上げグラフを作った時に系列のラベル名が長いと左余白を超える場合があり、見た目が格好悪いものになってしまいます。

svg 折り返し」で検索してみると foreignObjectを使う方法が出てくるけれども、何かが違う感じがするので、検索ワードを変更すると、 stack overflow に答えがありました。

stackoverflow.com

stack overflowの返答に書かれていたリンク先 Wrapping Long Labels を見ると、1文字づつ幅を確認していき、単語単位であふれる前に改行を行っていました。

日本語で単語の切れ目で折り返しを行おうとすると、形態素解析を行う必要が出てくるので今回は省略して、横方向にラベルを折り返しできるようにしました。ちょっとダサい部分もあるけど、目的を達成られたので、後日調整しようと思います。

   /**
    * 文字を折り返して指定された幅に収める
    *
    * http://bl.ocks.org/mbostock/7555321
    */
    function wrap(text, width) {
        text.each(function() {
            var text = d3.select(this);
            var words = [];
            org_label = text.text();
            for( i=org_label.length-1 ; 0 <= i ; i--){
                words.push(org_label.substr(i, 1));
            }
            var 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);
                }
            }
            lineNumber++
            var trans_y = ( lineNumber < 2 ? 0 : lineNumber-1.5 )* (text.node().getBBox().height/lineNumber) * -1;
            text.attr("transform","translate(-6, " + trans_y + ")")
        });
    }

折り返しの計算方法の参考したサイト

qiita.com