【C】Canvasでテキストを上下左右中央揃えで描画する
この記事は、ADVENTAR 『"Alphabet reg." Web develop Advent Calendar 2023』 02日目の記事です。
/icons/hr.icon
canvasなんもわからんと言いつつも、holorhysmもあって結局やらなきゃいけないなと思ったのでテキストから片付けます
愚直にやるなら
CanvasRenderingContext2D.fillStyleに色を指定
CSSのcolorとして解釈できる文字列とか
輪郭だけ書きたい場合はCanvasRenderingContext2D.strokeStyle
CanvasRenderingContext2D.fontにフォントを指定
CSSのfontプロパティで使う文字列と同じ形式っぽい
size/lineHeight fontNameが最低限必要、太字とかやるならここで指定
CanvasRenderingContext2D.textAlignに左右方向の揃え方を指定
左(left)・右(right)・中央(center)に加えて、論理プロパティのstartとendもある
CanvasRenderingContext2D.textBaselineに垂直方向の揃え方を指定
上(top)・下(bottom)・中央(right)に加えて、hanging・alphabetic・ideographicとかいうものもある
https://html.spec.whatwg.org/multipage/images/baselines.png
CanvasRenderingContext2D.directionに文字の描画方向を指定
左から(ltr)・右から(rtl)に加えて、適宜canvasやその上位要素から継承するinheritがある。デフォルトinheritなので指定不要な場合が多い
CanvasRenderingContext2D.fillText(text, x, y, maxWidth)でようやく描画できる
xとyは基準点の座標
maxWidthは最大描画幅(これを超えないように縮めたり小さくしたりしてくれるらしい)。指定は任意
輪郭だけ書くならCanvasRenderingContext2D.strokeText(text, x, y, maxWidth)
だるいので
CanvasRenderingContext2Dをオレオレ拡張したほうが早いと思うんだ
code:script.js
/**
* テキストを描画します。
* @param {String|CanvasGradient|CanvasPattern} fill - 塗りつぶし色(塗りつぶさない場合は"none"を指定)
* @param {String|CanvasGradient|CanvasPattern} stroke - 輪郭色(塗りつぶさない場合は"none"を指定)
* @param {Number} x - 基準点のX座標
* @param {Number} y - 基準点のY座標
* @param {String} text - 描画するテキスト
* @param {String} font - 使用するフォント。CSSのfontプロパティで有効な値を使用
* @param {Number} dir - 1〜9(123/456/789)で指定、基準点をどこにするか
* @param {Number} max=0 - 文字の最大描画幅。0だと無視。 */
CanvasRenderingContext2D.prototype.write = function (fill, stroke, x, y, text, font, dir, thickness = 1, max = 0) {
const predecessor = {
"fillStyle": this.fillStyle,
"strokeStyle": this.strokeStyle,
"lineWidth": this.lineWidth,
"font": this.font,
"textAlign": this.textAlign,
"textBaseline": this.textBaseline
};
this.lineWidth = thickness;
fill === "none" ? void 0 : this.fillText(text, x, y, max || undefined);
stroke === "none" ? void 0 : this.strokeText(text, x, y, max || undefined);
};
使用例
詳細は省きますが概ねこうなるはずです(canvasサイズは200x200)
code:script.js
$("canvas").ctx.rect("#f22", "none", 300, 300, 4, 4, 5, 4);
$("canvas").ctx.write("hsl(0 100% 50%)", "none", 300, 300, "111111", "3rem/1 'M PLUS 1p'", 1);
$("canvas").ctx.write("hsl(40 100% 50%)", "none", 300, 300, "2", "3rem/1 'M PLUS 1p'", 2);
$("canvas").ctx.write("hsl(80 100% 50%)", "none", 300, 300, "333333", "3rem/1 'M PLUS 1p'", 3);
$("canvas").ctx.write("hsl(120 100% 50%)", "none", 300, 300, "444444", "3rem/1 'M PLUS 1p'", 4);
$("canvas").ctx.write("hsl(160 100% 50%)", "none", 300, 300, "5", "3rem/1 'M PLUS 1p'", 5);
$("canvas").ctx.write("hsl(200 100% 50%)", "none", 300, 300, "666666", "3rem/1 'M PLUS 1p'", 6);
$("canvas").ctx.write("hsl(240 100% 50%)", "none", 300, 300, "777777", "3rem/1 'M PLUS 1p'", 7);
$("canvas").ctx.write("hsl(280 100% 50%)", "none", 300, 300, "8", "3rem/1 'M PLUS 1p'", 8);
$("canvas").ctx.write("hsl(320 100% 50%)", "none", 300, 300, "999999", "3rem/1 'M PLUS 1p'", 9);
https://scrapbox.io/files/656d70ab5b7b66002462c814.png
番外編
長方形のオレオレ拡張もつくった
code:script.js
/**
* 長方形を描画します。
* @param {String|CanvasGradient|CanvasPattern} fill - 塗りつぶし色(塗りつぶさない場合は"none"を指定)
* @param {String|CanvasGradient|CanvasPattern} stroke - 輪郭色(塗りつぶさない場合は"none"を指定)
* @param {Number} x - 基準点のX座標
* @param {Number} y - 基準点のY座標
* @param {Number} width - 幅
* @param {Number} height - 高さ
* @param {Number} dir - 1〜9(123/456/789)で指定、基準点をどこにするか
*/
CanvasRenderingContext2D.prototype.rect = function (fill, stroke, x, y, width, height, dir, thickness = 1) {
const predecessor = {
"fillStyle": this.fillStyle,
"strokeStyle": this.strokeStyle,
"lineWidth": this.lineWidth
};
const leftPos = x - width * (((dir - 1) % 3) / 2);
const topPos = y - height * (Math.floor((dir - 1) / 3) / 2);
this.lineWidth = thickness;
fill === "none" ? void 0 : this.fillRect(leftPos, topPos, width, height);
stroke === "none" ? void 0 : this.strokeRect(leftPos, topPos, width, height);
};