詳解JavaScript+Canvas繪制環(huán)形進(jìn)度條
效果圖
思考
移動端的場景里經(jīng)常會出現(xiàn)環(huán)形進(jìn)度條的功能,在實(shí)現(xiàn)這個功能前,我預(yù)想的解決方案大致有: echarts、antv、canvas、svg
前面兩種第三方提供的解決方案當(dāng)然是簡單,拿到案例修整一下即可,但是需要下載依賴,而且代碼量不小。有沒有不需要依賴第三方包,采用原生的寫法,獨(dú)立封裝成一個組件,降低耦合,而且性能優(yōu)越?
當(dāng)然,那就主要介紹canvas的使用
實(shí)現(xiàn)思路
可以展示整個圓、半圓以及任意角度弧形(左右對稱)的進(jìn)度條。整體思路如下:
1.先確定展示的形狀,是整個圓、半圓還是一般的弧形
2.把確定好形狀的圓弧均分100等份,計算出每一份所占的弧度
3.灰色圓弧占100份,紅色圓弧最終占的份數(shù)由參數(shù)確定
4.設(shè)置setInterval定時器,重復(fù)執(zhí)行畫圖操作
- 清空畫布
- 先畫灰色的圓弧,占100份
- 再畫紅色的圓弧:紅色圓弧的份數(shù)從0開始,每次加1
- 畫紅色圓弧末端的紅色圓:難點(diǎn)在于根據(jù)角度確定紅色圓的圓心,這里面涉及到三角函數(shù),在草稿紙上畫個圖就大致明白了
- 當(dāng)紅色圓弧的份數(shù)達(dá)到指定值(傳的參數(shù))的時候,清除定時器
具體代碼實(shí)現(xiàn)
<!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); /** * [順時針方向畫圖,起始點(diǎn)在左側(cè)] * @param {[number]} percent [所占的進(jìn)度百分比,比如66%,則傳66即可,0 <= percent <= 100] * @param {[number]} sR [圓弧起始角度,可不傳,默認(rèn)是π/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; // 默認(rèn)圓弧的起始點(diǎn)弧度為π/2 var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 紅圈的終點(diǎn)弧度 var step = (PI + (PI - sR) * 2)/100; // 一個1%對應(yīng)的弧度大小 var text = 0; // 顯示的數(shù)字 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); // 畫紅色圓頭 // 紅色圓頭其實(shí)就是一個圓,關(guān)鍵的是找到其圓心,涉及到三角函數(shù)知識,自己畫個圖一看就明了 var angle = 2*PI - endRadian; // 轉(zhuǎn)換成逆時針方向的弧度(三角函數(shù)中的) xPos = Math.cos(angle) * 80 + cWidth/2; // 紅色圓 圓心的x坐標(biāo) yPos = -Math.sin(angle) * 80 + cHeight/2; // 紅色圓 圓心的y坐標(biāo) drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2); // 數(shù)字 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>
關(guān)于動畫部分,可以使用requestAnimationFrame
做優(yōu)化,函數(shù)改寫如下:
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; // 默認(rèn)圓弧的起始點(diǎn)弧度為π/2 var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 紅圈的終點(diǎn)弧度 var step = (PI + (PI - sR) * 2)/100; // 一個1%對應(yīng)的弧度大小 var text = 0; // 顯示的數(shù)字 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); // 畫紅色圓頭 // 紅色圓頭其實(shí)就是一個圓,關(guān)鍵的是找到其圓心,涉及到三角函數(shù)知識,自己畫個圖一看就明了 var angle = 2*PI - endRadian; // 轉(zhuǎn)換成逆時針方向的弧度(三角函數(shù)中的) xPos = Math.cos(angle) * 80 + cWidth/2; // 紅色圓 圓心的x坐標(biāo) yPos = -Math.sin(angle) * 80 + cHeight/2; // 紅色圓 圓心的y坐標(biāo) drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2); // 數(shù)字 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(); }
到此這篇關(guān)于詳解JavaScript+Canvas繪制環(huán)形進(jìn)度條的文章就介紹到這了,更多相關(guān)JavaScript Canvas環(huán)形進(jìn)度條內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
uniapp?動態(tài)組件實(shí)現(xiàn)Tabs標(biāo)簽切換組件(喜馬拉雅app作為案例)
本文以喜馬拉雅app作為案例給大家詳解講解uniapp?動態(tài)組件實(shí)現(xiàn)Tabs標(biāo)簽切換組件功能,在uniapp中實(shí)現(xiàn)動態(tài)組件切換需看uniapp是否支持,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-10-10JavaScript前端實(shí)現(xiàn)壓縮圖片功能
這篇文章主要介紹了JavaScript前端實(shí)現(xiàn)壓縮圖片功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03JS與Ajax Get和Post在使用上的區(qū)別實(shí)例詳解
這篇文章主要介紹了JS與Ajax Get和Post在使用上的區(qū)別實(shí)例詳解的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-065個javascript的數(shù)字格式化函數(shù)分享
Javascript沒有任何內(nèi)建的格式化函數(shù),這里我們通過Google收集了5個javascript的數(shù)字格式化函數(shù),希望對于大家的web開發(fā)能夠帶來方便2011-12-12微信小程序獲取手機(jī)網(wǎng)絡(luò)狀態(tài)的方法【附源碼下載】
這篇文章主要介紹了微信小程序獲取手機(jī)網(wǎng)絡(luò)狀態(tài)的方法,涉及微信小程序wx.getNetworkType函數(shù)檢查網(wǎng)絡(luò)連接狀態(tài)的相關(guān)使用技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12Bootstrap的Carousel配合dropload.js實(shí)現(xiàn)移動端滑動切換圖片
這篇文章主要介紹了bootstrap的Carousel配合dropload.js實(shí)現(xiàn)移動端滑動切換圖片,實(shí)現(xiàn)方法非常簡單,具有參考借鑒價值,需要的朋友可以參考下2017-03-03JS+CSS實(shí)現(xiàn)的藍(lán)色table選項卡效果
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)的藍(lán)色table選項卡效果,通過鼠標(biāo)事件調(diào)用自定義函數(shù)實(shí)現(xiàn)頁面元素樣式的遍歷與動態(tài)切換效果,具有一定參考借鑒價值,需要的朋友可以參考下2015-10-10