准备工作

在HTML中指定一个区域放置时钟:

<div id="clock" style="position: relative;"></div>

时钟的一些外观设定:

var width = 260; // 桌布宽度
var height= 260; // 桌布高度
var dot = {
x : width / 2,
y : height / 2,
radius : 6
}; // 圆点位置、半径
var radius = 120; // 圆半径
var borderWidth = 6; // 圆边框宽度

创建<canvas>元素:

var clock = document.getElementById('clock');
var clockBg = document.createElement('canvas');
var clockPointers = document.createElement('canvas');

clockPointers.width = clockBg.width = width;
clockPointers.height = clockBg.height = height;
clockPointers.style.position = 'absolute';
clockPointers.style.left = 0;
clockPointers.style.right = 0;

clock.appendChild(clockBg);
clock.appendChild(clockPointers);

这里要创建两个<canvas>元素,目的在于把时钟的圆盘跟指针分离开。这是因为指针要根据当前时间擦除重绘,如果放置在一个<canvas>中,擦除的时候就会把圆盘也给擦掉了。

绘制圆盘

但凡要在<canvas>中绘图,都要先获得其上下文,对应的接口是 canvas.getContext

var bgCtx = clockBg.getContext('2d');

目前canvas.getContext接口的唯一一个合法参数是'2d',将来应该会支持3D绘图。

先来绘制最外面的圆框:

bgCtx.beginPath();
bgCtx.lineWidth = borderWidth;
bgCtx.strokeStyle = '#000';
bgCtx.arc(dot.x, dot.y, radius, 0, 2 * Math.PI, true);
bgCtx.stroke();
bgCtx.closePath();

绘图的流程其实都是类似的:

  1. 调用 context.beginPath() 新建路径;
  2. 设置颜色等样式;
  3. 调用路径函数生成路径;
  4. 画线(stroke)或者填充(fill);
  5. 调用 context.closePath() 关闭路径;

上面用到的 context.arc 接口可以生成圆弧路径,其详细说明参见此处

用类似的方法,画出圆点:

bgCtx.beginPath();
bgCtx.fillStyle = '#000';
bgCtx.arc(dot.x, dot.y, dot.radius, 0, 2 * Math.PI, true);
bgCtx.fill();
bgCtx.closePath();

此时,结果如下图所示:

绘制刻度

最复杂的地方就是画刻度了,这里要先复习一下数学中的三角函数

刻度的起始位置就是圆框上的一个点,第一步就是要知道这个点的坐标。上图中:

sinθ = AC / AO
cosθ = OC / AO

其中AO即为圆半径,而θ的值则根据刻度而定。0是π/2,3是0,6是3π/2,9是π:

由此可得到刻度起始点的位置为:

x = 圆点横坐标 + AO * cosθ
y = 圆点纵坐标 + AO * sinθ

同理可算出刻度结束点的位置为(结束点相当于在一个半径为圆框半径-刻度长度的圆上):

x = 圆点横坐标 + (AO - 刻度长度) * cosθ
y = 圆点纵坐标 + (AO - 刻度长度) * sinθ

于是,这程序可以写了:

for (var i = 0, angle = 0, tmp, len; i < 60; i++) {
bgCtx.beginPath();

// 突出显示能被5除尽的刻度
if (0 === i % 5) {
bgCtx.lineWidth = 5;
len = 12;
bgCtx.strokeStyle = '#000';
} else {
bgCtx.lineWidth = 2;
len = 6;
bgCtx.strokeStyle = '#999';
}

tmp = radius - borderWidth / 2; // 因为圆有边框,所以要减去边框宽度
bgCtx.moveTo(
dot.x + tmp * Math.cos(angle),
dot.y + tmp * Math.sin(angle)
);
tmp -= len;
bgCtx.lineTo(dot.x + tmp * Math.cos(angle), dot.y + tmp * Math.sin(angle));
bgCtx.stroke();
bgCtx.closePath();

angle += Math.PI / 30; // 每次递增1/30π
}

画好刻度后,结果应该是这样:

画指针

先得获取指针<canvas>的上下文:

var ptxContext = clockPointers.getContext('2d');

由于画指针的操作每隔一秒都要执行一次,所以这里就写成一个函数,方便传给setInterval调用:

function updatePointers() {
ptCtx.clearRect(0, 0, width, height);  // 清掉原来的指针

// 获取当前时间
var now = new Date();
var h = now.getHours();
var m = now.getMinutes();
var s = now.getSeconds();

// 算出时分秒指针现在应指向圆的几分之几处
h = h > 12 ? h - 12 : h;
h = h + m / 60;
h = h / 12;
m = m / 60;
s = s / 60;

drawPointers(s, 2, 92); // 画秒针
drawPointers(m, 4, 82); // 画分针
drawPointers(h, 6, 65); // 画时针
}

drawPointers函数的实现是:

// angle是角度,lineWidth是指针宽度,length是指针长度
function drawPointers(angle, lineWidth, length) {
angle = angle * Math.PI * 2 - Math.PI / 2;

ptCtx.beginPath();
ptCtx.lineWidth = lineWidth;
ptCtx.strokeStyle = "#000";
ptCtx.moveTo(dot.x, dot.y);
ptCtx.lineTo(dot.x + length * Math.cos(angle), dot.y + length * Math.sin(angle));
ptCtx.stroke();
ptCtx.closePath();
}

