<text/>のサイズがデータとして欲しいときにどうすべきか考察
背景を塗りたい場合のお手本
code:js
document.addEventListener("DOMContentLoaded", function(){
var text = document.querySelector("#target");
var bbox = text.getBBox();
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.style.fill = "yellow";
text.parentNode.insertBefore(rect, text);
}, false);
ただ背景や枠線が欲しい場合はこれで十分
衝突判定や位置調整をするためにテキストを囲む矩形がデータとして欲しい場合がある
上記の方法だとSVGとしてタグ生成されてからでないと #サイズ が分からない&環境や #フォント によって値が変わりうる VueやReactで宣言的にSVGを書いているときに毎回悩まされる
SVGをコンポーネント化していて親子のネストが入ってくるとさらに面倒
複数行 #テキスト に対応すると<text/>が複数になるのでさらにさらに面倒 対応策
データとして永続化はせず、毎回再計算を覚悟する
Vueの場合
<text/>にrefを付けてbboxをイベントで投げる
mountedやwatchを使ってサイズが変わりそうな場合にとにかくbboxを投げる
watchの場合は$nextTick()で描画を待ってからでないと最新の矩形にならない
code:js
if (!this.$refs.text) return
this.$emit('calcSize', this.$refs.text.getBBox())
データを管理する親コンポーネント側は上記イベントを受けてdataにそれを格納する
配列でなくマップとして管理するほうが楽な気がする
code:js
calcSize ({ key, bbox }) {
Vue.set(this.textNodeSizes, key, bbox)
}
そのデータはSVGが描画されるまで空であることを意識してその他処理を作っておく
dataが変われば勝手に再計算が走るVueの機能が大活躍する
全ての矩形取得が完了した判定をcomputedで作っておくと吉
code:js
calcTextSizeCeompleted () {
return !Object.keys(this.textNodes).find(key => !this.textNodeSizeskey) }
FIX ME
せっかくのバーチャルDOMなのに全然宣言的でもスマートでもない