导语:距离上一次写canvas,已经过去两年半,如今业务需要,再次拾起,随手记录。

【思考】 时钟的绘制主要在于圆的绘制:1. 使用context.arc()方法直接绘制圆或圆弧; 2. 使用圆的方程(x = r * cosA + X, y = r * sinA + Y)进行描点绘制。指针运行速率较慢,故使用setInterval进行刷新重绘。
【优化】可以使用两个canvas,一个用来绘制表盘,另一个绘制指针,如此,只需刷新重绘指针canvas,表盘canvas保持不变。

<!DOCTYPE html>
<html>
<head>
<title>Canvas Clock</title>
</head>
<body>
<canvas id="clock">Your borswer does not support canvas element.</canvas>
<script type="text/javascript">
/**
* 圆的方程:x = r * cosA + X, y = r * sinA + Y
* 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
*/
(function() {
let clockCvs = document.getElementById('clock')
if (!clockCvs || !clockCvs.getContext) return
clockCvs.width = 310
clockCvs.height = 310
let clockCtx = clockCvs.getContext('2d')
// X坐标偏移
const X = 155
// Y坐标偏移
const Y = 155
// 钟的半径
const R = 150 start()
setInterval(start, 1000) function start () {
clockCtx.clearRect(0, 0, clockCvs.width, clockCvs.height)
renderClockPlate()
renderClockTime()
renderClockHand()
} // 渲染表盘
function renderClockPlate () {
drawCircle(X, Y, '#070702', R, 1)
drawCircle(X, Y, '#4f4f52', R - 3, 5)
drawCircle(X, Y, '#070702', R - 6, 3)
drawCircle(X, Y, '#dddddd', R - 8)
drawCircle(X, Y, '#121213', R - 10, 3)
drawCircle(X, Y, '#19191a', R - 12, 0, 'fill', true) drawCircle(X, Y, '#4e4738', 15, 0, 'fill')
drawCircle(X, Y, '#eac55a', 10, 0, 'fill')
drawCircle(X, Y, '#3e3e41', 8, 0, 'fill')
drawCircle(X, Y, '#000000', 3, 0, 'fill')
} // 渲染时间
function renderClockTime () {
for (let angle = -90; angle < 270; angle = angle + 6) {
let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
let r = angle % 90 === 0 ? 4 : 2
drawCircle(x, y, '#eac55a', r, 0, 'fill')
if (angle % 30 === 0) {
x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
clockCtx.font = angle % 90 === 0 ? 'bold 15px yahei' : '12px yahei'
clockCtx.fillText((angle + 90) / 30 || 12, x , y)
}
}
} // 渲染表针
function renderClockHand () {
let date = new Date()
let hour = date.getHours()
let minute = date.getMinutes()
let second = date.getSeconds()
// 秒针
let angle1 = (second * 6 - 90)
let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
drawLine([[X, Y], [x, y]], 1)
// 分针
let angle2 = (minute * 6 - 90)
x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
drawLine([[X, Y], [x, y]], 2)
// 时针, 时针角度 = 小时角度 + 分钟角度
let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
drawLine([[X, Y], [x, y]], 4) } /**
* @param {String} color 颜色
* @param {Number} r 圆半径
* @param {Number} lineWidth 线条粗细
* @param {String} type 类型,stroke/fill
* @param {Boolean} isLinear 是否渐变
*/
function drawCircle (x, y,color = '#000000', r = 10, lineWidth = 2, type = 'stroke', isLinear = false) {
let grd = clockCtx.createLinearGradient(0, 0, clockCvs.width, clockCvs.height)
grd.addColorStop(0, color)
grd.addColorStop(0.5, '#555555')
grd.addColorStop(1, color)
clockCtx[type + 'Style'] = isLinear ? grd : color
clockCtx.lineWidth = lineWidth
clockCtx.beginPath()
clockCtx.arc(x, y, r, 0, Math.PI * 2, true)
clockCtx.closePath()
clockCtx[type]()
} /**
* @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
* @param {String} color 颜色
* @param {Number} lineWidth 线条粗细
*/
function drawLine (pos, lineWidth = 2, color = '#eac55a') {
clockCtx.strokeStyle = color
clockCtx.lineWidth = lineWidth
clockCtx.beginPath()
clockCtx.moveTo(pos[0][0], pos[0][1])
for (let i = 0, len = pos.length; i < len; i++) {
clockCtx.lineTo(pos[i][0], pos[i][1])
}
clockCtx.stroke()
clockCtx.closePath()
}
})()
</script>
</body>
</html>

优化前

