小程序canvas实现倒计时动画

1,039 阅读2分钟

预期效果

image.png

html

<canvas id="circle-count" type="2d"></canvas>

style样式

#circle-count
    width 120rpx
    height 120rpx

逻辑代码

初始化方法:

initProgress() {
                const query = uni.createSelectorQuery()
                query.select("#circle-count").fields({ node: true, size: true }).exec((res) => {
                    canvas = res[0].node
                    ctx = res[0].node.getContext("2d")
                    // 获取retina屏幕的设备像素比
                    const dpr = uni.getSystemInfoSync().pixelRatio
                    // 根据设备像素比,扩大canvas画布的像素,使1个canvas像素和1个物理像素相等
                    canvas.width = toRpx(120) * dpr 
                    canvas.height = toRpx(120) * dpr
                    // 将绘制比例放大
                    ctx.scale(dpr, dpr)

                    ctx.beginPath() // 开始一个新的路径
                    ctx.fillStyle = "#FF6951" // 设置填充的颜色
                    ctx.lineWidth = toRpx(8) // 设置圆环的宽度
                    ctx.strokeStyle = "#fff" // 设置填充的颜色
                    ctx.arc(toRpx(60), toRpx(60), toRpx(56), startAngle, endAngle)
                    ctx.fill() // 对当前路径进行填充
                    ctx.stroke() // 对当前路径进行描边
                    
                    // 绘制中间矩形
                    drawRoundRect(
                            ctx,
                            toRpx(36),
                            toRpx(36),
                            "#ffffff",
                            toRpx(48),
                            toRpx(48),
                            toRpx(8)
                    )
                })
            }

要注意的是,这里的大小数值不能写死,因为canvas样式是rpx响应式单位,这里也根据rpx计算方法动态计算,toRpx方法如下:

// 转化rpx单位
export function toRpx(val) {
    const res = uni.getSystemInfoSync()
    const scaleRate = res.windowWidth / 375
    return val * scaleRate
}
/**
 * @description: 绘制圆角矩形
 * @param {ctx} ctx 
 * @param {number} x 坐标
 * @param {number} y 坐标
 * @return {bg} 背景色
 * @return {h} 矩形高度
 * @return {w} 矩形宽度
 * @return {radius} 圆角大小
 */
export function drawRoundRect(ctx, x, y, bg, h, w, radius) {
    ctx.beginPath()
    ctx.fillStyle = bg
    //左上角
    ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2)
    ctx.lineTo(x + w - radius, y)
    //右上角
    ctx.arc(x + w - radius, y + radius, radius, Math.PI * 3 / 2, 0)
    ctx.lineTo(x + w, y + h - radius)
    //右下角
    ctx.arc(x + w - radius, y + h - radius, radius, 0, Math.PI / 2)
    ctx.lineTo(x + radius, y + h)
    //左下角
    ctx.arc(x + radius, y + h - radius, radius, Math.PI / 2, Math.PI)
    ctx.lineTo(x, y + radius)
    ctx.fill()
}
// 绘制圆环
    render() {
        const end = startAngle + (endAngle / 60) * (60 - this.time)
        ctx.beginPath() // 开始一个新的路径
        ctx.lineWidth = toRpx(8) // 设置圆环的宽度
        ctx.strokeStyle = "#FFD957" // 设置圆环的颜色
        ctx.lineCap = "round" // 设置圆环端点的形状
        ctx.arc(toRpx(60), toRpx(60), toRpx(56), startAngle, end, false) // 这里最后false代表顺时针方向,如果需要逆时针方向设为true即可
        ctx.stroke() // 对当前路径进行描边
    }    
 // 倒计时定时器,
    handleCountTime() {
        timer = setInterval(() => {
            this.time -= 0.1
            this.render()
            if (time < 0) {
                 // 计时时间到
                 clearInterval(timer)
            }
        }, 100)
    }

最后,可以关注本人公众号及时获取博客内容更新

公众号