js Canvas实现圆形时钟教程


Posted in Javascript onSeptember 19, 2016

阅读本文需要一点关于canvas基本用法的基础,本文实例为大家分享了HTML5 Canvas实现圆形时钟简易教程

第一步:新建一个最简单的html文件,并且在<body>标签中定义元素canvas。

canvas.html

<html>
 <head>
 <title>Canvas clock tutorial</title>
 </head>
 <body>
 <canvas id="clock" width="400" height="400"></canvas>
 </body>
</html>

 在这一步完成后,用浏览器打开canvas.html,你会发现什么都看不到,这是因为我们没有在canvas上绘制任何东西,同时也没有为其定义边界。

在canvas .html中为<canvas>添加css样式属性:

<html>
 <head>
 <title>Canvas clock tutorial</title>
 <style type="text/css">
  canvas { border: 1px solid black; }
 </style>
 </head>
 <body>
 <canvas id="clock" width="400" height="400"></canvas>
 </body>
</html>

这样,我们就能看到<canvas>的轮廓。

当没有设置宽度和高度的时候,canvas会初始化宽度为300像素和高度为150像素。该元素可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲。

注意: 如果你绘制出来的图像是扭曲的, 尝试在<canvas>的属性中明确规定宽和高,而不是使用CSS。 

第二步:新建实现绘制圆形时钟逻辑的draw.js文件,进行初始化工作。

毫无疑问,要实现时钟,就需要获取系统时间。 

在js语法中,可以利用Date()来实时获取时间。
 var currentTime = new Date();

随后,要掌握的是canvas绘制圆形的函数:
 arc(x, y, radius, startAngle, endAngle, anticlockwise)该方法表示画一个以(x,y)为圆心的、以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认顺时针(true))来生成。
 其中stratAngle和endAngle的单位并不是我们所熟悉的角度单位,而是弧度单位。一个完整的圆跨弧度2π。 

在canvas的坐标系中,是以x轴正方向所在的方向为0弧度。时钟指针按顺时针方向转,以2π为一个周期,因此如下图所示,时钟指针,是从(-1/2)*π位置开始走的。 

js Canvas实现圆形时钟教程

当前时间的弧度计算方式如下:

//将一个时钟周期12等分,对12求余是因为Date().getHours将返回24小时制的小时。
hour = (currentTime.getHours() % 12 ) * (2 * Math.PI /12); 
//MINUTE 一圈60等分
minute = (currentTIme.getMinutes) * (2* Math.PI / 60); 
//SECOND 一圈60等分
second = (currentTime.getSeconds) * (2 * Math.PI / 60);

由于在canvas中时钟圆从(-1/2)*π开始走,因此我们还需要给它们加上(-1/2)*π的起始偏移量。

初步得到draw.js:

function draw() {
 //canvas绘画的前提工作
 var canvas = document.getElementById('clock');
 var currentTime = new Date();
 var hour = (currentTime.getHours()%12) * Math.PI/6;
 var minute = currentTime.getMinutes() * Math.PI/30;
 var second = currentTime.getSeconds() * Math.PI/30;
 hour = hour - Math.PI * (1/2);
 minute = minute - Math.PI * (1/2);
 second = second - Math.PI * (1/2);
 if (canvas.getContext){
 var ctx = canvas.getContext('2d');
 ctx.beginPath();
 ctx.arc(200,200,50,Math.PI*(-1/2),hour,false);
 ctx.moveTo(200,100);
 ctx.arc(200,200,100,Math.PI*(-1/2),minute,false);
 ctx.moveTo(200,50);
 ctx.arc(200,200,150,Math.PI*(-1/2),second,false);
 ctx.stroke();
 }
}

同时在canvas.html中 加入draw.js的引用。 

<html>
 <head>
 <title>Canvas clock tutorial</title>
 <style type="text/css">
  canvas { border: 1px solid black; }
 </style>
 <script src="draw.js" type="text/javascript"></script>
 </head>
 <body onload="draw();">
 <canvas id="clock" width="400" height="400"></canvas>
 </body>
</html>

在完成了第二步之后,我们可以看到一个当前时间的圆形时钟轮廓。那么接下来,就是让它动起来! 

第三步:使用requestAnimationFrame()方法让时钟动起来。

requestAnimationFrame()的执行频率是1秒60帧,用户可以在requestAnimationFrame定义事件,使其在每一帧中重复、迭代完成相应的事件。

在我们这个案例中,每一帧里面requestAnimationFrame要做的事情很简单,为当前时间的三个参数(时针、分针、秒针)添加增量,然后重新绘制时钟。

