您的位置: 首页 >日志>前端技术>详细内容

前端技术

canvas 动画实现圆环倒计时效果

来源:本站原创 发布时间:2022-07-11 08:52:29 浏览次数: 【字体:

最近要做一个圆环倒计时的效果,百度找了好几个圆环倒计时的效果,但跟效果图的设计出入太大了,无法直接拿来使用,只好自己来做一个了。


首先想到的是用css3的动画效果来实现,但研究了一段时间以后,发现扩展性太差了,而且圆圈线条的各种圆角无法实现,最终选择了用 canvas 动画来实现,canvas 动画主要是通过js来控制画画的内容,后期需要实现暂停、结束、超时等相关条件的反馈事件也比较容易。


首先看下圆环倒计时效果:

7d0c19179db24dddafc4679f56a638ec.gif


下面来看下制作这样一个动态的圆环倒计时动画制作过程


一、制作动画前先创建好所需的变量和 canvas 的默认参数

var time = 5, // 每次转圈所用时间,单位:秒
    c_width = 500, // 画布的宽度
    c_height = 500, // 画布的高度
    radius = 90, // 圆圈的直径
    lineWidth =  10, // 圆圈的宽度
    lineColor = "#2C6E98", // 计时圆圈颜色
    backround = "#eeeeee", // 圆圈的底色

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
canvas.width = c_width; // 设置canvas宽度
canvas.height = c_height; // 设置canvas高度
ctx.save();


二、画出圆圈的背景色

画圆圈的背景色其实就是画个圆圈,圆圈的颜色定义为背景色

    //画出圆环的底色
    ctx.translate(c_width / 2, c_height / 2 );
    ctx.beginPath();
    ctx.strokeStyle = backround;
    ctx.lineWidth = lineWidth;
    ctx.arc(0, 0, radius, 0, Math.PI *2 );
    ctx.stroke();

输出结果:

85a1fdff34484e32ada119a62f022c1b.jpg


三、画出倒计时的圆环

倒计时的圆环同样也是画圆圈,跟背景圆圈不同的是,计时圆圈类似于进度条,根据时间的推移,圆圈的角度逐渐变大。例如倒计时完成一半,圆圈的角度刚好就180度,后面圆环的角度会通过js传值,实现动态的变化。下面先来画个90度的圆环

    //画90度圆环
    ctx.translate(c_width / 2, c_height / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.beginPath();
    ctx.strokeStyle = lineColor;
    ctx.lineWidth = lineWidth;
    ctx.arc(0, 0, radius, 0, Math.PI / 180 * 90);
    ctx.stroke();

输出结果:

3814ff96a1774ac786995d59aaa3ac18.jpg


四、画出线条首尾的圆角

虽然倒计时圆环的效果已经基本出来了,但是不是感觉有点生硬。线条的两端缺少圆角的效果,接下来需要把线两端的圆角给补上

731b614d17f2420488791a435c1081d4.jpg


4.1 画出线条开端的圆角

线条开端的圆角我们可以用个小圆形来实现,圆形的半径是线条宽度的一半,然后再通过定位,把小圆形的位置固定再圆圈的顶端。

    //线条开始点的圆角
    ctx.translate(c_width / 2 , c_height / 2 );
    ctx.rotate(-Math.PI / 2);
    ctx.fillStyle = lineColor;
    ctx.beginPath();
    ctx.arc(radius, 0, lineWidth / 2, 0, Math.PI*2);
    ctx.lineTo(0, 0);
    ctx.closePath();
    ctx.fill();

输出效果:

ae8d26205d674f4b9d83a4396adb5acb.jpg

4.2 画出线条末端的圆角

线条末端的这个圆角同样可以用个小圆形来实现,但这个圆形有点特别,中间有个白色的小点,同时还要跟圆环的计时来同步做圆周运动

    //跟随旋转的小圆点
    ctx.translate(c_width / 2, c_height / 2 ); // 画布平移到设定的中心坐标
    ctx.beginPath();
    ctx.fillStyle = "#ffffff";
    ctx.strokeStyle = lineColor;
    ctx.rotate(Math.PI / 180 * 90);//根据时间改变角度
    ctx.rotate(-Math.PI / 2);
    ctx.lineWidth = lineWidth/4;
    ctx.arc(radius, 0, lineWidth*3/8 , 0, Math.PI*2);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();

输出效果:

c71bc54d0895492090685da286b7b36a.jpg


五、让圆环动起来

最后,我们把上面这些代码组合起来,通过 settimeout 或 setinterval 来重复执行画圆的方法,没执行一次圆圈的角度增加一点,具体每次执行所需的角度可以通过这个公式来计算


当前角度 = 360 - 剩余时间 /  (总时间 / 360)


完整代码:

var time = 5, // 每次转圈所用时间,单位:秒
    c_width = 500, // 画布的宽度
    c_height = 500, // 画布的高度
    radius = 90, // 圆圈的直径
    lineWidth =  10, // 圆圈的宽度
    lineColor = "#2C6E98", // 计时圆圈颜色
    backround = "#eeeeee", // 圆圈的底色
    interTime = 50; //执行的阶段时间,数组越少越流畅,但越耗资源,单位:毫秒

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
canvas.width = c_width; // 设置canvas宽度
canvas.height = c_height; // 设置canvas高度
ctx.save();

function drawCircle(angle){
    ctx.clearRect(0, 0, c_width, c_height);
    ctx.save();

    //画出圆环的底色
    ctx.translate(c_width / 2, c_height / 2 );
    ctx.beginPath();
    ctx.strokeStyle = backround;
    ctx.lineWidth = lineWidth;
    ctx.arc(0, 0, radius, 0, Math.PI *2 );
    ctx.stroke();

    ctx.restore();
    ctx.save();

    //画圆环
    ctx.translate(c_width / 2, c_height / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.beginPath();
    ctx.strokeStyle = lineColor;
    ctx.lineWidth = lineWidth;
    ctx.arc(0, 0, radius, 0, Math.PI / 180 * angle);
    ctx.stroke();

    ctx.restore();
    ctx.save();

    //线条开始点的圆角
    ctx.translate(c_width / 2 , c_height / 2 );
    ctx.rotate(-Math.PI / 2); // 画布旋转 -90度
    ctx.fillStyle = lineColor;
    ctx.beginPath();
    ctx.arc(radius, 0, lineWidth / 2, 0, Math.PI*2);
    ctx.lineTo(0, 0);
    ctx.closePath();
    ctx.fill();

    ctx.restore();
    ctx.save();

    //跟随旋转的小圆点
    ctx.translate(c_width / 2, c_height / 2 ); // 画布平移到设定的中心坐标
    ctx.beginPath();
    ctx.fillStyle = "#ffffff";
    ctx.strokeStyle = lineColor;
    ctx.rotate(Math.PI / 180 * angle);//根据时间改变角度
    ctx.rotate(-Math.PI / 2);
    ctx.lineWidth = lineWidth/4;
    ctx.arc(radius, 0, lineWidth*3/8 , 0, Math.PI*2);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();

    //重新加载、保存默认设置,不影响下次画板
    ctx.restore();
    ctx.save();
}

var msSecondsTime = time * 1000;
var timeangle = 0;
var remainTime = msSecondsTime;
setInterval(function() {
    timeangle = 360 - remainTime / (msSecondsTime / 360);
    drawCircle(timeangle);
    if(remainTime > 0 ){
        remainTime = remainTime - interTime;
    }else{
        remainTime = msSecondsTime;
    }
}, interTime);


×

用户登录