效果以下:javascript
能夠展現整個圓、半圓以及任意角度弧形(左右對稱)的進度條。總體思路以下:html
先肯定展現的形狀,是整個圓、半圓仍是通常的弧形java
把肯定好形狀的圓弧均分100等份,計算出每一份所佔的弧度canvas
灰色圓弧佔100份,紅色圓弧最終佔的份數由參數肯定函數
設置setInterval定時器,重複執行畫圖操做優化
清空畫布動畫
先畫灰色的圓弧,佔100份spa
再畫紅色的圓弧:紅色圓弧的份數從0開始,每次加1scala
畫紅色圓弧末端的紅色圓:難點在於根據角度肯定紅色圓的圓心,這裏面涉及到三角函數,在草稿紙上畫個圖就大體明白了code
當紅色圓弧的份數達到指定值(傳的參數)的時候,清除定時器
完整代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> <title>Canvas</title> </head> <body> <canvas id="canvas" width="300" height="300"></canvas> <script> draw(66); /** * [順時針方向畫圖,起始點在左側] * @param {[number]} percent [所佔的進度百分比,好比66%,則傳66便可,0 <= percent <= 100] * @param {[number]} sR [圓弧起始角度,可不傳,默認是π/2,Math.PI/2 <= sR < 3/2 * Math.PI] */ function draw(percent, sR) { if (percent < 0 || percent > 100) { return; } if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) { return; } var canvas = document.querySelector('#canvas'), cxt = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height, baseColor = '#e1e1e1', coverColor = '#fe4d43', PI = Math.PI, sR = sR || 1/2 * PI; // 默認圓弧的起始點弧度爲π/2 var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 紅圈的終點弧度 var step = (PI + (PI - sR) * 2)/100; // 一個1%對應的弧度大小 var text = 0; // 顯示的數字 var timer = setInterval(function() { cxt.clearRect(0, 0, cWidth, cHeight); var endRadian = sR + text * step; // 畫灰色圓弧 drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2); // 畫紅色圓弧 drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2); // 畫紅色圓頭 // 紅色圓頭其實就是一個圓,關鍵的是找到其圓心,涉及到三角函數知識,本身畫個圖一看就明瞭 var angle = 2*PI - endRadian; // 轉換成逆時針方向的弧度(三角函數中的) xPos = Math.cos(angle) * 80 + cWidth/2; // 紅色圓 圓心的x座標 yPos = -Math.sin(angle) * 80 + cHeight/2; // 紅色圓 圓心的y座標 drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2); // 數字 cxt.fillStyle = coverColor; cxt.font = '40px PT Sans'; var textWidth = cxt.measureText(text+'%').width; cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15); text++; if (endRadian.toFixed(2) >= finalRadian.toFixed(2)) { clearInterval(timer); } }, 30); function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) { cxt.beginPath(); cxt.lineCap = "round"; cxt.strokeStyle = color; cxt.lineWidth = lineWidth; cxt.arc(x, y, r, sRadian, eRadian, false); cxt.stroke(); } } </script> </body> </html>
關於動畫部分,能夠使用requestAnimationFrame
作優化,函數改寫以下:
function draw(percent, sR) { if (percent < 0 || percent > 100) { return; } if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) { return; } var canvas = document.querySelector('#canvas'), cxt = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height, baseColor = '#e1e1e1', coverColor = '#fe4d43', PI = Math.PI, sR = sR || 1/2 * PI; // 默認圓弧的起始點弧度爲π/2 var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 紅圈的終點弧度 var step = (PI + (PI - sR) * 2)/100; // 一個1%對應的弧度大小 var text = 0; // 顯示的數字 window.requestAnimationFrame(paint); function paint() { cxt.clearRect(0, 0, cWidth, cHeight); var endRadian = sR + text * step; // 畫灰色圓弧 drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2); // 畫紅色圓弧 drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2); // 畫紅色圓頭 // 紅色圓頭其實就是一個圓,關鍵的是找到其圓心,涉及到三角函數知識,本身畫個圖一看就明瞭 var angle = 2*PI - endRadian; // 轉換成逆時針方向的弧度(三角函數中的) xPos = Math.cos(angle) * 80 + cWidth/2; // 紅色圓 圓心的x座標 yPos = -Math.sin(angle) * 80 + cHeight/2; // 紅色圓 圓心的y座標 drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2); // 數字 cxt.fillStyle = coverColor; cxt.font = '40px PT Sans'; var textWidth = cxt.measureText(text+'%').width; cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15); text++; if (endRadian.toFixed(2) < finalRadian.toFixed(2)) { window.requestAnimationFrame(paint); } } function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) { cxt.beginPath(); cxt.lineCap = "round"; cxt.strokeStyle = color; cxt.lineWidth = lineWidth; cxt.arc(x, y, r, sRadian, eRadian, false); cxt.stroke(); }