根据一秒60帧的频率,那么second在1帧里面的增量是:2*π / 60 / 60 = π / 1800;

minute在一帧里面的增量是second增量的60分之一;hour在一帧里面的增量是minute的12分之1。

另外:当hour、minute、second任一一个变量到达3/2*π后,意味着完成了一个周期,就要重新初始化为(-1/2)*π,否则会覆盖绘制成一个圆。

由此得到:requestAnimationFrame()函数中,hour,minute,second的更新过程如下: 

var s = Math.PI / 1800;
  var m = s / 60;
  var h = m / 12;
  second = second + s;
  minute = minute + m;
  hour = hour + h;
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  if(minute >= Math.PI * (3/2)){
  minute = Math.PI * (-1/2);
  }
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }</span>

 更新draw.js的完整代码如下:

function draw() {
 var canvas = document.getElementById('clock');
 var currentTime = new Date();
 var hour = (currentTime.getHours()%12) * Math.PI/6;
 var minute = currentTime.getMinutes() * Math.PI/30;
 var second = currentTime.getSeconds() * Math.PI/30;
 hour = hour - Math.PI * (1/2);
 minute = minute - Math.PI * (1/2);
 second = second - Math.PI * (1/2);
 if (canvas.getContext){
 var ctx = canvas.getContext('2d');
 var s = Math.PI / 1800;
 var m = s / 60;
 var h = m / 12;
 var rotate = requestAnimationFrame(step);
 function step(){
  second = second + s;
  minute = minute + m;
  hour = hour + h;
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  if(minute >= Math.PI * (3/2)){
  minute = Math.PI * (-1/2);
  }
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  ctx.clearRect(0, 0, 400 , 400);
  ctx.beginPath();
  ctx.arc(200,200,50,Math.PI*(-1/2),hour,false);
  ctx.moveTo(200,100);
  ctx.arc(200,200,100,Math.PI*(-1/2),minute,false);
  ctx.moveTo(200,50);
  ctx.arc(200,200,150,Math.PI*(-1/2),second,false);
  ctx.stroke();
  requestAnimationFrame(step);
 }
 }
}

到这步为止,我们已经得到了一个会动的圆形时钟,接下来,我们为其添加上指针。 

第四步*:添加时针、分针、秒针。 

JS为我们提供了Math.cos() 、Math.sin() 计算指针到达的位置,它们所接收参数的单位也都是弧度。

function draw() {
 var canvas = document.getElementById('clock');
 var currentTime = new Date();
 var hour = (currentTime.getHours()%12) * Math.PI/6;
 var minute = currentTime.getMinutes() * Math.PI/30;
 var second = currentTime.getSeconds() * Math.PI/30;
 hour = hour - Math.PI * (1/2);
 minute = minute - Math.PI * (1/2);
 second = second - Math.PI * (1/2);
 if (canvas.getContext){
 var ctx = canvas.getContext('2d');
 var s = Math.PI / 1800;
 var m = s / 60;
 var h = m / 12;
 var rotate = requestAnimationFrame(step);
 function step(){
  second = second + s;
  minute = minute + m;
  hour = hour + h;
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  if(minute >= Math.PI * (3/2)){
  minute = Math.PI * (-1/2);
  }
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  //秒针的终点
  xs = 150 * Math.cos(second) + 200;
  ys = 150 * Math.sin(second) + 200;
  //分针的终点
  xm = 100 * Math.cos(minute) + 200;
  ym = 100 * Math.sin(minute) + 200;
  //时针的终点
  xh = 50 * Math.cos(hour) + 200;
  yh = 50 * Math.sin(hour) + 200;

  ctx.clearRect(0, 0, 400 , 400);
  ctx.beginPath();
  //绘制指针
  ctx.moveTo(200,200);
  ctx.lineTo(xs,ys);
  ctx.moveTo(200,200);
  ctx.lineTo(xm,ym);
  ctx.moveTo(200,200);
  ctx.lineTo(xh,yh);
  //绘制圆形轮廓
  ctx.moveTo(200,150);
  ctx.arc(200,200,50,Math.PI*(-1/2),hour,false);
  ctx.moveTo(200,100);
  ctx.arc(200,200,100,Math.PI*(-1/2),minute,false);
  ctx.moveTo(200,50);
  ctx.arc(200,200,150,Math.PI*(-1/2),second,false);
  ctx.stroke();
  requestAnimationFrame(step);
 }
 }
}

