复习Javascript到Canvas的知识点,看到一个使用Canvas绘制的静态时钟例子,便想将其变成动态显示系统时间的时钟动画。另外再配上数字显示的时钟,一个小的时钟模块的诞生了!目前的界面还比较粗糙,只有简单的界面和动画效果。

演示观看地址:http://htmlpreview.github.io/?https://github.com/omocc/Demo/blob/master/%E6%97%B6%E9%92%9Fdemo/clock.html

  这个时钟包括两个部分,动画圆盘时钟和数字时钟。首先是使用超时调用setTimeout()方法做一个循环动画的效果以显示时间。先看数字时钟的代码,比较简单,圆盘时钟的做法也是模仿数字时钟做的。

var ntimeoutId = setTimeout(ntimeOut,0);
function ntimeOut() {
clearTimeout(ntimeoutId);
var now = new Date();
var hours = now.getHours().toString(),
minutes = now.getMinutes().toString(),
seconds = now.getSeconds().toString();
var time = hours+" : "+minutes+" : "+seconds;
var timediv = document.getElementById("time");
timediv.innerHTML = time;
ntimeoutId = setTimeout(ntimeOut, 1000);
}

  1、首先是设定一个超时调用以首次调用方法来显示系统当前时间,时间之所以设置为0,是为了没有延迟地显示时间。

  2、每次循环之前清除前一次的超时调用(为什么要这样做,我也还不清楚???可能是为了内存性能相关,注释了以后程序也能正常执行。)

  3、取得当前系统时间,并按照一定的字符串格式保存。

  4、为了动态显示在页面中,在Html页面中定义了一个空的div元素,以存放该时间字符串。使用DOM操作将其添加到div元素中即可动态显示。

  5、通过不停循环超时调用,就可以动态显示数字时钟了, 同过开发者工具也可以看到div元素里的动态变化。

  接下来就是制作圆盘时钟动画,圆盘和数值的刻画都比较简单,只要使用context.arc()方法和context.fillText()方法即可。下面是其源代码:

     context.beginPath();
context.restore();
context.translate(0,0);
context.clearRect(0,0,300,300); //绘制时钟内外边框
context.arc(150,150,149,0,2 * Math.PI,false);
context.moveTo(295,150);
context.arc(150,150,145,0,2 * Math.PI,false); context.font = "bold 18px Arial";
context.textAlign = "center"; //绘制时钟表盘数值
context.fillText("12",150,25);
context.fillText("3",285,150);
context.fillText("6",150,290);
context.fillText("9",15,150);
context.fillText("1",215,45);
context.fillText("2",265,95);
context.fillText("4",265,225);
context.fillText("7",95,275);
context.fillText("5",215,275);
context.fillText("8",35,225);
context.fillText("10",35,95);
context.fillText("11",75,45); context.stroke();
context.closePath();

  接下来就是指针的绘制了,指针的绘制中参考高程中的做法,使用变换操作context.translate()方法改变原点,再绘制路径成为指针会方便很多。另一个绘制指针的难点是弧度的计算,当然这就是数学问题了。下面先看源代码:

     //绘制指针
context.save();
context.translate(150,150); //时针
context.moveTo(0,0);
hour(hours); function hour(thour) {
context.save();
var newhour = 0;
if(thour>12) {
newhour = thour-12;
} else {
newhour = thour;
}
context.rotate((2*Math.PI/12)*newhour);
context.lineTo(0,-80);
context.restore();
} //分针
context.moveTo(0,0);
minute(minutes); function minute(tminute) {
context.save();
context.rotate((2*Math.PI/12)*tminute/5);
context.lineTo(0,-110);
context.restore();
} //秒针
context.moveTo(0,0);
second(seconds); function second(tsecond) {
context.save();
context.fillStyle = "#fff";
context.rotate((2*Math.PI/12)*tsecond/5);
context.lineTo(0,-120);
context.restore();
} context.stroke();

  在绘制指针中,每种指针都使用了函数来改变每次指针绘制的弧度来实现指针转动的动画效果。对于时针,则将二十四小时制转化为十二小时制,每次转动30°即可。分针和秒针则是转为0到11进行转动,简单的数学问题,相信大家都是比我厉害的,当时我还纠结了一阵子。在每个函数中都有使用context.save()方法和context.restore()方法,是为了保存和复原初始化时的路径,不然指针都要跑偏啦。

  所有工作基本准备就绪了,接下来只要将钟盘和指针都放在超时调用中即可,但仍然有些问题需要注意的,比如说钟盘和指针的原点设置不同,要注意使用保存和复原来还原初始化时候的路径,不然钟盘和指针都要跑偏了。另外要注意的是,使用Canvas制作动画,每次的动画循环都是要清空画布重新绘制,不然指针一直转转转,转成一朵花的样子。

  完整的圆盘时钟代码如下:

//显示指针时间
var drawing = document.getElementById("drawing");
if(drawing.getContext) {
var context = drawing.getContext("2d"); var rtimeoutId = setTimeout(roudClock,0);
function roudClock() {
clearTimeout(rtimeoutId); context.beginPath();
context.restore();
context.translate(0,0);
context.clearRect(0,0,300,300); //绘制时钟内外边框
context.arc(150,150,149,0,2 * Math.PI,false);
context.moveTo(295,150);
context.arc(150,150,145,0,2 * Math.PI,false); context.font = "bold 18px Arial";
context.textAlign = "center"; //绘制时钟表盘数值
context.fillText("12",150,25);
context.fillText("3",285,150);
context.fillText("6",150,290);
context.fillText("9",15,150);
context.fillText("1",215,45);
context.fillText("2",265,95);
context.fillText("4",265,225);
context.fillText("7",95,275);
context.fillText("5",215,275);
context.fillText("8",35,225);
context.fillText("10",35,95);
context.fillText("11",75,45); context.stroke();
context.closePath(); var now = new Date();
var hours = now.getHours(),
minutes = now.getMinutes(),
seconds = now.getSeconds(); //绘制指针
context.save();
context.translate(150,150); //时针
context.moveTo(0,0);
hour(hours); function hour(thour) {
context.save();
var newhour = 0;
if(thour>12) {
newhour = thour-12;
} else {
newhour = thour;
}
context.rotate((2*Math.PI/12)*newhour);
context.lineTo(0,-80);
context.restore();
} //分针
   context.moveTo(0,0);
minute(minutes); function minute(tminute) {
context.save();
context.rotate((2*Math.PI/12)*tminute/5);
context.lineTo(0,-110);
context.restore();
} //秒针
context.moveTo(0,0);
second(seconds); function second(tsecond) {
context.save();
context.fillStyle = "#fff";
context.rotate((2*Math.PI/12)*tsecond/5);
context.lineTo(0,-120);
context.restore();
} context.stroke();
context.restore();
context.translate(0,0);
context.save();
rtimeoutId = setTimeout(roudClock,1000);
}
}

  最后总结我在这次Demo的练习中遇到的几点问题:

  1、画布重绘问题

  在指针动画循环的时候,前一个路径都没有方法清除,造成每一次循环都留下印记。尝试了小范围地使用clearRect()方法,结果发现只能在范围内清除了表盘和数字的内容,指针依然会留下痕迹。后来通过搜索,得到的答案是使用Canvas制作动画一定是要进行重绘的,在新绘制内容前要清空画布内容,每一次的动画变化都要清空一次。重绘的方法可以参考一下链接,我使用的是clearRect()方法清空整个画布。

参考方法链接:http://blog.csdn.net/u010484625/article/details/46046217

  2、save()方法和restore()方法的使用

  因为我的钟盘和指针的原点设定不同,所以在进行重绘后,钟盘的原点会改变为指针的原点,因此要利用save()方法和restore()方法改变。除了这个地方也有其他一些地方需要用到,适合操作以后改变了设定,但后续操作需要用原设定的情况。注意的是这两个方法只会保存和恢复设定,而不是内容。

  3、translate()方法的使用

  translate()方法是属于变换操作中的,可改变画布的原点,默认画布的原点在画布的左上角。使用这个方法可以更轻易地绘制指针的路径,当然还有一些其他需要用的地方,我还没有接触到。

  4、setTimeout()方法的使用

  使用超时调用是比间歇调用更好的方法,使用超时调用可以模拟间歇调用。通过在超时调用传入的函数中再添加超时调用就可以很好地模仿循环。还可以在函数中根据一些条件限定循环的次数和时间。

  5、对应当前时间,弧度的使用方法

  这就是数学问题,我在这个问题纠结了好一会儿,没有拐过弯来,明白其中的原理就不是技术上的难题了。

  6、对于时间重复取得和重复使用方法的问题

  对于代码中还存在有重复代码的情况,我还没有想到更好的方法减少冗余。例如在获取时间上,在两个超时调用中均有重复定义,但若是把他们放在全局中,则没有了动画效果,只是显示加载完成后的那个静态时间。另外的是指针的函数设定中有重复的部分,是否可以合为一个函数方法再进行调用呢。

  欢迎大家提出想法,对于不足的地方提出建议,一起来交流。

