JavaScript实现时钟滴答声效果


Posted in Javascript onJanuary 29, 2017

下面一段代码给大家分享js实现时钟滴答声功能,具体代码如下所示:

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
 <meta name="keywords" content="clock">
 <meta name="description" content="This is a clock">
 <title>Clock</title>
 </head>
 <body>
 <audio id="ticktock">
 <source = src="ticktock.mp3" type="audio/mp3">
 </audio>
 <script type="text/javascript">
 /*
 年(y)可以用 1-4 个占位符
 月(M)、日(d)、时(H,24时)、时(h,12时)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符
 毫秒(S)只能用 1 个占位符(是 1-3 位数字) 
 AM或PM只能用 1 个占位符(是 2 位英文)
 上午或下午(T)只能用 1 个占位符(是 2 位中文)
 星期(E)可以用 1-3 个占位符
 季度(q)只能用 1 个占位符(是 1 位数字)
 */
 Date.prototype.format = function(fmt) {
 var map = {
  "M+" : this.getMonth() + 1, //月
  "d+" : this.getDate(), //日
  "H+" : this.getHours(), //24时
  /*
  上午12时只代表当天上午的12时,下午的12时代表当天下午的12时,
  0时代表第二天的开始,即前面一天12时已过0时开始计算新一天的时间,
  虽然说时间上跟前面那一天下午12时重合,但日期已经发生更改,所以不能说0时就是12时
  */
  "h+" : this.getHours()%12 == 0 ? 12 : this.getHours()%12,//12时
  "m+" : this.getMinutes(), //分
  "s+" : this.getSeconds(), //秒
  "S" : this.getMilliseconds(), //毫秒
  "t" : this.getHours() < 12 ? "AM" : "PM",
  "T" : this.getHours() < 12 ? "上午" : "下午",
 };
 var week = {
  "0" : "日",
  "1" : "一",
  "2" : "二",
  "3" : "三",
  "4" : "四",
  "5" : "五",
  "6" : "六",
 }
 var quarter = {
  "0" : "一",
  "1" : "二",
  "2" : "三",
  "3" : "四",
 }
 if(/(y+)/.test(fmt)) {
  fmt = fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
 }
 if(/(E+)/.test(fmt)) {
  var weekPreStr;
  switch(RegExp.$1.length) {
  case 1:
  weekPreStr = "";
  break;
  case 2:
  weekPreStr = "周";
  break;
  default:
  weekPreStr = "星期";
  break;
  }
  fmt = fmt.replace(RegExp.$1, weekPreStr + week[this.getDay()]);
 }
 if(/(q)/.test(fmt)) {
  fmt = fmt.replace(RegExp.$1, quarter[Math.floor(this.getMonth() / 3)]);
 }
 for(var key in map) {
  if(new RegExp("(" + key + ")").test(fmt)) {
  fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? map[key] : ("00" + map[key]).substr((map[key]+"").length));
  }
 }
 return fmt;
 }
 </script>
 <script>
 var canvas = document.createElement("canvas");
 document.body.appendChild(canvas);
 var ctx = canvas.getContext("2d");
 var halfPI = Math.PI / 2;
 var doublePI = Math.PI * 2;
 //阴影级别
 var shadowBlur = 10;
 //阴影宽度
 var shadowWidth = 8;
 //阴影在X方向上的偏移
 var shadowOffsetX = 5;
 //阴影在Y方向上的便宜
 var shadowOffsetY = 5;
 //深色阴影
 var shadowDarkColor = "rgba(0,0,0,0.8)";
 //浅色阴影
 var shadowLightColor = "rgba(0,0,0,0.1)";
 //画布中心到边缘的内切圆半径
 var canvasRadius = 250;
 canvas.width = canvasRadius * 2;
 canvas.height = canvasRadius * 2;
 //获取画布中心的坐标
 var cx = canvasRadius;
 var cy = canvasRadius;
 //时钟外圈的贝塞尔花纹个数
 var bezierPatternCount = 36;
 //时钟外圈的贝塞尔花纹波峰处半径
 var bezierPeakRadius = canvasRadius - 10;
 //时钟外圈的贝塞尔花纹一半的角度
 var bezierHalfSpan = doublePI / bezierPatternCount / 2;
 //时钟外圈的贝塞尔花纹底部半径
 var bezierRadius = bezierPeakRadius - 20;
 //时钟外圈的贝塞尔花纹颜色
 var bezierPatternColor = "Plum";
 //时钟外圈半径
 var clockBorderRadius = bezierRadius - 10;
 //时钟外圈宽度
 var clockBorderWidth = 10;
 //时钟外圈颜色
 var clockBorderColor = "Aqua";
 //时钟外圈阴影半径
 var clockBorderShadowRadius = clockBorderRadius - shadowWidth + 1;
 //时钟整数时间刻度线宽
 var clockScaleWidth = 2;
 //时钟整数时间刻度外半径
 var clockScaleOuterRadius = clockBorderRadius - shadowWidth;
 //时钟整数时间刻度内半径
 var clockScaleInnerRadius = clockScaleOuterRadius - 20;
 //时钟刻度颜色
 var clockScaleColor = "Black";
 //时钟非整数时间处半径
 var clockScaleMiddleRadius = clockScaleOuterRadius - 10;
 //时钟数字半径
 var clockNumRadius = clockBorderShadowRadius - 40;
 //时钟数字字体
 var clockNumFont = "25px Arial";
 //时钟数字颜色
 var clockNumColor = "black";
 //数字日期距中心的垂直距离
 var digitalDateMarginCenter = 50;
 //数字日期颜色
 var digitalDateColor = "Black";
 //数字日期字体
 var digitalDateFont = "bold 18px Arial";
 //数字时间距中心的垂直距离
 var digitalTimeMarginCenter = 100;
 //数字时间颜色
 var digitalTimeColor = "white";
 //数字时间背景颜色
 var digitalTimeBgColor = "DarkSlateBlue";
 //数字时间字体
 var digitalTimeFont = "bold 25px Arial";
 //数字时间高度的一半
 var digitalTimeHeight = 40;
 //数字时间分隔线宽度
 var digitalTimeSpanLineWidth = 2;
 //时钟中心点内圆的半径
 var clockCenterInnerDotRadius = 7;
 //时钟中心点内圆的颜色
 var clockCenterInnerDotColor = "FireBrick";
 //时钟中心点外圆的半径
 var clockCenterOuterDotRadius = 10;
 //时钟中心点外圆的颜色
 var clockCenterOuterDotColor = "Maroon";
 //时针线宽
 var clockNeedleWidth = 5;
 //时针半径
 var clockHourNeedleRadius = clockBorderShadowRadius - 120;
 //时针颜色
 var clockHourNeedleColor = "DarkGreen";
 //分针半径
 var clockMinuteNeedleRadius = clockBorderShadowRadius - 80;
 //分针颜色
 var clockMinuteNeedleColor = "DarkSlateGray";
 //秒针半径
 var clockSecondNeedleRadius = clockBorderShadowRadius - 40;
 //秒针尾部半径
 var clockSecondNeedleBottomRadius = -20;
 //秒针颜色
 var clockSecondNeedleColor = "FireBrick";
 //画圆环
 function strokeCircle(cx, cy, r) {
 ctx.beginPath();
 ctx.arc(cx, cy, r, 0, doublePI);
 ctx.stroke();
 }
 //画圆
 function fillCircle(cx, cy, r) {
 ctx.beginPath();
 ctx.arc(cx, cy, r, 0, doublePI);
 ctx.fill();
 }
 //绘制线条
 function strokeLine(x1, y1, x2, y2) {
 ctx.beginPath();
 ctx.moveTo(x1, y1);
 ctx.lineTo(x2, y2);
 ctx.stroke();
 }
 //根据角度和半径计算圆上相应位置的坐标(最右侧为起始角度,顺时针方向为正)
 function circlePos(cx, cy, theta, radius) {
 var pos = {
  x: cx + radius * Math.cos(theta),
  y: cy + radius * Math.sin(theta),
 };
 return pos;
 }
 //在圆环上绘制刻度线
 function strokeCircleLine(cx, cy, theta, r1, r2) {
 var pos1 = circlePos(cx, cy, theta, r1);
 var pos2 = circlePos(cx, cy, theta, r2);
 strokeLine(pos1.x, pos1.y, pos2.x, pos2.y);
 }
 //设置默认阴影
 function setShadow(type) {
 ctx.lineWidth = shadowWidth;
 ctx.shadowBlur = shadowBlur;
 ctx.shadowOffsetX = shadowOffsetX;
 ctx.shadowOffsetY = shadowOffsetY;
 if(type === 1) {
  ctx.shadowColor = shadowLightColor;
 } else {
  ctx.shadowColor = shadowDarkColor;
 }
 }
 //取消阴影
 function clearShadow() {
 ctx.shadowColor = "rgba(0,0,0,0)";
 ctx.shadowBlur = 0;
 ctx.shadowOffsetX = 0;
 ctx.shadowOffsetY = 0;
 }
 //绘制时钟外圈的贝塞尔花纹
 function renderBezierPattern() {
 ctx.fillStyle = bezierPatternColor;
 ctx.beginPath();
 var theta = 0;
 //由于circlePos是顺时针方向正, 故圈也是顺时针方向
 var beginPos = circlePos(cx, cy, theta, bezierRadius);
 ctx.moveTo(beginPos.x, beginPos.y);
 while(theta < doublePI) {
  //贝塞尔曲线控制点
  var controlTheta = theta + bezierHalfSpan;
  var controlPos = circlePos(cx, cy, controlTheta, bezierPeakRadius);
  //贝塞尔曲线终止点
  var endTheta = controlTheta + bezierHalfSpan;
  var endPos = circlePos(cx, cy, endTheta, bezierRadius);
  ctx.quadraticCurveTo(controlPos.x, controlPos.y, endPos.x, endPos.y);
  theta = endTheta;
 }
 //绘制圆counterclockwise=false, 即默认是顺时针方向
 ctx.arc(cx, cy, clockBorderRadius, 0, doublePI, true);
 //注意: 两个相反方向的路径内部为填充范围
 ctx.fill();
 }
 //绘制时钟边框
 function renderClockBorder() {
 //画外框
 ctx.strokeStyle = clockBorderColor;
 ctx.lineWidth = clockBorderWidth;
 strokeCircle(cx, cy, clockBorderRadius);
 //画外框的内阴影
 ctx.strokeStyle = shadowLightColor;
 setShadow(1);
 strokeCircle(cx, cy, clockBorderShadowRadius);
 clearShadow();
 }
 //绘制时钟圆周上的数字和刻度部分
 function renderClockNums() {
 ctx.textAlign = "center";
 ctx.textBaseline = "middle";
 ctx.font = clockNumFont;
 var span = doublePI / 60;
 for(var i = 1, radian = -halfPI + span; i <= 60; i++, radian += span) {
  if(i % 5 == 0) {
  //绘制刻度
  ctx.strokeStyle = clockScaleColor;
  ctx.lineWidth = clockScaleWidth;
  strokeCircleLine(cx, cy, radian, clockScaleInnerRadius, clockScaleOuterRadius);
  //绘制数字
  var pos = circlePos(cx, cy, radian, clockNumRadius);
  var num = i / 5;
  ctx.fillStyle = clockNumColor;
  ctx.fillText(num, pos.x, pos.y);
  } else {
  ctx.strokeStyle = clockScaleColor;
  ctx.lineWidth = clockScaleWidth;
  strokeCircleLine(cx, cy, radian, clockScaleMiddleRadius, clockScaleOuterRadius);
  }
 }
 }
 //绘制数字时钟
 function renderDigital(date) {
 //绘制日期
 ctx.textAlign = "center";
 ctx.textBaseline = "middle";
 ctx.font = digitalDateFont;
 ctx.fillStyle = digitalDateColor;
 var text = date.format("yyyy年MM月dd日 EEE");
 ctx.fillText(text, cx, cy + digitalDateMarginCenter);
 //绘制时间
 ctx.font = digitalTimeFont;
 text = date.format(" HH mm ss ");
 ctx.fillStyle = digitalTimeBgColor;
 var textWidth = ctx.measureText(text).width;
 var textBgX = cx - textWidth / 2;
 var textBgY = cy + digitalTimeMarginCenter - digitalTimeHeight / 2;
 ctx.fillRect(textBgX, textBgY, textWidth, digitalTimeHeight);
 ctx.fillStyle = digitalTimeColor;
 ctx.fillText(text, cx, cy + digitalTimeMarginCenter);
 //绘制事件中间的分隔线
 ctx.lineWidth = digitalTimeSpanLineWidth;
 ctx.strokeStyle = digitalTimeColor;
 var textSpan = textWidth / 6;
 var leftLineX = cx - textSpan;
 strokeLine(leftLineX, textBgY, leftLineX, textBgY + digitalTimeHeight);
 var rightLineX = cx + textSpan;
 strokeLine(rightLineX, textBgY, rightLineX, textBgY + digitalTimeHeight);
 }
 //绘制时钟中心最下方红点
 function renderClockCenterOuterDot() {
 ctx.fillStyle = clockCenterOuterDotColor;
 fillCircle(cx, cy, clockCenterOuterDotRadius);
 }
 //绘制时钟中心最上方红点
 function renderClockCenterInnerDot() {
 ctx.fillStyle = clockCenterInnerDotColor;
 fillCircle(cx, cy, clockCenterInnerDotRadius);
 }
 //绘制时钟指针
 function renderClockNeedle(date) {
 var hourRadian = date.getHours() % 12 / 12 * doublePI - halfPI;
 var minuteRadian = date.getMinutes() / 60 * doublePI - halfPI;
 var secondRadian = date.getSeconds() / 60 * doublePI - halfPI;
 setShadow();
 ctx.lineCap = "round";
 ctx.lineWidth = clockNeedleWidth;
 ctx.strokeStyle = clockHourNeedleColor;
 strokeCircleLine(cx, cy, hourRadian, 0, clockHourNeedleRadius);
 ctx.strokeStyle = clockMinuteNeedleColor;
 strokeCircleLine(cx, cy, minuteRadian, 0, clockMinuteNeedleRadius);
 ctx.strokeStyle = clockSecondNeedleColor;
 strokeCircleLine(cx, cy, secondRadian, clockSecondNeedleBottomRadius, clockSecondNeedleRadius);
 ctx.lineCap = "square";
 clearShadow();
 }
 function render(date) {
 ctx.clearRect(0, 0, canvas.width, canvas.height);
 renderBezierPattern();
 renderClockBorder();
 renderClockNums();
 renderDigital(date);
 renderClockCenterOuterDot();
 renderClockNeedle(date);
 renderClockCenterInnerDot();
 }
 var lastTime = 0;
 var audio = document.getElementById("ticktock");
 function loop() {
 var date = new Date();
 var currentTime = date.getTime();
 if(currentTime - lastTime >= 1000) {
  lastTime = currentTime;
  //注意:这里设0非常关键,否则虽然会循环播放,但会从上一次暂停的地方开始播放,造成延迟
  audio.currentTime = 0;
  audio.play();
  render(date);
 }
 requestAnimationFrame(loop);
 }
 loop();
 </script>
 </body>
