使用canvas绘制动画版的环形进度条

694 阅读1分钟

效果图

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: space-around;
            align-items: center;
            height: 100vh;
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container {
            width: 100px;
            height: 100px;
            border: 1px dashed skyblue;
        }
        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
    <script src="./draw.js"></script>
</head>
<body>
    <div class="container">
        <canvas id="canvas" width="200" height="200"></canvas>
    </div>
    <script>
        const canvas = document.getElementById('canvas')
        drawRing({
            drawingEle: canvas,
            percent: 70,
            bgColor: "#eef7e4",
            forecolor: "#85d824",
            lineWidth: 16,
            fontSize: 40,
            fontFamily: '微软雅黑'
        })
    </script>
</body>
</html>

以下为draw.js


const drawRing = function({
    drawingEle = null,
    percent = 100,
    bgColor =  "#eef7e4",
    forecolor = "#85d824",
    lineWidth =  16,
    fontSize =  40,
    fontFamily = '微软雅黑',
}) {
     /*
        @drawingEle: 绘制对象
        @percent:绘制圆环百分比, 范围[0, 100]
        @bgcolor: 绘制圆环的背景色,颜色代码
        @forecolor: 绘制圆环的前景色,颜色代码
        @lineWidth: 绘制圆环的环形宽度
        @fontSize: 绘制圆环中的文本的字体大小
        @fontFamily: 绘制圆环中的文本的字体样式  
    */
    if (!drawingEle) throw new Error('绘制对象不能为空')
    const context = drawingEle.getContext('2d')
    // 获取圆的圆心和半径
    const center_x = drawingEle.width / 2
    const center_y = drawingEle.height / 2
    const radius = center_x - lineWidth
    // 每绘制一帧就走一步
    let step = 0
    // 每一步的步伐长度(弧度)
    let radian = Math.PI * 2 / 100


    // 绘制背景圆环
    function backgroundCircle() {
        //save和restore可以保证样式属性只运用于该段canvas元素
        context.save()
        context.beginPath()
        context.lineWidth = lineWidth
        context.strokeStyle = bgColor
        context.arc(center_x, center_y, radius, 0, 2*Math.PI, false)
        context.stroke()
        context.closePath()
        context.restore()
    }
    // 绘制运动圆环
    function foregroundCircle(step) {
        context.save()
        context.beginPath()
        context.lineWidth = lineWidth
        context.strokeStyle = forecolor
        context.arc(center_x, center_y, radius,  -Math.PI/2, -Math.PI/2 + step * radian, false)
        context.stroke()
        context.closePath()
        context.restore()

    }
    // 绘制文字
    function text(step) {
        context.save()
        context.fillStyle = forecolor
        context.font = `${fontSize}px ${fontFamily}`
        const str = step.toFixed(0) + '%'
        const textWidth = context.measureText(str).width
        const textX = center_x - textWidth/2
        const textY = center_y + fontSize/2
        context.fillText(str, textX, textY)
        context.restore()
    } 
    // 执行动画
    (function drawFrame() {
        window.requestAnimationFrame(drawFrame) // 类似于定时器,执行频率为每秒60帧,所以一帧16秒
        context.clearRect(0, 0, drawingEle.width, drawingEle.height)
        backgroundCircle()
        foregroundCircle(step)
        text(step)
        if (step >= percent) return
        step += 1
    }())
}