前端學習筆記:使用canvas繪製有圓角的百分比進度條

王先生2019加油發表於2019-04-01

前言

依然是這個簡單的專案。

前端學習筆記:使用canvas繪製有圓角的百分比進度條

由於使用JS+CSS不能實現圓角的效果(如下圖,主要使用到了CSS3的transform屬性),所以特地研究了一下怎麼使用canvas來100%復原設計稿。

前端學習筆記:使用canvas繪製有圓角的百分比進度條

HTML中的canvas

第一眼看到canvas相關的API文件時,感覺有點頭大:東西實在太多了,想要一下子學會似乎問題不小。不過看完了相關的文件之後,發現儘管API有點多,但是邏輯還是比較簡單的。

HTML中的canvas通過canvas標籤引入,部分瀏覽器似乎不支援,需要做相容處理,這裡不做過多敘述。

//html中的canvas標籤
<canvas id="canvas">您的瀏覽器不支援canvas</canvas>
複製程式碼

使用canvas的重點在JS部分。在JS中,第一個比較難理解的概念是如何獲取canvasContext。我的第一反應是獲取到了對應的HTML canvas DOM物件,就可以使用相應的API來做圖。但實際上,做圖相關的API不是在DOM物件上,而是在DOM物件下的canvasContext物件上。具體如下:

//這裡也需要處理相容性問題
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d');
if (!ctx) {
    //相容性處理
    console.log("您的瀏覽器不支援畫圖");
} else {
    //開始做圖
}
複製程式碼

這裡我的理解是這樣的。canvas這個概念模擬了現實生活中畫畫的概念。不過,canvas不僅可以在平面(2D空間)上作畫,還可以在3D空間中作畫。在JS中獲取canvas DOM物件,相當於告訴瀏覽器,我要準備畫畫了。那麼,我們要畫的是2D的畫還是3D的畫呢?這就需要我們進一步告知瀏覽器。因此需要2個步驟。

理解完了這步以後,我們繼續閱讀canvas的API文件。我的目的是實現上圖中的圓角效果。可以看到,上圖中的圓角效果實際上是通過兩個有一定寬度的圓弧組成的,其中第一個圓弧是半圓,第二個圓弧是有一定角度的扇形。canvasContext物件提供了arc()方法畫圓。這個方法接收6個引數,其中第一、二個引數為圓心座標點,第三個引數為圓的半徑,第四、五個引數指定了畫圓的起始角度和結束角度,起始角度是以三點鐘的方向來進行計算的。第六個引數為boolen型別,指定畫圓是順時針還是逆時針。第六個引數是可選的,在不指定時,預設以順時針方向畫圓。

arc(x, y, radius, startDeg, endDeg, true);

我們不指定第六個引數,指定圓心的位置為(60, 60),指定半徑為50,開始角度為Math.PI,結束角度為2*Math.PI,這樣我們就畫出來一個半圓啦!

ctx.arc(60, 60, 50, Math.PI, 2*Math.PI)
複製程式碼

但是很快我們就發現另一個問題:瀏覽器中並沒有我們畫的半圓(白色部分為canvas)。這是為什麼呢?

前端學習筆記:使用canvas繪製有圓角的百分比進度條

原因很簡單,canvasContext畫圖結束時,需要指定是畫出來的路徑是描邊(stroke方法)還是填充(fill方法)。我們兩個方法都試試看看得到的結果。

ctx.stroke();
//ctx.fill();
複製程式碼

前端學習筆記:使用canvas繪製有圓角的百分比進度條

//ctx.stroke();
ctx.fill();
複製程式碼

前端學習筆記:使用canvas繪製有圓角的百分比進度條

這些概念都非常直觀。可以看得出來,canvas實際上在最大程度模擬現實生活中的畫畫。想要實現上圖的進度條效果,顯然需要使用到的是stroke()方法。這樣我們就獲得了一個半圓。不過,畫出來的半圓的邊框顏色是黑色,看上去似乎也沒有寬度,起始點和結束點也不是圓角。我們繼續閱讀API文件,發現這些樣式在API中都有,他們分別是strokeStyle、lineWidth和lineCap,我們把這三個樣式都設定一下。

ctx.strokeStyle = 'orange';
ctx.lineWidth = 10;
ctx.lineCap = 'round'
複製程式碼

前端學習筆記:使用canvas繪製有圓角的百分比進度條

半圓進度條就畫出來了!

依樣畫葫蘆,我們再畫一個20%的進度條。我們發現畫出來的不是我們想要的效果。這是為什麼呢?

ctx.arc(60,60,50,Math.PI,1.2*Math.PI);
ctx.stroke();
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.lineCap = 'round';
複製程式碼

前端學習筆記:使用canvas繪製有圓角的百分比進度條

其實也很好理解,JS中後面的程式碼會覆蓋前面的程式碼。畫20%進度條的程式碼基本上和畫半圓的進度條是一樣的,因此前面的程式碼就被後面的覆蓋了。對應現實中的畫畫,就是這裡的程式碼實現的畫畫是連筆的,沒有中斷。上述的程式碼實現的效果是先畫一個半圓,然後畫筆再移到了第二個進度條的起始點(對應圖中紅色的橫線),並完成20%進度條的繪畫。由於最後邊框的顏色指定為紅色,因此在頁面看不出第二個20%進度條。

那實際上,我們想要的效果是完成第一個半圓以後,把畫筆從畫布上移開,移動到20%進度條的起始點,再繼續完成20%進度條的繪畫。API中也提供了對應的方法:beginPath()。我們把這個方法放上去看看效果。

ctx.beginPath();
ctx.arc(60,60,50,Math.PI,1.2*Math.PI);
ctx.stroke();
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.lineCap = 'round';
複製程式碼

前端學習筆記:使用canvas繪製有圓角的百分比進度條

我們看到加上了beginPath()方法以後,不但沒有了前面紅色的橫線,而且還保留了第一個半圓進度條的樣式。這樣,我們就百分百復現了原型圖中有圓角的進度條。按照這個思路去繼續看API的其它方法和屬性,是不是就一目瞭然了呢?

小程式中的canvas

和HTML有些不同,小程式提供了createCanvasContext()方法獲取canvasContext。

另外,小程式中canvasContext的屬性還支援通過對應的方法來設定。

//以下兩行程式碼是等價的
ctx.fillStyle = "red";
ctx.setFillStyle('red');
複製程式碼

最後,小程式除了需要以stroke()或者fill()結尾外,還要在最後加draw()方法,否則對應的頁面不會顯示繪製的影象或內容。

相關文章