在canvas中,我們經常需要繪制線段,主要使用moveTo和lineTo兩個方法,moveTo移動至線段起始點,lineTo將線段繪制至終點。同時,繪制線段時可以指定線段的寬度,使用lineWidth屬性,lineWidth默認為1,必須大於0
moveTo(x, y): 移動至坐標x,y
lineTo(x, y): 線段終點坐標x,y
簡單繪制代碼如下:
var context = document.getElementById('canvas').getContext('2d'); context.lineWidth = 2; //設置線寬 context.beginPath(); //開始繪制路徑 context.moveTo(0, 50); //移動至起始點 context.lineTo(50, 50); //移動至終點 context.stroke(); //繪制
Done, 繪制出了一條線寬為2的線段,就這么簡單
那我們再繪制一條線寬為1的線段
context.lineWidth = 1; context.beginPath(); context.moveTo(50, 50); context.lineTo(100, 50); context.stroke();
我勒個去,怎么跟線寬2的寬度是一樣的,寬度也是2,只是顏色稍淺。
那我們換個思路,剛才繪制的Y軸左邊為50,我們改成50.5呢,分別再繪制兩條線寬分別是2和1的線段
context.lineWidth = 2; context.beginPath(); context.moveTo(0, 70.5); context.lineTo(50, 70.5); context.stroke(); context.lineWidth = 1; context.beginPath(); context.moveTo(0, 80.5); context.lineTo(50, 80.5); context.stroke();
從上至下分別稱為線段1,2,3,4
顯然,線段3比1,2都要寬,實際為3px,線段4實際為1px
線段1:繪制線寬2, 實際寬度2
線段2:繪制寬度1, 實際寬度2
線段3:繪制寬度2, 實際寬度3
線段4:繪制寬度1: 實際寬度1
只有1和4才是我們想要的結果
為什么呢?
其實,這跟canvas的繪制邏輯有關,當我們試圖繪制一個線段時,canvas會讀取lineWidth,,然后嘗試將在坐標處兩邊各繪制一半的lineWidth,比如我們下圖:
我們在坐標3處畫一條寬為1的橫線,canvas會以3為中軸線,在兩邊各畫0.5像素,深藍色就是我們期望的效果(2.5-3.5,1個像素),但實際上,淺藍色也會被繪制出來,因為canvas無法在整個像素寬內只繪制半個像素,所以坐標軸上下兩個方向都都會被擴展至整個像素寬度內(2-4,兩個像素),但是擴展的像素實際的值並不是原值相同,而是取其一半,所以最直接的視覺感受是:線條比預想的變寬了,但是顏色淺了很多。
還是以寬為1的橫線為例,我們如果將其繪制在縱坐標2.5處呢,即以半像素作為中軸線
同樣瀏覽器進行繪制時,在2.5上下各繪制0.5的像素寬度,但與上面的例子不同的是,圖像邊界正好落在整數像素邊界內,合起來正好為1個像素,這個時候,就不需要向兩邊擴展,而是我們預期的(2-3)的1個像素寬度。
同理,我們分別使用兩種方式繪制寬度為2的線段時,效果恰恰相反,在坐標3處繪制的時候,像素正好擴展至2-4,即2個像素,符合我們的預期;而在坐標2.5處繪制時,像素擴展至1.5-3.5,未到邊界,需要補足,就變成了1-4,即3個像素。
建議
在實際應用中,如果想得到更好的體驗,精確的像素值,如果線段的寬度是奇數像素,繪制時以n.5,即半數像素作為中軸線,如果線段的寬度為偶數像素,繪制時以n.0,即整數像素作為中軸線