依然是這個簡單的項目。html
因爲使用JS+CSS不能實現圓角的效果(以下圖,主要使用到了CSS3的transform屬性),因此特意研究了一下怎麼使用canvas來100%復原設計稿。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對象上。具體以下:bash
//這裏也須要處理兼容性問題
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個步驟。ui
理解完了這步之後,咱們繼續閱讀canvas的API文檔。個人目的是實現上圖中的圓角效果。能夠看到,上圖中的圓角效果其實是經過兩個有必定寬度的圓弧組成的,其中第一個圓弧是半圓,第二個圓弧是有必定角度的扇形。canvasContext對象提供了arc()方法畫圓。這個方法接收6個參數,其中第1、二個參數爲圓心座標點,第三個參數爲圓的半徑,第4、五個參數指定了畫圓的起始角度和結束角度,起始角度是以三點鐘的方向來進行計算的。第六個參數爲boolen類型,指定畫圓是順時針仍是逆時針。第六個參數是可選的,在不指定時,默認以順時針方向畫圓。this
arc(x, y, radius, startDeg, endDeg, true);spa
咱們不指定第六個參數,指定圓心的位置爲(60, 60),指定半徑爲50,開始角度爲Math.PI,結束角度爲2*Math.PI,這樣咱們就畫出來一個半圓啦!prototype
ctx.arc(60, 60, 50, Math.PI, 2*Math.PI)
複製代碼
可是很快咱們就發現另外一個問題:瀏覽器中並無咱們畫的半圓(白色部分爲canvas)。這是爲何呢?設計
緣由很簡單,canvasContext畫圖結束時,須要指定是畫出來的路徑是描邊(stroke方法)仍是填充(fill方法)。咱們兩個方法都試試看看獲得的結果。
ctx.stroke();
//ctx.fill();
複製代碼
//ctx.stroke();
ctx.fill();
複製代碼
這些概念都很是直觀。能夠看得出來,canvas實際上在最大程度模擬現實生活中的畫畫。想要實現上圖的進度條效果,顯然須要使用到的是stroke()方法。這樣咱們就得到了一個半圓。不過,畫出來的半圓的邊框顏色是黑色,看上去彷佛也沒有寬度,起始點和結束點也不是圓角。咱們繼續閱讀API文檔,發現這些樣式在API中都有,他們分別是strokeStyle、lineWidth和lineCap,咱們把這三個樣式都設置一下。
ctx.strokeStyle = 'orange';
ctx.lineWidth = 10;
ctx.lineCap = 'round'
複製代碼
半圓進度條就畫出來了!
依樣畫葫蘆,咱們再畫一個20%的進度條。咱們發現畫出來的不是咱們想要的效果。這是爲何呢?
ctx.arc(60,60,50,Math.PI,1.2*Math.PI);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.lineCap = 'round';
//注意,這篇文章以前的代碼沒有以stroke()方法結尾,特意作了一個修改
ctx.stroke();
複製代碼
其實也很好理解,JS中後面的代碼會覆蓋前面的代碼。畫20%進度條的代碼基本上和畫半圓的進度條是同樣的,所以前面的代碼就被後面的覆蓋了。對應現實中的畫畫,就是這裏的代碼實現的畫畫是連筆的,沒有中斷。上述的代碼實現的效果是先畫一個半圓,而後畫筆再移到了第二個進度條的起始點(對應圖中紅色的橫線),並完成20%進度條的繪畫。因爲最後邊框的顏色指定爲紅色,所以在頁面看不出第二個20%進度條。
那實際上,咱們想要的效果是完成第一個半圓之後,把畫筆從畫布上移開,移動到20%進度條的起始點,再繼續完成20%進度條的繪畫。API中也提供了對應的方法:beginPath()。咱們把這個方法放上去看看效果。
ctx.beginPath();
ctx.arc(60,60,50,Math.PI,1.2*Math.PI);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.lineCap = 'round';
ctx.stroke();
複製代碼
咱們看到加上了beginPath()方法之後,不但沒有了前面紅色的橫線,並且還保留了第一個半圓進度條的樣式。這樣,咱們就百分百復現了原型圖中有圓角的進度條。按照這個思路去繼續看API的其它方法和屬性,是否是就一目瞭然了呢?
爲了方便伸手黨,把以上代碼整合放在這裏了。
<--!html部分-->
<canvas id="canvas">您的瀏覽器不支持canvas</canvas>
//JS部分
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
if(!ctx) {
console.log("該瀏覽器不支持canvas")
} else {
ctx.arc(60, 60, 50, Math.PI, 2 * Math.PI);
ctx.strokeStyle = "orange";
ctx.lineWidth = "10";
ctx.lineCap = "round";
ctx.stroke();
ctx.beginPath();
ctx.arc(60, 60, 50, Math.PI, 1.2 *Math.PI);
ctx.strokeStyle = "red";
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.stroke();
}
複製代碼
爲了方便你們本身設置進度條,這裏再寫了一個類。
/*
*radius:進度條半徑;innerColor:內部進度條顏色;outerColor:外部進度條顏色;lineWidth:進度條寬度
*/
function Progress(radius, innerColor, outerColor, lineWidth) {
this.radius = radius;
this.innerColor = innerColor;
this.outerColor = outerColor;
this.lineWidth = lineWidth;
this.drawProgress();
}
Progress.prototype = {
drawProgress: function() {
var radius = this.radius;
var innerColor = this.innerColor;
var outerColor = this.outerColor;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
if(!ctx) {
console.log("該瀏覽器不支持canvas")
} else {
ctx.arc(radius + 10, radius + 10, radius, Math.PI, 2 * Math.PI);
ctx.stroke();
ctx.strokeStyle = outerColor;
ctx.lineWidth = "10";
ctx.lineCap = "round";
ctx.beginPath();
ctx.arc(radius + 10, radius + 10, radius, Math.PI, 1.2 *Math.PI);
ctx.stroke();
ctx.strokeStyle = innerColor;
ctx.lineWidth = 10;
ctx.lineCap = "round";
}
}
}
複製代碼
和HTML有些不一樣,小程序提供了createCanvasContext()方法獲取canvasContext。
另外,小程序中canvasContext的屬性還支持經過對應的方法來設置。
//如下兩行代碼是等價的
ctx.fillStyle = "red";
ctx.setFillStyle('red');
複製代碼
最後,小程序除了須要以stroke()或者fill()結尾外,還要在最後加draw()方法,不然對應的頁面不會顯示繪製的圖像或內容。