<!DOCTYPE html>
<html>
<head>
<title>Canvas Clock</title>
</head>
<body>
<canvas id="clock" style="position: absolute;">Your borswer does not support canvas element.</canvas>
<canvas id="clockHand" style="position: absolute;">Your borswer does not support canvas element.</canvas>
<script type="text/javascript">
/**
* 圆的方程:x = r * cosA + X, y = r * sinA + Y
* 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
*/
(function() {
let clockCvs = document.getElementById('clock')
let clockHandCvs = document.getElementById('clockHand')
if (!clockCvs || !clockCvs.getContext) return
clockCvs.width = clockHandCvs.width = 310
clockCvs.height = clockHandCvs.height = 310
let clockCtx = clockCvs.getContext('2d')
let clockHandCtx = clockHandCvs.getContext('2d')
// X坐标偏移
const X = 155
// Y坐标偏移
const Y = 155
// 钟的半径
const R = 150 renderClockPlate()
renderClockTime()
renderClockHand()
setInterval(function () {
clockHandCtx.clearRect(0, 0, clockHandCvs.width, clockHandCvs.height)
renderClockHand()
}, 1000) // 渲染表盘
function renderClockPlate () {
drawCircle(clockCtx, clockCvs, X, Y, '#070702', R, 1)
drawCircle(clockCtx, clockCvs, X, Y, '#4f4f52', R - 3, 5)
drawCircle(clockCtx, clockCvs, X, Y, '#070702', R - 6, 3)
drawCircle(clockCtx, clockCvs, X, Y, '#dddddd', R - 8)
drawCircle(clockCtx, clockCvs, X, Y, '#121213', R - 10, 3)
drawCircle(clockCtx, clockCvs, X, Y, '#19191a', R - 12, 0, 'fill', true) drawCircle(clockCtx, clockCvs, X, Y, '#4e4738', 15, 0, 'fill')
drawCircle(clockCtx, clockCvs, X, Y, '#eac55a', 10, 0, 'fill')
drawCircle(clockCtx, clockCvs, X, Y, '#3e3e41', 8, 0, 'fill')
drawCircle(clockCtx, clockCvs, X, Y, '#000000', 3, 0, 'fill')
} // 渲染时间
function renderClockTime () {
for (let angle = -90; angle < 270; angle = angle + 6) {
let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
let r = angle % 90 === 0 ? 4 : 2
drawCircle(clockCtx, clockCvs, x, y, '#eac55a', r, 0, 'fill')
if (angle % 30 === 0) {
x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
clockCtx.font = angle % 90 === 0 ? 'bold 15px yahei' : '12px yahei'
clockCtx.fillText((angle + 90) / 30 || 12, x , y)
}
}
} // 渲染表针
function renderClockHand () {
let date = new Date()
let hour = date.getHours()
let minute = date.getMinutes()
let second = date.getSeconds()
// 秒针
let angle1 = (second * 6 - 90)
let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
drawLine(clockHandCtx, [[X, Y], [x, y]], 1)
// 分针
let angle2 = (minute * 6 - 90)
x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
drawLine(clockHandCtx, [[X, Y], [x, y]], 2)
// 时针, 时针角度 = 小时角度 + 分钟角度
let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
drawLine(clockHandCtx, [[X, Y], [x, y]], 4)
} /**
* @param {String} color 颜色
* @param {Number} r 圆半径
* @param {Number} lineWidth 线条粗细
* @param {String} type 类型,stroke/fill
* @param {Boolean} isLinear 是否渐变
*/
function drawCircle (ctx, cvs, x, y,color = '#000000', r = 10, lineWidth = 2, type = 'stroke', isLinear = false) {
let grd = ctx.createLinearGradient(0, 0, cvs.width, cvs.height)
grd.addColorStop(0, color)
grd.addColorStop(0.5, '#555555')
grd.addColorStop(1, color)
ctx[type + 'Style'] = isLinear ? grd : color
ctx.lineWidth = lineWidth
ctx.beginPath()
ctx.arc(x, y, r, 0, Math.PI * 2, true)
ctx.closePath()
ctx[type]()
} /**
* @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
* @param {String} color 颜色
* @param {Number} lineWidth 线条粗细
*/
function drawLine (ctx, pos, lineWidth = 2, color = '#eac55a') {
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
ctx.beginPath()
ctx.moveTo(pos[0][0], pos[0][1])
for (let i = 0, len = pos.length; i < len; i++) {
ctx.lineTo(pos[i][0], pos[i][1])
}
ctx.stroke()
ctx.closePath()
}
})()
</script>
</body>
</html>

  

