vue 实现canvas圆环进度条

469 阅读1分钟

效果如下:

image.png

代码如下:

<template>
    <div>
        <!-- 圆环背景 -->
        <canvas id="canvas" style="width: 100%;height: 100%">
        </canvas>
    </div>
       
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/71c0bcaa7a9d4df0b93840d5765d26a0~tplv-k3u1fbpfcp-watermark.image?)
</template>
 
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5fe8e07943d144b096767fa5fdc853fe~tplv-k3u1fbpfcp-watermark.image?)
<script>
export default {
    // 电量环形图
    name:'electricQuantity',
    props:{
        num:{
            type:Number,
            default:()=>0
        }
    },
    data(){
        return{
            defaultValue:0,
            timer:null
        }
    },
    created(){
        this.$nextTick(()=>{
            this.drawCanvas()
        })
    },
    watch:{
        num:function(){
            this.drawCanvas()
        }
    },
    methods:{
        drawCanvas(){
            var canvas=document.getElementById('canvas');
            canvas.width = 300
            canvas.height = 300
            var ctx=canvas.getContext("2d")
            this.timer = setInterval(()=>{
                this.drawMove(ctx)
            },5)
        },
        drawMove(ctx){
            ctx.clearRect(0, 0, 300, 300);
            const {defaultValue,num} = this
            // 外部圆环
            ctx.lineWidth = 2
            ctx.beginPath();
            ctx.arc(150,150,150,0,Math.PI * 2,false);
            var canvasGradient = ctx.createLinearGradient(150, 150, 40, 150);
            // ctx.strokeStyle='#fff';
            canvasGradient.addColorStop(0, "#289EFF");
            canvasGradient.addColorStop(0.12, "#00EBCE");
            //将fillStyle的属性值设为该CanvasGradient对象
            ctx.strokeStyle = canvasGradient;
            ctx.closePath()
            ctx.stroke();
            // 内部空槽
            ctx.lineWidth = 23
            ctx.beginPath();
            ctx.arc(150,150,120,0,Math.PI * 2,false);
            ctx.strokeStyle='rgb(29,39,53)';
            ctx.closePath()
            ctx.stroke();
            if(defaultValue>=num){
                this.defaultValue = num
                clearInterval(this.timer)
            }else{
                this.defaultValue = this.defaultValue + 1
            }
            ctx.lineWidth = 23
            ctx.beginPath();
            ctx.arc(150,150,120,Math.PI*1.5,this.defaultValue?Math.PI * ((this.defaultValue/100 -0.25)*2-0.0001):Math.PI*1.5,false);
            var canvasGradient = ctx.createLinearGradient(150, 0, 150, 300);
            canvasGradient.addColorStop(0, "#289EFF");
            canvasGradient.addColorStop(1, "#00EBCE");
            ctx.strokeStyle = canvasGradient;
            // ctx.closePath()
            ctx.stroke();
            // 文字部分
            if(this.defaultValue >= 100){
                ctx.font = "bold 50px arial";
            }else{
                ctx.font = "bold 70px arial";
            }
            ctx.fillStyle='#02D3FD';
            ctx.fillText(this.defaultValue,105,160);
            let numWidth = ctx.measureText(this.defaultValue).width
            ctx.font = "bold 20px arial";
            ctx.fillStyle='#02D3FD';
            ctx.fillText("%",110+numWidth,160);
            ctx.font = "23px arial";
            ctx.fillStyle='#02D3FD';
            ctx.fillText("电量剩余",105,190);
            // 起点小圆
            ctx.beginPath();
            ctx.arc(150, 10, 5, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fillStyle = '#27A0FE';
            ctx.fill();
            // 终点小圆
            let x = 150 + Math.cos(this.defaultValue?Math.PI * ((this.defaultValue/100 -0.25)*2-0.0001):Math.PI*1.5) * 140
            let y = 150 + Math.sin(this.defaultValue?Math.PI * ((this.defaultValue/100 -0.25)*2-0.0001):Math.PI*1.5) * 140
            ctx.beginPath();
            ctx.arc(x, y, 5, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fillStyle = '#27A0FE';
            ctx.fill();
        }
 
    }, 
}
</script>

感觉有很多不妥,欢迎大佬指正 

记录萌新第一步