【JavaScript】 Canvas上のテキストの幅と高さを求める
更新日:2024/04/22
Canvas上で文字列の幅と高さを求め、枠を描画するところまでやってみます。
文字列の幅と高さを計算
Canvas上での文字列の幅と高さは、コンテキストのmeasureText()メソッドを使用します。
measureText()メソッドは幅を取得するケースが多いですが、高さも取得できます。
measureText()メソッド
文字列を指定すると、文字列の枠情報を取得できます。
JavaScript:measureText使用例
const cvs = document.getElementById("canvas");
const context = cvs.getContext("2d");
const text = "文字列の幅と高さを取得";
const measure = context.measureText( text );
measureText()から返る値はTextMetricsオブジェクトで、次のプロパティを持っています。
TextMetricsオブジェクト {
width : 文字列の幅 ,
actualBoundingBoxLeft : 基準点から左枠までの距離
actualBoundingBoxRight : 基準点から右枠までの距離
actualBoundingBoxAscent : 基準点から上枠までの距離
actualBoundingBoxDescent : 基準点から下枠までの距離
}
基準点は、textBaselineやtextAlignにより設定されます。
幅はwidthで取得できます。
actualBoundingBoxLeftとactualBoundingBoxRightからも求めることができますが、widthとイコールにはなりません。
高さは、actualBoundingBoxAscentとactualBoundingBoxDescentの合計から求めることができます。
JavaScript:文字列の高さと幅を求める例
const measure = context.measureText( text );
const textWidth = measure.width,
const textHeight = measure.actualBoundingBoxAscent
+ measure.actualBoundingBoxDescent
文字列の矩形を計算
文字列の矩形は、次の計算式で求めることができます。
なおfillText()やstrokeText()で指定した座標を( mx , my )とします。
左上座標( x , y )
const x = mx - Math.abs( measure.actualBoundingBoxLeft )
const y = my - measure.actualBoundingBoxAscent
Math.abs()は絶対値を求めるメソッドです。
actualBoundingBoxLeftは、Google Chromeではプラスの値になりますが、Firefoxではマイナスの値になります。
そのためMath.abs()は絶対値を求めてから、マイナスしています。
幅width,高さheight
幅と高さは、前項と同じです。
const width = measure.width
const height = measure.actualBoundingBoxAscent
+ measure.actualBoundingBoxDescent
文字枠矩形を描画
textAlignとtextBaselineの変化に合わせて、文字列枠を描画してみます。
(()=>{
const lineDraw = (cts, sx , sy , ex , ey ) =>{
cts.beginPath();
cts.strokeStyle = "aqua";
cts.moveTo( sx , sy );
cts.lineTo( ex , ey );
cts.stroke();
};
window.addEventListener( "DOMContentLoaded" , ()=> {
const cvs = document.getElementById("canvas");
const context = cvs.getContext('2d');
context.font = "20px serif";
const textAlign = [ "right" , "center" ,"left" ];
const textBaseline = ["top","middle","bottom"];
textAlign.forEach( (e,i)=>{
context.textAlign = e;
textBaseline.forEach( ( e2,j) => {
context.textBaseline = e2;
const text = `文字枠(${e},${e2})` ;
const [ x , y ] = [ 110 * ( i + 1 ) + 100 , 50 * ( j + 1 )];
lineDraw( context , x - 200 , y , x + 200 , y);
lineDraw( context , x , y + 50 , x , y - 50);
context.beginPath();
const measure = context.measureText( text );
const pos =[
x - Math.abs(measure.actualBoundingBoxLeft),
y - measure.actualBoundingBoxAscent,
measure.width,
measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent
];
context.strokeStyle = "blue";
context.strokeRect( ...pos );
context.fillStyle = "red";
context.fillText( text , x ,y);
});
});
});
})();
更新日:2024/04/22
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。