计时器(canvas版)

1,406 阅读1分钟

相信大家都用过google身份验证器,每30s刷新一次,然后更新6位验证码。今天我们就来写一个它的计时器。它有一个特点就是:第一圈并不是从30s开始计时,可能是26s,也可能是11s,完全跟当前时间有关系。所以我们要用Date.now()取值。效果如下:

效果

1.html

我们需要2个canvas,一个作为前景,一个作为背景,前景每秒绘制一次,背景只绘制一次。

<div class='wrap'>
  <canvas class='canvas front' width='200' height='200'></canvas>
  <canvas class='canvas back' width='200' height='200'></canvas>
</div>

2.css

使前景和背景分层,不然前景会覆盖掉背景,背景不显示。

.wrap{
  position:relative;
}
/*  使其脱离文档流  */
.front{
  z-index:100;
  position:absolute; 
}
.back{
  position:absolute;
  left:0px;
  right:0px;
}

3.前景

前景画很多次,需传入参数

function drawCircle(n){
  if(n == 0) n = 30;
  context.beginPath();
  context.strokeStyle = '#508bd9';
  context.lineWidth = 20;
  context.arc(centerX,centerY,50,-Math.PI/2, -Math.PI/2 + n*rad,true);
  //显示数字
  context.fillStyle = "#555";
  context.font = '30px Arial';
  context.textAlign = "center";
  context.textBaseline = "middle";
  context.fillText((30-n==0?30:30-n),centerX ,centerY);
  context.stroke();
}

4.背景

背景只画一次

function drawBackCircle(){
  var backCanvas = document.getElementsByClassName('canvas')[1],
      cxt = backCanvas.getContext('2d');
  cxt.save();
  cxt.beginPath();
  cxt.strokeStyle = "#eee";
  cxt.lineWidth = 20;
  cxt.arc(centerX,centerY,50,-Math.PI/2, 3 * Math.PI/2,true);
  cxt.stroke();
}

5.定时器

循环绘制前景,使用setTimout()

function setTimer() {
  if(timer){
    clearTimeout(timer);
  }
  context.clearRect(0, 0, canvas.width, canvas.height); //清除前景
  var speed = Math.floor(Date.now() / 1000 % 30); //取当前时间,每30s一圈
  drawCircle(speed);  //绘制前景
  var timer = setTimeout(function(){
    setTimer();
  },1000);
}

codepen完整版
可以打开你的google身份验证器和codepen地址看看,时间是不是同步的呢,哈哈。也可以缩短定时器的时间间隔,让它转得更像动画。

如果有错误,请指出。