37
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SVGでtext要素のサイズを測る

Last updated at Posted at 2014-03-12

D3でグラフ描画なんかをやっているとSVGのtext要素を枠線で囲ったりしたくなります。どのような文字列の入力にも対応できるようにするためには、text要素の縦横幅を取得して装飾を行う必要があるため、この稿ではその方法を紹介します。

SVG要素の描画領域の短形範囲がgetBBox()メソッドで取得できます。text要素のgetBBoxを呼ぶことでtextの縦横幅を取得することができます。

ソースコード

<svg width="300px" height="300px">
    <rect width="300" height="300" fill="lightgray"/>
    <text id="text1" x="50" y="30">text</text>
    <text id="text2" x="50" y="60" font-size="2em">text</text>
    <text id="text3" transform="translate(50, 90)rotate(45)">text</text>
    <text id="text4" x="50" y="120" style="visibility: hidden;">text</text>
    <text id="text5" x="50" y="150" style="display: none;">text</text>
</svg>
<table id="output">
    <tr>
        <th>id</th>
        <th>width</th>
        <th>height</th>
        <th>x</th>
        <th>y</th>
    </tr>
</table>
<script>
var output = document.getElementById('output');

function getSize(id) {
    var bbox = document.getElementById(id).getBBox();
    var tr = document.createElement('tr');
    var tdId = document.createElement('td');
    tdId.innerHTML = id;
    tr.appendChild(tdId);
    var tdWidth = document.createElement('td');
    tdWidth.innerHTML = bbox.width;
    tr.appendChild(tdWidth);
    var tdHeight = document.createElement('td');
    tdHeight.innerHTML = bbox.height;
    tr.appendChild(tdHeight);
    var tdX = document.createElement('td');
    tdX.innerHTML = bbox.x;
    tr.appendChild(tdX);
    var tdY = document.createElement('td');
    tdY.innerHTML = bbox.y;
    tr.appendChild(tdY);
    output.appendChild(tr);
}

getSize('text1');
getSize('text2');
getSize('text3');
getSize('text4');
getSize('text5');
</script>

実行結果

実行結果を見ると、text要素のwidth、height、x、yの値が取得できていることがわかると思います。text2のように、font-sizeを指定するとそれに応じてwidth、heightが変化しています。text3では、transformでtranslate、rotateをかけていますが、transformを使っていないtext1と同じ結果になっています。text4は、styleでvisibility: hidden;を指定していますが、上と同様にサイズを取得することができます。一方で、text5のようにdisplay: none;を指定した場合、これらの値が0になることを注意してください。

D3への応用

以上をふまえて、D3.jsでtextを枠線で囲うプログラムは以下のようになります。

var texts = [{text: 'spam'}, {text: 'ham'}, {text: 'egg'}];

var textsSelection = d3.select('svg')
    .selectAll('text')
    .data(texts)
    .enter()
    .append('g')
    .attr('transform', function(_, i) {
        return 'translate(50,' + (50 * i) + ')';    
    });
textsSelection.append('text')
    .text(function(d) {
        return d.text;
    })
    .attr('font-size', '2em')
    .each(function(d) {
        var bbox = this.getBBox();
        d.width = bbox.width;
        d.height = bbox.height;
        d.x = bbox.x;
        d.y = bbox.y;
    })
    .attr('dy', function(d) {
        return -d.y;
    });
textsSelection.append('rect')
    .attr({
        width: function(d) {
            return d.width;
        },
        height: function(d) {
            return d.height;
        },
        fill: 'none',
        stroke: 'black'
    });

jsfiddle上での実行結果はこちら。
http://jsfiddle.net/likr/kJuUE/

textのサイズを決定するような属性などを与えたあと、eachの中でgetBBoxを呼び(ここでthisがtext要素を指します)、selectionで結びついているデータにサイズの情報を格納しておきます。
また、text要素のy=0の位置はベースラインになりますので、getBBoxで取得したyを使ってtext要素の上端がy=0となるように補正しています。

37
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?