这里主要也是用到三角函数,就不啰嗦了,但是要注意angel的计算。由于传入的angel是一个百分数,所以要乘以一个圆周,也就是2π,才知道对应的弧度,算出来以后还要减去π/2,因为从上面的坐标图就可以看到,0是位于x轴而不是y轴除,刚好比正常的时钟多了π/2。

最后别忘了调用updatePointers实时更新指针:

setInterval(updatePointers, 1000);
updatePointers();

这下时钟完全出来了,除了初步熟悉<canvas>绘图API外,还顺便复习了一次三角函数。

(完整代码)http://sandbox.runjs.cn/show/3afkqodu

使用canvas绘制时钟 (http://heeroluo.net/Article/Detail/95)的更多相关文章

  1. 使用canvas绘制时钟

    使用canvas绘制时钟  什么使canvas呢?HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.<canvas> 标签只是图 ...

  2. Canvas绘制时钟

    ①首先在HTML的body标签中添加一个canvas标签,用于绘制时钟. <canvas id="myCanvas" width="600" height ...

  3. HTML5 之Canvas 绘制时钟 Demo

    <!DOCTYPE html> <html> <head> <title>Canvas 之 时钟 Demo</title> <!--简 ...

  4. html5 Canvas绘制时钟以及绘制运动的圆

    1.绘制时钟 <!-- js代码 --> <script type="text/javascript"> window.onload=function(){ ...

  5. 小任务之Canvas绘制时钟

    背景图的绘制(大圆.数字.小圆点) 掌握基础知识:圆的绘制(arc方法),关于圆的弧度的计算,数学中关于sin cos的用法 圆的弧度为2*Math.PI 12个数字分得弧度每个为2*Math.PI/ ...

  6. 用canvas绘制时钟

    用canvas做时钟其实很简单,下面是我做出的效果: 是不是还挺漂亮的? 下面上代码: html <div class="whole"> <canvas id=& ...

  7. HTML5 Canvas 绘制时钟

    网上会看到很多绘制的时钟,看代码也是云里雾里,自学了下Canvas,觉得不难,就自己做了一个. 先看一下截图: 比较简陋,但是该有的都有了,样式只加了个阴影. html代码就不贴了,就一个canvas ...

  8. canvas绘制时钟及注释及save和restore的用法

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. 用canvas绘制一个简易时钟

    在见识了html5中canvas的强大,笔者准备制作一个简易时钟. 下面就是成果啦,制作之前我们先分析一下,绘制一个时钟需要做哪些准备. 一 . 1.首先这个时钟分为表盘,指针(时针,分针,秒针)和数 ...

随机推荐

  1. [转载]AI教师正来势汹汹,教师饭碗堪优

    (原文标题:开门,机器人老师来了) 一. 开门,机器人老师到了 国庆几天,河南刚刚上演一幕新科技的大戏: 计算机和人展开了为期四天的人机大战.这一次,对垒的双方不再是李世乭和阿尔法狗,而是教师和人工智 ...

  2. python基于万象优图识别图片中的中文

    最近一直在研究光学字符识别,即OCR.最开始在谷爹那里了解到了开源的Tesseract,可以拿来识别简单的英文和数字.但是识别中文的准确率并不高. 然后从Tesseract到Tesseract.js, ...

  3. iOS 记录近期遇到的几个bug

    1. actionSheet与pickerView 不兼容 发生环境:ios 9以上,其他无测试. actionSheet与pickerView在一起使用时,当actionSheet弹出后,紧接着再弹 ...

  4. 细品 - 逻辑回归(LR)

    1. LR的直观表述 1.1 直观表述 今天我们来深入了解一个人见人爱,花见花开,工业界为之疯狂,学术界..额,好像学术界用的不多哎.不过没关系,就算学术界用的不多也遮不住它NB的光芒,它就是LR模型 ...

  5. 转:C++输入一行字符串的一点小结

    原文链接: http://www.wutianqi.com/?p=1181 大家在学习C++编程时,一般在输入方面都是使用的cin.而cin是使用空白(空格,制表符和换行符)来定字符串的界的.这就导致 ...

  6. Volley图片加载并加入缓存处理(转自http://blog.csdn.net/viewhandkownhealth/article/details/50957024)

    直接上代码  两种方式 ImageView 和NetworkImageView 如有问题或者好的建议.意见 欢迎大家加入技术群(群号: 387648673 ) 先自定义全局Application 获取 ...

  7. Windows中 MySQL5.7.17解压版安装步骤

    1.先去MySQL官网下载.当前最新版是5.7.19,可能安装方法不同了,本人测试没有安装成功,若有安装成功的朋友,希望分享一下安装步骤. 个人推荐下载MySQL5.7.17,官方下载网址:https ...

  8. Memcached查找命令

    Memcached各个查找命令的语法格式都类似,且有相同的参数和参数含义,先将可能出现的各个参数的意义说明如下 key:键值 key-value 结构中的 key,用于查找缓存值. noreply(可 ...

  9. Python对于CSV文件的读取与写入

    今天天气"刚刚好"(薛之谦么么哒),无聊的我翻到了一篇关于csv文件读取与写入的帖子,作为测试小白的我一直对python情有独钟,顿时心血来潮,决定小搞他一下,分享给那些需要的小白 ...

  10. Java基础笔记8

    Object类 Object类是所有类的父类. 如果某个类没有显示的继承某个父类,那么该类则继承Object. 类 Object 是类层次结构的根类.每个类都使用 Object 作为超类. 所有对象( ...