导语:距离上一次写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. Java基础-this和super的区别

    package com.cn.This; /** * this与super的区别: * 1.this相当于指向本类的对象的指针,调用本类的另一种类型的构造方法 * 2.super调用的是父类中形参相同 ...

  2. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  3. 听翁恺老师mooc笔记(3)--指针的定义

    在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...

  4. alpha-咸鱼冲刺day7

    一,合照 emmmmm.自然还是没有的. 二,项目燃尽图 三,项目进展 正在写登陆+注册ing 注册搞出来了!!!!!!!!QAQ(喜极而泣!!!!.jpg) 四,问题困难 数据流程大概是搞定了.不过 ...

  5. DNS协议(一)

    在互联网上要想与另外一台主机通信,要知道对方的IP地址,但是IP地址是很难记忆的, 比如百度的一台服务器的IP地址为115.239.210.27,我们在浏览器中输入http://115.239.210 ...

  6. 弹幕视频播放app案例分析

    产品 哔哩哔哩动画 相对于其他视频播放软件来说,哔哩哔哩动画没有广告影响观看体验,而且内容更偏重于二次元,因此我更倾向于使用它. 第一部分 调研, 评测 #第一次上手体验 用起来还是比较方便,可以快速 ...

  7. win7开启wifi

    在启用本地共享连接时,出现的错误! 我已经建了一个无线临时网络,来启用共享用来上网的!Internet连接共享访问被启用时,出现了一个错误(null)?而且这错误也会在系统日志里留下记录,都是些莫名其 ...

  8. Python打包分发工具setuptools

    作为Python标准的打包及分发工具,setuptools可以说相当地简单易用.它会随着Python一起安装在你的机器上.你只需写一个简短的setup.py安装文件,就可以将你的Python应用打包 ...

  9. 【iOS】Swift LAZY 修饰符和 LAZY 方法

    延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略.另外,有些情况下我们并不会立即用到 ...

  10. 在网络编程中的io流小问题

    在客户端和服务端调用io流进行传输数据的过程中,当将数据write到outputstream中,需要及时刷新,否则会发生io阻塞. 在输入数据的时候,最好选用BufferedReader,因为read ...