Canvas - 时钟绘制
导语:距离上一次写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 - 时钟绘制的更多相关文章
- canvas自适应圆形时钟绘制
前面的话 前面介绍过canvas粒子时钟的绘制,本文将详细介绍canvas自适应圆形时钟绘制 效果演示 最终自适应圆形时钟的效果如下所示 功能分析 下面来分析一下该圆形时钟的功能 [1]静态背景 对于 ...
- 环形进度条的实现方法总结和动态时钟绘制(CSS3、SVG、Canvas)
缘由: 在某一个游戏公司的笔试中,最后一道大题是,“用CSS3实现根据动态显示时间和环形进度[效果如下图所示],且每个圆环的颜色不一样,不需要考虑IE6~8的兼容性”.当时第一想法是用SVG,因为SV ...
- canvas基础绘制-绚丽时钟
效果图: 与canvas基础绘制-绚丽倒计时的代码差异: // var endTime = new Date();//const声明变量,不可修改,必须声明时赋值: // endTime.setTim ...
- 原生js之canvas时钟组件
canvas一直是前端开发中不可或缺的一种用来绘制图形的标签元素,比如压缩上传的图片.比如刮刮卡.比如制作海报.图表插件等,很多人在面试的过程中也会被问到有没有接触过canvas图形绘制. 定义 ca ...
- Javascript高级编程学习笔记(88)—— Canvas(5)绘制文本
绘制文本 同样的,canvas也为绘制文本提供了相应的方法. 2D上下文提供的文本绘制方法主要有两个: fillText() strokeText() 这两个方法都接受四个参数 要绘制的文本字符串 绘 ...
- Javascript高级编程学习笔记(87)—— Canvas(4)绘制路径
绘制路径 2D上下文支持许多在画布上绘制路径的方法 通过路径可以创造出复杂的形状和线条,要绘制路径首先必须调用beginPath()方法,表示开始绘制路径 然后再通过下列的方法绘制路径: arc(x, ...
- 浅谈JavaScript的Canvas(绘制图形)
HTML5中新增加的一个元素canvas,要使用canvas元素,浏览器必须支持html5.通过canvas标签来创建元素,并需要为canvas指定宽度和高度,也就是绘图区域的大小. <canv ...
- canvas快速绘制圆形、三角形、矩形、多边形
想看前面整理的canvas常用API的同学可以点下面: canvas学习之API整理笔记(一) canvas学习之API整理笔记(二) 本系列文章涉及的所有代码都将上传至:项目代码github地址,喜 ...
- Coffeescript实现canvas时钟
前言 参照Mozilla 官方教程,要在Canvas上画动画时钟,思路非常有意思. 把动画看作是多个帧组成,定时每个时间点在Canvas上画一帧来实现动画.而Mozilla 官方教程画图实现的思路有意 ...
随机推荐
- phpcms v9 列表页直接下载功能代码实现
{pc:content action="lists" catid="$catid" num="3" order="id DESC& ...
- 巨人大哥谈Web应用中的Session(session详解)
巨人大哥谈Web应用中的Session(session详解) 虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一技术. ...
- 第七周PTA作业
第一题: #include<stdio.h> int main() { ; ; ){ sum=sum+i; i++; } printf("sum = %d\n",sum ...
- 数据故障的恢复-MSSQL ndf文件大小变为0 KB恢复过程
一.故障描述 成都某客户,存储损坏,数据库崩溃.重组存储,恢复数据库文件,发现有四个ndf文件大小变为0 KB.数据库大小约80TB.数据库中有1223个文件,数据库每10天生成一个NDF文件,每个N ...
- C#中的函数式编程:递归与纯函数(二)
在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential transparency)来定义的.如果一个 ...
- 第四章 Ajax与jQuery
第四章 Ajax与jQuery 一.Ajax简介 在传统的Web应用中,每次请求服务器都会生成新的页面,用户在提交请求后,总是要等待服务器的响应.如果前一个请求没有响应,则后一个请求就不能发送,在 ...
- PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式
php模式设计之单例模式 什么是单例模式? 单例模式是指在整个应用中只有一个实例对象的设计模式 为什么要用单例模式? php经常要链接数据库,如果在一个项目中频繁建立连接数据库,会造成服务器资源的很大 ...
- LxmlLinkExtractor类参数解析
LxmlLinkExtractor LxmlLinkExtractor 是一种强大的链接提取器,使用他能很方便的进行选项过滤,他是通过xml中强大的HTMLParser实现的 源代码如下: class ...
- 新概念英语(1-103)The French Test
Lesson 103 The French test 法语考试 Listen to the tape then answer this question. How long did the exam ...
- Spring Boot面试题
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...