嗯嗯,虽然指针是画出来了,都是我略感后悔,因为感觉太丑了。从审美学角度而言,带指针时钟就应该是个全圆轮廓的时钟。不知道读者有没有同感。我决定在第五步中把第四步回退了。 

第五步:个性化、美化、自定义你的时钟。

html5的canvas画布,提供了多种样式属性,如线条颜色、线条粗细等等。

为了提高代码的可重用性,我们将画圆的代码抽象成一个函数。

function draw() {
 var canvas = document.getElementById('clock');
 var currentTime = new Date();
 var hour = (currentTime.getHours()%12) * Math.PI/6;
 var minute = currentTime.getMinutes() * Math.PI/30;
 var second = currentTime.getSeconds() * Math.PI/30;
 hour = hour - Math.PI * (1/2);
 minute = minute - Math.PI * (1/2);
 second = second - Math.PI * (1/2);
 if (canvas.getContext){
 var ctx = canvas.getContext('2d');
 var s = Math.PI / 1800;
 var m = s / 60;
 var h = m / 12;
 var rotate = requestAnimationFrame(step);
 function step(){
  second = second + s;
  minute = minute + m;
  hour = hour + h;
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  if(minute >= Math.PI * (3/2)){
  minute = Math.PI * (-1/2);
  }
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }

  ctx.clearRect(0, 0, 400 , 400);
  ctx.beginPath();
  //绘制圆形轮廓
  drawCircle(ctx, 100, hour, '#99ff00');
  drawCircle(ctx, 120, minute, '#99ff66');
  drawCircle(ctx, 140, second, '#66cc66');
  requestAnimationFrame(step);
 }
 }
}

function drawCircle(ctx, radius ,endAngle, color){
 ctx.beginPath();
 ctx.moveTo(200,200-radius);
 ctx.strokeStyle = color;
 ctx.lineWidth = 20;
 ctx.arc(200,200,radius,Math.PI*(-1/2),endAngle,false);
 ctx.stroke();
}

第六步(后续添加):为时钟添加数字指数。

具体做法为多增加一个画布canvas元素。既然我们已经能从Date()中获取时间,那么显示数值的来源不成问题。读者唯一需要知道的就是利用setInterval(thingstodo(),interval)方法来实现每秒更新一次指数。 

修改后的canvas.html

<html>
 <head>
 <title>Canvas clock tutorial</title>
 <style type="text/css">
  canvas { border: 1px solid black; }
  #display {position: absolute; top:8; left:8;}
 </style>
 <script src="draw.js" type="text/javascript"></script>
 </head>
 <body onload="draw();">
 <canvas id="clock" width="400" height="400"></canvas>
 <canvas id="display" width="400" height="400"></canvas>
 </body>
</html>

修改后的draw.js

function draw() {
 var canvas = document.getElementById('clock');
 var displayCanvas = document.getElementById('display');
 var currentTime = new Date();
 var hour = (currentTime.getHours()%12) * Math.PI/6;
 var minute = currentTime.getMinutes() * Math.PI/30;
 var second = currentTime.getSeconds() * Math.PI/30;
 hour = hour - Math.PI * (1/2);
 minute = minute - Math.PI * (1/2);
 second = second - Math.PI * (1/2);
 if (canvas.getContext){
 var ctx = canvas.getContext('2d');
 var ctxD = displayCanvas.getContext('2d');
 showDisplay(ctxD, currentTime);
 var s = Math.PI / 1800;
 var m = s / 60;
 var h = m / 12;
 var rotate = requestAnimationFrame(step);
 function step(){
  second = second + s;
  minute = minute + m;
  hour = hour + h;
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }
  if(minute >= Math.PI * (3/2)){
  minute = Math.PI * (-1/2);
  }
  if(second >= Math.PI * (3/2)){
  second = Math.PI * (-1/2);
  }

  ctx.clearRect(0, 0, 400 , 400);
  ctx.beginPath();
  //绘制圆形轮廓
  drawCircle(ctx, 100, hour, '#99ff00');
  drawCircle(ctx, 120, minute, '#99ff66');
  drawCircle(ctx, 140, second, '#66cc66');
  requestAnimationFrame(step);
 }
 }
}

function drawCircle(ctx, radius ,endAngle, color){
 ctx.beginPath();
 ctx.moveTo(200,200-radius);
 ctx.strokeStyle = color;
 ctx.lineWidth = 20;
 ctx.arc(200,200,radius,Math.PI*(-1/2),endAngle,false);
 ctx.stroke();
}

