前言
HTML5支持的canvas可以在Web中画各种相对复杂的图案,只要你愿意,前端不需要美工设计再提供任何切图!废话不多说,进入正题,本文将给大家介绍通过HTML5 Canvas实现炫酷钟表效果。
正文
分解步骤
首先先到网上随便找一个钟表的图片当作本文的设计图。
这个图表的渲染可以分为几个大的方向,钟表的轮盘,钟表的刻度和上面的数字,钟表指针和中间的圆心,这样钟表大概的步骤就完成了,最后再实现钟表转动的动画这个就算完成了。
画布初始化
使用2d上下文建立画布
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>基于canvas实现clock效果</title> </head> <body> <canvas id="clock" width="200" height="200"></canvas> </body> <script src="./clock.js"></script> </html> var drawing = document.getElementById('clock'), context;
定义常量
定义常量的目的是为了增强这个钟表样式的可配置性和可维护性,之后函数可能会大量用到的常量定义如下:
const radius = 4, // 指数圈半径 radius1 = 100, // 圆1半径(这里圆1的直径需要为画布width的一半, 不然下面刻度的部分可能对不上) radius2 = 90, // 圆2半径 radius3 = 83, // 圆3半径 fontRadius = 65, // 字体距圆心的距离 hourWidth = 5, // 时针宽度 hourHeight = 55, // 时针高度 hourShadow = 2; // 时针阴影 minuteWidth = 3, // 分针宽度 minuteHeight = 68, // 分针高度 minuteShadow = 1; // 分针阴影 secondWidth = 1, // 秒针宽度 secondHeight = 80, // 秒针高度 secondShadow = 0.5; // 秒针阴影
工具类函数
这里定义了sin,cos和degTolength函数,具体的说明已经写在注释里了,为什么要定义sin,cos?Math库里不是有现成的,因为太久没写数学题了,额,有点分不清sin,cos的正负,所以为了后面函数绘制计算的方便,便转换成了角度并且取了字符串
/** * 把sin值封装成绝对正数,因为我不记得什么时候取负数了,头皮发麻 * @params num 度数 */ function sin(num){ return Math.abs(Math.sin(degTolength(num))); } /** * 把cos值封装成绝对正数 * @params num 度数 */ function cos(num){ return Math.abs(Math.cos(degTolength(num))); } /** * 度数转弧度 */ function degTolength(num){ return num * (2 * Math.PI / 360); }
绘制钟表轮框
钟表轮框不难看出,由三个圆叠加形成,第一个是白变黑的渐变色,第二个是黑灰渐变色,第三个橘黄变黄的渐变色
/** * 钟表轮框 */ function paintClockBorder(){ // 先画一个圈圈出来 context.beginPath(); context.arc(100, 100, radius1, 0, 2 * Math.PI, false); // 调个白变黑渐变色 var fTo0 = context.createLinearGradient(-50, 100, 200, 100); fTo0.addColorStop(0, '#fff'); fTo0.addColorStop(1, '#000'); // 第一个最外面的圈圈搞定 context.fillStyle = fTo0; context.fill(); // 咱开始画第二个圈圈 context.beginPath(); context.arc(100, 100, radius2, 0, 2 * Math.PI, false); // 搞个黑灰渐变色 var bTod = context.createLinearGradient(10, 100, 190, 100); bTod.addColorStop(0, '#000'); bTod.addColorStop(1, '#39452D'); context.fillStyle = bTod; context.fill(); // 终于搞第三个圈圈了 context.beginPath(); context.arc(100, 100, radius3, 0, 2 * Math.PI, false); // 调个橘黄to黄渐变 var oToy = context.createLinearGradient(20, 70, 180, 170); oToy.addColorStop(0, '#E17101'); oToy.addColorStop(1, '#FFF507'); // 第三个圈圈搞定 context.fillStyle = oToy; context.fill(); }
钟表指数
这里主要就是初中数学的三角sin,cos的计算吧,唯一要注意的就是因为我取了绝对值,所以要分四个区间去渲染
/** * 钟表指数 */ function paintClockSign(){ context.beginPath(); // 咱先画大的,每10分钟的,注意要分四个区间去渲染 for(let i = 0; i < 12; i++){ // 每加一个就加30deg if(i < 3){ context.moveTo(radius1 + radius3 * sin(30 * i) + radius, radius1 - radius3 * cos(30 * i)); context.arc(radius1 + radius3 * sin(30 * i), radius1 - radius3 * cos(30 * i), radius, 0, 2 * Math.PI, false); }else if(i >= 3 && i < 6){ context.moveTo(radius1 + radius3 * sin(30 * i) + radius, radius1 + radius3 * cos(30 * i)); context.arc(radius1 + radius3 * sin(30 * i), radius1 + radius3 * cos(30 * i), radius, 0, 2 * Math.PI, false); }else if(i >= 6 && i < 9){ context.moveTo(radius1 - radius3 * sin(30 * i) + radius, radius1 + radius3 * cos(30 * i)); context.arc(radius1 - radius3 * sin(30 * i), radius1 + radius3 * cos(30 * i), radius, 0, 2 * Math.PI, false); }else{ context.moveTo(radius1 - radius3 * sin(30 * i) + radius, radius1 - radius3 * cos(30 * i)); context.arc(radius1 - radius3 * sin(30 * i), radius1 - radius3 * cos(30 * i), radius, 0, 2 * Math.PI, false); } } context.fillStyle = '#000'; context.fill(); // 然后咱画一下分钟的,分钟的每加一个是加6deg context.beginPath(); for(let i = 0; i < 60; i++){ if(i < 15){ context.moveTo(radius1 + (radius3 - radius) * sin(6 * i), radius1 - (radius3 - radius) * cos(6 * i)); context.lineTo(radius1 + radius3 * sin(6 * i), radius1 - radius3 * cos(6 * i)); }else if(i >= 15 && i < 30){ context.moveTo(radius1 + (radius3 - radius) * sin(6 * i), radius1 + (radius3 - radius) * cos(6 * i)); context.lineTo(radius1 + radius3 * sin(6 * i), radius1 + radius3 * cos(6 * i)); }else if(i >= 30 && i < 45){ context.moveTo(radius1 - (radius3 - radius) * sin(6 * i), radius1 + (radius3 - radius) * cos(6 * i)); context.lineTo(radius1 - radius3 * sin(6 * i), radius1 + radius3 * cos(6 * i)); }else{ context.moveTo(radius1 - (radius3 - radius) * sin(6 * i), radius1 - (radius3 - radius) * cos(6 * i)); context.lineTo(radius1 - radius3 * sin(6 * i), radius1 - radius3 * cos(6 * i)); } } context.strokeStyle = '#AD9300'; context.stroke(); // 最后我们开始写度数的字 context.font = '20px Arial'; context.textAlign = 'center'; context.textBaseline = 'middle'; for(let i = 1; i <= 12; i++){ if(i <= 3){ context.fillText(i, radius1 + fontRadius * sin(30 * i), radius1 - fontRadius * cos(30 * i)); }else if(i > 3 && i <= 6){ context.fillText(i, radius1 + fontRadius * sin(30 * i), radius1 + fontRadius * cos(30 * i)); }else if(i > 6 && i <= 9){ context.fillText(i, radius1 - fontRadius * sin(30 * i), radius1 + fontRadius * cos(30 * i)); }else{ context.fillText(i, radius1 - fontRadius * sin(30 * i), radius1 - fontRadius * cos(30 * i)); } } }
绘制钟表指针
用到最关键的是rotate,先绘制竖直的矩形,再进行旋转,不过在调用rotate的时候需要先把原点换到圆心的位置
/** * 钟表指针 */ function paintClockPointer(){ let hour = new Date().getHours(), minute = new Date().getMinutes(), second = new Date().getSeconds(); context.beginPath(); context.fillStyle = '#fff'; // 搞个阴影吧,不搞阴影太丑了。 context.shadowBlur = 4; context.shadowColor = '#B97C29'; // 先把画布原点换到圆心,因为得绕中心旋转 context.translate(radius1, radius1); // 先时针吧,时针得粗一点 context.shadowOffsetX = hourShadow; context.shadowOffsetY = hourShadow; context.rotate(degTolength(hour * 30)); context.fillRect(- 2.5, - hourHeight + 10, hourWidth, hourHeight); // 分针 context.shadowOffsetX = minuteShadow; context.shadowOffsetY = minuteShadow; context.rotate(degTolength( - hour * 30 + minute * 6)); context.fillRect(- 2.5, - minuteHeight + 10, minuteWidth, minuteHeight); //秒针 context.shadowOffsetX = secondShadow; context.shadowOffsetY = secondShadow; context.rotate(degTolength(- ( - hour * 30 + minute * 6) + second * 6)); context.fillRect(- 2.5, - secondHeight + 10, secondWidth, secondHeight); // 圆心画个小黑点吧 context.beginPath(); context.arc(0 ,0 ,1 ,0, 2 * Math.PI, false); context.fillStyle = '#000'; }
钟表动画
经过上面的部分钟表的静态就已经完成了,并且会和目前时间同步,但是动画怎么实现呢,这里采取的方式清空画布,重新渲染,并把这个过程放入定时函数来实现钟表的动画
// 判断浏览器是否支持canvas if(drawing.getContext){ context = drawing.getContext('2d'); setInterval(paintClock, 1000); } /** * 绘制钟表 */ function paintClock(){ // 清空画布 context.height = context.height; // 保存初始的配置,颜色,画布圆心,旋转度数等 context.save(); paintClockBorder(); paintClockSign(); paintClockPointer(); // 重置配置 context.restore(); }
小结
到这里,基于HTML5 Canvas实现炫酷钟表效果就结束了, 具体效果如下动图
附上github链接:github.com/czm129043370
有需要的小伙伴可以自取,觉得不错别忘了给个star哈
小伙伴们今天的学习就到这里了,如果觉得本文对你有帮助的话,欢迎转发,评论,收藏,点赞!!!