圆形进度条

365 阅读2分钟

直接上代码

let canvas = document.getElementById('myCanvas')
let ctx = canvas.getContext('2d')

ctx.strokeStyle = '#0000ff';
let start = 0       // 开始角度,  暂时不用,  都从顶部开始
let end = 0.6       // progress
let count = 0       // 速度计数
let sR = 15  // 小圆弧的半径
let bR = 100 // 大圆弧外圈的半径
let {width, height} = canvas.getBoundingClientRect()
let bX = width / 2  // 大圆弧的圆心坐标  x
let bY = height / 2  // 大圆弧的圆心坐标  y
let color = '#00f'

//     x, y  圆心坐标   r 半径
//  arc( x, y, r, startAngle, endAngle, 方向(false顺时针  true逆时针)

// 尾的 起始位置要变化   圆心 位置变化
// 圆心从 x = bX  y = bY - bR + 2*sR  大圆外圈的下面为起点
// 到   x = bX  y = bY + bR - 2*sR  大圆外圈的  上面为终点
// 圆心怎么变   bX ,  bY 为圆心  半径为bR - sR 的一个圆
// 起点位置怎么变 bX, bY 为圆心   半径为bR - 2*sR 的一个愿
// (x - bX)^2  + (y - bY)^2  = (bR - sR)^2

// 点p 在 x = bX  y = bY - bR + sR 的时候
// 角度每增长0.02Pi   x和y 坐标的增量
//  r*sin(0.02Pi)     r - r*cos(0.02Pi)

//  里面的圆统一从0.5 PI  开始画
requestAnimationFrame(function a(time) {
    count = c_bezier(0, 0, 0.58, 1, time / 1000)
    console.log(count * 1000)
    ctx.clearRect(0, 0, width, height)
    ctx.beginPath()
    ctx.fillStyle = color
    // 外圈 只有结束角度需要改变 
    ctx.arc(bX, bY, bR, Math.PI * 1.5, Math.PI * 1.5 + Math.PI * 2 * count, false);

    // 尾  圆心,  起始角  结束角  都需要改变  尾部的圆是半圆, 不能闭合
    ctx.arc(bX + (bR - sR) * Math.sin(Math.PI * 2 * count), bY - bR + sR + (bR - sR) * (1 - Math.cos(Math.PI * 2 * count)), sR, (Math.PI * 1.5 + Math.PI * 2 * count) % (Math.PI * 2), (Math.PI * 1.5 + Math.PI + Math.PI * 2 * count)% (Math.PI * 2), false)// 绘制路径

    // 内圈 
    ctx.arc(bX, bY, bR - 2 * sR, (Math.PI * 0.5 + Math.PI + Math.PI * 2 * count)% (Math.PI * 2), Math.PI * 1.5, true)

    // 头 如果开始角度不变, 就不需要变, 位置固定。
    // path.moveTo(bX, bY - bR + 2 * sR)
    ctx.arc(bX, bY - bR + sR, sR, Math.PI * 0.5, Math.PI * 0.5 - Math.PI, false)

    ctx.closePath()
    ctx.fill()
    // 在尾部画一个空心圆  r = sR / 4
    // 起始点  是起始点  圆心是圆心
    ctx.beginPath()
    ctx.fillStyle = '#fff'
    ctx.arc(bX + (bR - sR) * Math.sin(Math.PI * 2 * count), bY - bR + sR + (bR - sR) * (1 - Math.cos(Math.PI * 2 * count)), sR / 4, Math.PI * 0.5 + Math.PI * 2 * count, Math.PI * 0.5 + 2 * Math.PI + Math.PI * 2 * count, false)
    ctx.closePath()
    ctx.fill()
    if (count < end) {
        requestAnimationFrame(a)
    }
})

// 缓动函数
function c_bezier(p0,p1,p2,p3,t){
    return p0*(1-t)*(1-t)*(1-t)+3*p1*t*(1-t)*(1-t)+3*p2*t*t*(1-t)+p3*t*t*t;
}

复制可直接使用。

最近需要用一个圆形的进度条,在头部还要有个小圈圈, 但是网上的版本好像都是画一条线,设置线宽, 并不能满足要求, 所以只好自己写一个。
count是每一次绘制的时候的进度, 不过这个缓动函数虽然是先快后慢, 但是还是看不大出来效果。

颜色可以设置渐变, 可以设置阴影,直接给ctx设置shadow就行。

效果

2.png