</html>

JavaScript实现时钟滴答声效果

以上所述是小编给大家介绍的JavaScript实现时钟滴答声效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
flash javascript之间的通讯方法小结
Dec 20 Javascript
js substr、substring和slice使用说明小记
Sep 15 Javascript
初学Jquery插件制作 在SageCRM的查询屏幕隐藏部分行的功能
Dec 26 Javascript
js实现的牛顿摆效果
Mar 31 Javascript
jQuery插件zTree实现删除树节点的方法示例
Mar 08 Javascript
关于vue-resource报错450的解决方案
Jul 24 Javascript
vue实现密码显示隐藏切换功能
Feb 23 Javascript
Vue.js 2.x之组件的定义和注册图文详解
Jun 19 Javascript
Vuex 使用及简单实例(计数器)
Aug 29 Javascript
JS使用Chrome浏览器实现调试线上代码
Jul 23 Javascript
详解JavaScript作用域 闭包
Jul 29 Javascript
vue打包静态资源后显示空白及static文件路径报错的解决
Sep 02 Javascript
Javascript中 带名 匿名 箭头函数的重要区别(推荐)
Jan 29 #Javascript
jQuery图片轮播功能实例代码
Jan 29 #Javascript
jQuery代码实现实时获取时间
Jan 29 #Javascript
用director.js实现前端路由使用实例
Jan 27 #Javascript
详解bootstrap的modal-remote两种加载方式【强化】
Jan 27 #Javascript
Jquery uploadify 多余的Get请求(404错误)的解决方法
Jan 26 #Javascript
js监听input输入框值的实时变化实例
Jan 26 #Javascript
You might like
PHP Yaf框架的简单安装使用教程(推荐)
2016/06/08 PHP
YII视图整合kindeditor扩展的方法
2016/07/13 PHP
深入讲解PHP的对象注入(Object Injection)
2017/03/01 PHP
JavaScript 模仿vbs中的 DateAdd() 函数的代码
2007/08/13 Javascript
js解析与序列化json数据(一)json.stringify()的基本用法
2013/02/01 Javascript
jquery scrollTop方法根据滚动像素显示隐藏顶部导航条
2013/05/27 Javascript
js中的scroll和offset 使用比较的实例与分析
2013/09/29 Javascript
js和html5实现手机端刮刮卡抽奖效果完美兼容android/IOS
2013/11/18 Javascript
java、javascript实现附件下载示例
2014/08/14 Javascript
jquery使用$(element).is()来判断获取的tagName
2014/08/24 Javascript
IE下通过a实现location.href 获取referer的值
2014/09/04 Javascript
jQuery中:button选择器用法实例
2015/01/04 Javascript
javascript白色简洁计算器
2015/05/04 Javascript
jQuery实现dialog设置focus焦点的方法
2015/06/10 Javascript
JS实现超简单的鼠标拖动效果
2015/11/02 Javascript
js完整倒计时代码分享
2016/09/18 Javascript
深入学习nodejs中的async模块的使用方法
2017/07/12 NodeJs
关于webpack2和模块打包的新手指南(小结)
2017/08/07 Javascript
vue2.0 路由模式mode=&quot;history&quot;的作用
2018/10/18 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
vue路由插件之vue-route
2019/06/13 Javascript
Vue实现多标签选择器
2019/11/28 Javascript
JS数组的常用10种方法详解
2020/05/08 Javascript
[48:00]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第二场 11.04
2020/11/04 DOTA
django model去掉unique_together报错的解决方案
2016/10/18 Python
python实现员工管理系统
2018/01/11 Python
Python 输出时去掉列表元组外面的方括号与圆括号的方法
2018/12/24 Python
使用celery执行Django串行异步任务的方法步骤
2019/06/06 Python
Python多线程实现支付模拟请求过程解析
2020/04/21 Python
Python 实现RSA加解密文本文件
2020/12/30 Python
夜大自我鉴定
2013/10/31 职场文书
房产公证委托书范本
2014/09/20 职场文书
城管执法人员个人对照检查材料思想汇报
2014/09/29 职场文书
初婚未育证明样本
2015/06/18 职场文书
2016全国“质量月”活动标语口号
2015/12/26 职场文书
Java详细解析==和equals的区别
2022/04/07 Java/Android