Canvas - 时钟绘制的更多相关文章

  1. canvas自适应圆形时钟绘制

    前面的话 前面介绍过canvas粒子时钟的绘制,本文将详细介绍canvas自适应圆形时钟绘制 效果演示 最终自适应圆形时钟的效果如下所示 功能分析 下面来分析一下该圆形时钟的功能 [1]静态背景 对于 ...

  2. 环形进度条的实现方法总结和动态时钟绘制(CSS3、SVG、Canvas)

    缘由: 在某一个游戏公司的笔试中,最后一道大题是,“用CSS3实现根据动态显示时间和环形进度[效果如下图所示],且每个圆环的颜色不一样,不需要考虑IE6~8的兼容性”.当时第一想法是用SVG,因为SV ...

  3. canvas基础绘制-绚丽时钟

    效果图: 与canvas基础绘制-绚丽倒计时的代码差异: // var endTime = new Date();//const声明变量,不可修改,必须声明时赋值: // endTime.setTim ...

  4. 原生js之canvas时钟组件

    canvas一直是前端开发中不可或缺的一种用来绘制图形的标签元素,比如压缩上传的图片.比如刮刮卡.比如制作海报.图表插件等,很多人在面试的过程中也会被问到有没有接触过canvas图形绘制. 定义 ca ...

  5. Javascript高级编程学习笔记(88)—— Canvas(5)绘制文本

    绘制文本 同样的,canvas也为绘制文本提供了相应的方法. 2D上下文提供的文本绘制方法主要有两个: fillText() strokeText() 这两个方法都接受四个参数 要绘制的文本字符串 绘 ...

  6. Javascript高级编程学习笔记(87)—— Canvas(4)绘制路径

    绘制路径 2D上下文支持许多在画布上绘制路径的方法 通过路径可以创造出复杂的形状和线条,要绘制路径首先必须调用beginPath()方法,表示开始绘制路径 然后再通过下列的方法绘制路径: arc(x, ...

  7. 浅谈JavaScript的Canvas(绘制图形)

    HTML5中新增加的一个元素canvas,要使用canvas元素,浏览器必须支持html5.通过canvas标签来创建元素,并需要为canvas指定宽度和高度,也就是绘图区域的大小. <canv ...

  8. canvas快速绘制圆形、三角形、矩形、多边形

    想看前面整理的canvas常用API的同学可以点下面: canvas学习之API整理笔记(一) canvas学习之API整理笔记(二) 本系列文章涉及的所有代码都将上传至:项目代码github地址,喜 ...

  9. Coffeescript实现canvas时钟

    前言 参照Mozilla 官方教程,要在Canvas上画动画时钟,思路非常有意思. 把动画看作是多个帧组成,定时每个时间点在Canvas上画一帧来实现动画.而Mozilla 官方教程画图实现的思路有意 ...

随机推荐

  1. 使用listview空控件展示数据

    1.使用listview控件可以一次性的将有关的全部图像保存在控件中,建立集合图像. 图像列表控件的主要属性 属性                                           ...

  2. WCF跨域解决方法及一些零碎的东西。

    之前发过一篇随笔,说的WCF配置文件配置问题.里面也配了跨域支持,但是jsoncollback只支持Get请求,Post请求是解决不了,所以这里把真正的WCF跨域问题贴出来. 话不多说,直接帖配置文件 ...

  3. Git常用命令(一)------ 本地操作

    本文总结自廖雪峰的网站. 几个名词: 工作区(Working Directory):电脑里能看到的目录 版本库(Repository):包含暂存区和master 暂存区(Stage):待放入maste ...

  4. MySQL之集合函数与分组查询

    这是分组查询用到的语句,也包括了排序以及常用的集合函数

  5. Beta 集合

    Beta冲刺序列: Beta凡事预则立 :Beta No.0 Beta冲刺Day1:Beta No.1 Beta冲刺Day2:Beta No.2 Beta冲刺Day3:Beta No.3 Beta冲刺 ...

  6. C语言博客作业--函数 陈张鑫

    一.PTA实验作业 题目1:6-3 使用函数判断完全平方数 1. 本题PTA提交列表 2. 设计思路 1.定义int IsSquare( int n )函数 2.判断(sqrt(n)是否为整数 3., ...

  7. 20155306 2006-2007-2 《Java程序设计》第3周学习总结

    20155306 2006-2007-2 <Java程序设计>第3周学习总结 教材学习内容总结 第四章 认识对象 4.1 类与对象 定义类 1.先在程序中定义类: Clothes{ Str ...

  8. C/C++生成随机数

    一.rand和srand   在C++11标准出来之前,C/C++都依赖于stdlib.h头文件的rand或者srand来生成随机数.   其不是真正的随机数,是一个伪随机数,是根据一个数(我们可以称 ...

  9. C#中委托。

    委托(delegate):是一个类型.其实winform中控件的事件也是特殊的委托类型. 如: 自定义委托:自定义委托在winform中的用法. 当要在子线程中更新UI时,必须通过委托来实现. pri ...

  10. python3 常用模块

    一.time与datetime模块 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们 ...