by Conmajia SN: S22-W1M
由來
看到一篇帖子《vue實用組件——圓環百分比進度條》,讓我想起了很多年前我在WinForm下仿制過的Chrome進度條。

那時候我經常半夜接着酒勁兒用我的小破電腦跟GDI+ 較真兒,一轉眼都快10年了。這日子過得還真是讓人唏噓呢。本來想翻出來紀念一下,可是以前的東西早他媽不知扔哪兒了,有點兒遺憾。再看看上邊兒那進度條是Vue的,我現在還沒本事玩兒,可是又手癢癢,先用H5做一個湊合吧。反正也是打發時間,少打幾圈兒麻將唄。
特性 & Demo
說實在的,單進度條非做一圓,別的屁功能沒有,真的沒意思,不如來點兒添頭,把一堆進度條都給揉里邊兒。我相信一定有人能用上,別客氣。
- 可以堆疊任意數量子進度條
- 計算總進度
- 原生H5
![]() |
![]() |
![]() |
最后的效果就上邊兒那圖的把式。如果你的瀏覽器支持H5,那么你應該可以看到下面這個動態演示。你可以點擊按鈕試試看用在網頁上的實際效果。
代碼
全是基礎的東西。
非常簡單,略去了一些不重要的東西(我討厭整頁整頁都是代碼的文章)。最最基礎的H5動畫,沒啥可說的,我寫了點兒注釋。
// ctx 為 canvas context
var ctx = g.getContext('2d');
// (x, y) 中心點
var x = g.width / 2, y = g.height / 2;
// p 保存所有子進度條,value 0-100%
var p = [{
value: 0,
color: 'orange'
},
...
{
value: 0,
color: 'blue'
}];
// 演示專用(略):隨機更新各個進度條 value,模擬走進度
function inc(a) {
...
}
// 計算總進度
function getTotal(a) {
var t = 0;
for(var i = 0; i < a.length; i++) {
t += a[i].value;
}
return t / a.length;
}
// 畫圓環。start、stop 起止點,以 scale 划分 360 度
function drawBand(start, stop, color = 'silver', scale = 100) {
var div = Math.PI * 2 / scale;
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = 30;
ctx.beginPath();
ctx.arc(x, y, 100, start * div, stop * div, false);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
// 畫所有子進度條
function drawProg(a) {
for (var i = 0; i < a.length; i++) {
var s = 0;
// 計算起點
for (var j = 0; j < i; j++) {
s += a[j].value;
}
s /= a.length;
drawBand(s, s + a[i].value / a.length, a[i].color);
s = s + a[i].value;
}
}
// 中心總進度文字
function drawLabel(n) {
...
}
// 動畫循環
(function drawFrame() {
window.requestAnimationFrame(drawFrame);
ctx.clearRect(0, 0, g.width, g.height); // 清空繪圖區
drawBand(0, 100); // 畫底環(0-100 刻度,默認色)
drawLabel(total(p)); // 畫進度文字
drawProg(p); // 畫所有進度條
inc(p); // 模擬更新,演示專用
}());
代碼就這么簡單。老實說,其實這挺無聊的,bootstrap自帶的進度條就能堆疊(當然那個是直線型的);隨便用個Chart.js、ECharts.js,也能輕輕松松實現這個效果,比這好上一萬倍。

まあ,就當練手了唄,反正我的H5連門兒都還沒入,弄出來也算熟悉熟悉,挺好的。
The End. \(\Box\)
var c = ['Navy', 'Blue', 'Aqua', 'Teal', 'Green', 'Lime', 'Yellow', 'Orange', 'Red', 'Maroon', 'Fuchsia']; var auto = true; var g = document.getElementById('canvas1'); var ctx = g.getContext('2d'); var x = g.width / 2; var y = g.height / 2; var rad = Math.PI * 2 / 100; var p = [{ speed: 0.2, value: 0, color: 'orange' }, { speed: 0.1, value: 0, color: 'blue' }, { speed: 0.2, value: 0, color: 'green' }, { speed: 0.4, value: 0, color: 'red' }]; $('#add').click(function(e) { e.preventDefault(); auto = true; add(); }); $('#remove').click(function(e) { e.preventDefault(); auto = true; remove(); }); $('#shuffle').click(function(e) { e.preventDefault(); auto = true; shuffle(); }); function add() { p.push({ speed: Math.random(), value: 0, color: c[Math.floor(Math.random() * (c.length))] }); } function remove() { p.pop(); } function shuffle() { for (var i = 0; i < p.length; i++) { p[i].value = Math.floor(Math.random() * 100); p[i].speed = Math.random(); } p=_.shuffle(p); } function inc(a) { if (!auto) return false; for (var i = 0; i < a.length; i++) { if (a[i].value <= 100) a[i].value += a[i].speed; } if (total(a) >= 100) { for (var i = 0; i < a.length; i++) { a[i].value = 0; } } } function total(a) { var t = 0; for (var i = 0; i < a.length; i++) { t += a[i].value; } return t / a.length; } function draw(s, l, p) { ctx.save(); ctx.strokeStyle = p.color; ctx.lineWidth = 30; ctx.beginPath(); ctx.arc(x, y, 100, Math.PI / 2 + s * rad, Math.PI / 2 + (s + p.value / l) * rad, false); ctx.stroke(); ctx.closePath(); ctx.restore(); } function drawProg(a) { for (var i = 0; i < a.length; i++) { var s = 0; for (var j = 0; j < i; j++) { s += a[j].value; } s /= a.length; draw(s, a.length, a[i]); s = s + a[i].value; } } function drawBand() { ctx.save(); ctx.lineWidth = 30; ctx.strokeStyle = "silver"; ctx.beginPath(); ctx.arc(x, y, 100, 0, Math.PI * 2, false); ctx.stroke(); ctx.closePath(); ctx.restore(); } function drawLabel(n) { ctx.save(); ctx.strokeStyle = "silver"; ctx.font = "40px Arial"; ctx.textAlign = "center"; ctx.fillText(n ? numeral(n).format("0.0") + "%" : "N/A", x, y + 15); ctx.stroke(); ctx.restore(); }(function drawFrame() { window.requestAnimationFrame(drawFrame); ctx.clearRect(0, 0, g.width, g.height); drawBand(); inc(p); drawLabel(total(p)); drawProg(p); }());