canvas 动画实现圆环倒计时效果
最近要做一个圆环倒计时的效果,百度找了好几个圆环倒计时的效果,但跟效果图的设计出入太大了,无法直接拿来使用,只好自己来做一个了。
首先想到的是用css3的动画效果来实现,但研究了一段时间以后,发现扩展性太差了,而且圆圈线条的各种圆角无法实现,最终选择了用 canvas 动画来实现,canvas 动画主要是通过js来控制画画的内容,后期需要实现暂停、结束、超时等相关条件的反馈事件也比较容易。
首先看下圆环倒计时效果:
下面来看下制作这样一个动态的圆环倒计时动画制作过程
一、制作动画前先创建好所需的变量和 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();
输出结果:
三、画出倒计时的圆环
倒计时的圆环同样也是画圆圈,跟背景圆圈不同的是,计时圆圈类似于进度条,根据时间的推移,圆圈的角度逐渐变大。例如倒计时完成一半,圆圈的角度刚好就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();
输出结果:
四、画出线条首尾的圆角
虽然倒计时圆环的效果已经基本出来了,但是不是感觉有点生硬。线条的两端缺少圆角的效果,接下来需要把线两端的圆角给补上
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();
输出效果:
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();
输出效果:
五、让圆环动起来
最后,我们把上面这些代码组合起来,通过 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);
用户登录
还没有账号?
立即注册