环形进度条
发布于 3 年前 作者 kqin 4777 次浏览 来自 分享

动画效果一直都喜欢用setInterval,看到了文档提供了requestAnimationFrame,所以尝试了一下,下面是代码(组件)。

wxml

<view class="progress-container">
    <canvas class="canvas" type="2d" id="posterCanvas"></canvas>
    <view wx:if="{{showText}}" class="num-text">
        <view class="num">{{number}}</view>
        <view class="text">{{text}}</view>
    </view>
</view>

js

Component({
    properties: {
        showText: {
            type: Boolean,
            value: true,
        },
        percent: {
            type: Number,
            value: 0,
        },
        number: {
            type: Number,
            value: 0,
        },
        text: {
            type: String,
            value: '打卡天数',
        },
    },
    data: {},
    attached() {
        this.value = 0;
        this.init();
    },
    methods: {
        init() {
            const query = this.createSelectorQuery();
            query
                .select('#posterCanvas')
                .fields({ node: true, size: true })
                .exec((res) => {
                    const canvas = res[0].node;
                    const ctx = canvas.getContext('2d');
                    const system = wx.getSystemInfoSync();
                    const dpr = system.pixelRatio;
                    const ratio = system.windowWidth / 750;
                    canvas.width = res[0].width * dpr;
                    canvas.height = res[0].height * dpr;
                    ctx.scale(dpr, dpr);
                    // 设置圆环的宽度
                    ctx.lineWidth = parseInt(10 * ratio);
                    // 设置圆环端点的形状
                    ctx.lineCap = 'round';
                    this.drawBottomColor(ctx, ratio);
                    if (this.data.percent !== 0) {
                        const renderLoop = () => {
                            if (this.value <= this.data.percent) {
                                this.render(ctx, ratio);
                                canvas.requestAnimationFrame(renderLoop);
                            }
                        };
                        canvas.requestAnimationFrame(renderLoop);
                    }
                });
        },
        render(ctx, ratio) {
            ctx.clearRect(0, 0, parseInt(750 * ratio), parseInt(240 * ratio));
            this.draw(ctx, ratio);
        },
        draw(ctx, ratio) {
            // 画底色
            this.drawBottomColor(ctx, ratio);
            // 画高亮色
            this.drawActiveColor(ctx, ratio, this.value++);
            ctx.stroke();
        },
        // 底色条
        drawBottomColor(ctx, ratio) {
            ctx.beginPath();
            ctx.strokeStyle = '#F8F8F8';
            ctx.arc(
                parseInt(90 * ratio),
                parseInt(90 * ratio),
                parseInt(85 * ratio),
                -0.5 * Math.PI,
                1.5 * Math.PI,
                false
            );
            ctx.stroke();
        },
        // 高亮进度条
        drawActiveColor(ctx, ratio, percent) {
            ctx.beginPath();
            ctx.strokeStyle = '#00CBA3'; // 设置圆环的颜色
            ctx.arc(
                parseInt(90 * ratio),
                parseInt(90 * ratio),
                parseInt(85 * ratio),
                -0.5 * Math.PI,
                -0.5 * Math.PI + Number(percent / 100) * 2 * Math.PI,
                false
            );
        },
    },
});

回到顶部