使用Canvas制作时钟动画的更多相关文章

  1. 用Canvas制作loading动画

    上一篇讲到用SVG制作loading动画,其中提到了线性渐变在扇形区域中的问题,并且用SVG SIML语法制作的loading动画并不是所有浏览器都兼容,所以现在用Canvas重新实现了一遍. 这里与 ...

  2. canvas制作简单动画

    在画布元素<canvas>中,除了绘制图形.图像.文字外,还可以制作一些简单的动画,制作过程十分简单,主要分为两步操作: 1.自定义一个函数,用于图形的移动或其他动作. 2.使用setIn ...

  3. 利用HTML5的canvas制作万花筒动画特效

    <!DOCTYPE HTML> <html> <head> <style> #canvas{ background-color:#cccccc; } & ...

  4. 15个超强悍的CSS3圆盘时钟动画赏析

    在网页上,特别是个人博客中经常会用到时钟插件,一款个性化的时钟插件不仅可以让页面显得美观,而且可以让访客看到当前的日期和时间.今天我们给大家收集了15个超强悍的圆盘时钟动画,很多都是基于CSS3,也有 ...

  5. Canvas制作的下雨动画

    简介 在codepen上看到一个Canvas做的下雨效果动画,感觉蛮有意思的.就研究了下,这里来分享下,实现技巧.效果可以见下面的链接. 霓虹雨: http://codepen.io/natewile ...

  6. 14款超时尚的HTML5时钟动画

    时钟动画在网页应用中也非常广泛,在一些个人博客中,我们经常会看到一些相当个性化的HTML5时钟动画.今天我们向大家分享了14款形态各异的超时尚HTML5时钟动画,其中有圆盘时钟.3D时钟.个性化时钟等 ...

  7. 14款形态各异的超时尚HTML5时钟动画

    14款超时尚的HTML5时钟动画(附源码)   时钟动画在网页应用中也非常广泛,在一些个人博客中,我们经常会看到一些相当个性化的HTML5时钟动画.今天我们向大家分享了14款形态各异的超时尚HTML5 ...

  8. [JS,Canvas]日历时钟

    [JS,Canvas]日历时钟 Html: <!doctype html> <html> <head> <meta charset="UTF-8&q ...

  9. 酷!使用 jQuery & Canvas 制作相机快门效果

    在今天的教程中,我们将使用 HTML5 的 Canvas 元素来创建一个简单的摄影作品集,它显示了一组精选照片与相机快门的效果.此功能会以一个简单的 jQuery 插件形式使用,你可以很容易地整合到任 ...

随机推荐

  1. 五,ESP8266 TCP服务器多连接

    一些时间去准备朋友的元器件了... 接着写,,争取今天写完所有的文章,,因为答应了朋友下周5之前要做好朋友的东西 对于TCP大家在玩AT指令的时候有没有发现客户端最多连接5个,,,再连接就不行了?? ...

  2. webpack配置这一篇就够

    最近看了一篇好文,根据这个文章重新梳理了一遍webpack打包过程,以前的一些问题也都清楚了,在这里分享一下,同时自己也做了一些小的调整 原文链接:http://www.jianshu.com/p/4 ...

  3. 201521123084 《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  4. 集美大学网络1413第八次作业(团队四)-- 第一次项目冲刺(Alpha版本)成绩

    首先非常抱歉,刚休完假,凌晨才回来,导致这么晚发布成绩,以后旅行可以考虑带点轻便点的笔记本~ O(∩_∩)O 第一次项目冲刺结束了,可以看出来,有的团队做的很棒,也有的团队组合不是很理想,导致进度一直 ...

  5. 结对作业(1)----基于GUI的四则运算

    小伙伴:201421123031 余洋 201421123044  潘志坚  题目要求: 我们在个人作业1中,用各种语言实现了一个命令行的四则运算小程序.进一步,本次要求把这个程序做成GUI(可以是W ...

  6. 个人作业3—个人总结(Alpha阶段)

    一.关于Alpha阶段的总结 1.我们团队的情况 关于我们拖拉机团队,大家在一起做项目的这几周算是比较团结.首先组长布置的任务,每个人都有认真去做,每次例会还会总结不足,提出改进,并且实施这些改进:其 ...

  7. 201521123106 《Java程序设计》第6周学习总结

    1. 本章学习总结 2. 书面作业 Q1. clone方法 1.1 Object对象中的clone方法是被protected修饰,在自定义的类中覆盖clone方法时需要注意什么? 答:在同一个包里或者 ...

  8. 201521123033《Java程序设计》第1周学习总结

    1. 本周学习总结 (1)了解了JVM,JRE,JDK (2)配置java环境变量 (3)编译一些简单的java代码 2. 书面作业 为什么java程序可以跨平台运行?执行java程序的步骤是什么?( ...

  9. java第十四次作业

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  10. 201521123087《Java程序设计》第14周学习总结

    1. 本周学习总结 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名)在自己建立的数据库上执行常见SQL语句(截图)-参考 ...