用canvas2d繪製font texture的注意事項
前言
用canvas2d繪製font可以輕鬆地找到範例,但繪製時有些需要注意的事,在此把過程做個紀錄。內容
由於WebGL本身不提供字型,所以需要產生font texture,產生的流程如下圖![]() |
| 產生font texture的流程 |
繪製字型是用canvas2d繪製後輸出到image,再來將imgae的資料輸出到WebGL的texture,之後WebGL再利用該texture來繪製font,整個流程不是很簡潔,但是我目前找到的方法中最好的。
基本的繪製範例如下
let canvas=document.getElementById('myCanvas');
let ctx=canvas.getContext('2d');
canvas.width=300;
canvas.height=300;
let fontSize=36;
let str='|_jx/|';
ctx.fillStyle='#ff0000';
ctx.font=fontSize+'px sans-serif';
ctx.textBaseline='top';
for(let i=0,curOffset=0;i<str.length;i++){
let width=ctx.measureText(str[i]).width;
ctx.fillStyle='#ff0000ff';
ctx.fillText(str[i],curOffset,0);
curOffset+=width;
}
繪製的結果如下
![]() |
| 範例繪製的結果 |
繪製的結果看起來沒問題,但事實上有問題,請看"_"與"j"連接的部分會連在一起,這對font texture而言可不是好事,如果WebGL在繪製"_"時會看到與"j"的部分,再想想如果將"_"改成"A",在繪製"A"時下方會多出"j"的一部分,這樣是無法讓人接受的。為什麼會發生這個問題呢?看看範例是如何知道該字的寬,"ctx.measureText()"就這個method,這是唯一可以得到字寬的方法,字高呢?font size有多高該字就多高,像"_"與"A"的高明顯不同,但只能把字型高的空間整個拿去畫。
前面提到透過"ctx.measureText()"來取得字寬,但"j"這個字很特別,它的左側會會超出繪製的字寬,如下圖
![]() |
| "j"的字寬很特別 |
第一個"j"的左側會被截掉,是因為超出canvas的左側,第二個"j"就可以看到該字的左側會超出邊框,這就是問題了。這問題怎麼解決呢?目前我想到的是針對"j"來做特例處理,讓"j"的左側會多出一些空間來包住"j",具體的範例如下
let canvas=document.getElementById('myCanvas');
let ctx=canvas.getContext('2d');
canvas.width=300;
canvas.height=300;
let fontSize=36;
let str='jj|_jx/|';
let modWidth=10;
ctx.fillStyle='#ff0000';
ctx.font=fontSize+'px sans-serif';
ctx.textBaseline='top';
for(let i=0,curOffset=0;i<str.length;i++){
let width=ctx.measureText(str[i]).width;
if(str[i] === 'j')
modWidth=5/72 *fontSize;
else
modWidth=0;
ctx.fillStyle='#ff0000ff';
ctx.fillText(str[i],curOffset+modWidth,0);
ctx.strokeRect(curOffset+modWidth,0,width,fontSize);
curOffset+=width+modWidth;
}
這個範例會對"j"這個字的左側增加"5/72"的寬度,這個寬度是我實驗的寬度,可以依據需要自己改,並且會考慮新增的寬度繪製新的邊框(邊框的寬度還是原本的寬度,但字跟字不會連在一起了),繪製的結果如下
![]() |
| 修正"j"的寬度的繪製結果 |




沒有留言:
張貼留言