> blog

雑多に書いていくブログ

JavaScriptで文字列の矩形領域を取得する

JavaScriptを使って任意の文字列の座標を取得する方法を探していたのですが,
なかなか良い方法が見つからなかったので僕なりに実装してみたコードを公開します.

function retrieveCharactersRects(elem) {
    if(elem.nodeType == elem.TEXT_NODE) {

        var range = elem.ownerDocument.createRange();

        // selectNodeContentsを実行することでText NodeにRangeをフォーカスさせ,
        // 文字列のoffsetを取得する
        range.selectNodeContents(elem);

        var current_pos = 0;
        var end_pos = range.endOffset;

        var results = [];

        while(current_pos + 1 < end_pos) {
            range.setStart(elem, current_pos);
            range.setEnd(elem, current_pos + 1);
            current_pos += 1;

            results.push({character: range.toString(), rect: range.getBoundingClientRect()});
        }

        range.detach();

        return results;

    } else {

        var results = [];
        for(var i = 0; i < elem.childNodes.length; i++) {
            results.push(retrieveCharactersRects(elem.childNodes[i]));
        }

        // 結果の配列をフラットにする
        return Array.prototype.concat.apply([], results);
    }
    return null;
}

方法

指定した要素内のText Nodeを取得し,Text Node内の文字列一つ一つをRangeオブジェクトの始点と終点で囲った後にgetBoundingClientRectしてやることで矩形領域を取得しています.

終わりに

文字列の矩形領域を取得する方法に関して他にも何人か実装を試みている人がいたのですが,文字列を一つ一つspanタグで囲ったりなかなか激しいアプローチをとっていたりしていたのでなるべくDOM要素に手を加えないようRangeオブジェクトを使ったアプローチを試してみました.

Rangeオブジェクトは文字列選択などに用いられたりしますが,こういう風に文字列の矩形領域の取得にも使えて便利です.

ちなみにiOSアプリでUIWebView内の全文字列の位置を取得してそれぞれの文字列の位置にUIViewをセットして矩形領域を視覚化してみたやつ.
f:id:mattatz:20130721160241j:plain

elementFromPointと併用するとマウス座標以下の文字列を取得できたりして色々な機能の実現に役立てられそう.