function showDisplay(ctx, date){
 var h = date.getHours(),m = date.getMinutes(),s = date.getSeconds();
 //计时文字样式
 ctx.font = "13px Sans-Serif";
 ctx.textAlign = "center";
 ctx.strokeText(h+":"+m+":"+s,200,200);
 var timmer = setInterval(function(){
 s++;
 if(s>=60){
  m++;
  s=0;
 }
 if(m>=60){
  h++;
  m=0;
 }
 if(h>=24){
  h=0;
 }
 ctx.clearRect(0,0,400,400);
 ctx.strokeText(h+":"+m+":"+s,200,200);
 },1000);
}

最终成果图如下:

js Canvas实现圆形时钟教程

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery AnythingSlider滑动效果插件
Feb 07 Javascript
jquery checkbox,radio是否选中的判断代码
Mar 20 Javascript
浅谈Javascript鼠标和滚轮事件
Jun 27 Javascript
js中的屏蔽的使用示例
Jul 30 Javascript
jQuery遍历Form示例代码
Sep 03 Javascript
jQuery点击改变class并toggle及toggleClass()方法定义用法
Dec 11 Javascript
js如何判断输入字符串长度
Dec 16 Javascript
原生javascript实现匀速运动动画效果
Feb 26 Javascript
详解微信小程序——自定义圆形进度条
Dec 29 Javascript
Angular 组件之间的交互的示例代码
Mar 24 Javascript
node.js使用zlib模块进行数据压缩和解压操作示例
Feb 12 Javascript
vue中 this.$set的使用详解
Nov 17 Vue.js
Bootstrap模态框调用功能实现方法
Sep 19 #Javascript
javascript实现的上下无缝滚动效果
Sep 19 #Javascript
Angular ng-class详解及实例代码
Sep 19 #Javascript
javascript实现的左右无缝滚动效果
Sep 19 #Javascript
javascript实现图片左右滚动效果【可自动滚动,有左右按钮】
Sep 19 #Javascript
BootStrap入门教程(三)之响应式原理
Sep 19 #Javascript
HTML5 实现的一个俄罗斯方块实例代码
Sep 19 #Javascript
You might like
Windows下PHP的任意文件执行漏洞
2006/10/09 PHP
PHP与SQL注入攻击[一]
2007/04/17 PHP
PHPMYADMIN 简明安装教程 推荐
2010/03/07 PHP
JavaScript 封装Ajax传递的数据代码
2009/06/05 Javascript
FileUpload 控件 禁止手动输入或粘贴的实现代码
2010/04/07 Javascript
JavaScript自定义DateDiff函数(兼容所有浏览器)
2012/03/01 Javascript
js中生成map对象的方法
2014/01/09 Javascript
js制作网站首页图片轮播特效代码
2016/08/30 Javascript
JS实现的Unicode编码转换操作示例
2017/04/28 Javascript
vue实现登录拦截
2020/06/29 Javascript
Js图片点击切换轮播实现代码
2020/07/27 Javascript
python基础教程之字典操作详解
2014/03/25 Python
Python的组合模式与责任链模式编程示例
2016/02/02 Python
Python的string模块中的Template类字符串模板用法
2016/06/27 Python
Bottle框架中的装饰器类和描述符应用详解
2017/10/28 Python
python实现简单登陆流程的方法
2018/04/22 Python
python自定义函数实现最大值的输出方法
2019/07/09 Python
Python抓包程序mitmproxy安装和使用过程图解
2020/03/02 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
一款利用纯css3实现的360度翻转按钮的实例教程
2014/11/05 HTML / CSS
BCBG官网:BCBGMAXAZRIA
2017/12/29 全球购物
中学教师实习自我鉴定
2013/09/28 职场文书
内容编辑个人求职信
2013/12/10 职场文书
留学推荐信中文范文三篇
2014/01/25 职场文书
英语三分钟演讲稿
2014/08/19 职场文书
党的群众路线领导班子整改方案
2014/09/27 职场文书
办理护照工作证明
2014/10/10 职场文书
转让协议书
2015/01/27 职场文书
会议主持词开场白
2015/05/28 职场文书
军训阅兵新闻稿
2015/07/17 职场文书
离婚起诉书范文2016
2015/11/26 职场文书
《学会看病》教学反思
2016/02/17 职场文书
Python中os模块的简单使用及重命名操作
2021/04/17 Python
golang协程池模拟实现群发邮件功能
2021/05/02 Golang
python实现的人脸识别打卡系统
2021/05/08 Python
mysql分组后合并显示一个字段的多条数据方式
2022/01/22 MySQL