整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HTML使用Canvas绘制动画时钟

么是Canvas

<canvas> 是HTML中的一个元素,它可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画。

Canvas API 提供了一个通过 JavaScriptHTML<canvas> 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

<canvas>标签本身没有绘图能力,它仅仅是图形的容器。在HTML,一般通过Javascript语言来完成实际的操作。

创建HTML页面并添加绘图容器

本文通过Javascript操作Canvas制作一个简单的显示当前时间的动画时钟,了解和学习简单的canvas用法,仅以抛砖引玉。

首先创建一个HTML文件,为了方便管理,使用一个div标签包裹两个canvas标签,并加上一些简单的css样式。

<!doctype html>
<html lang="zh-cn">
<head><title>Canvas绘制动画时钟</title>
<style>
html,body{margin:0;padding:0}
#clockWrap {
	position: relative;
}
canvas {
	position: absolute;
}
#clock-ui {
	z-index: 2;
}
#clock-plate {
	z-index: 1;
}
</style>
</head>
<body>
  <div id="clockWrap">
  <canvas id="clock-plate"></canvas>
  <canvas id="clock-ui"></canvas>
</div>
<script></script>
</body></html>

本示例中使用了两个canvas标签(为什么使用两个,一个不是更简单吗?),一个用于绘制钟面,一个根据当前时间实时显示和更新时针、分针和秒针的动态指向。好了,话不多说,开干。

绘制钟面刻度

一个简单的时钟,可以分为钟面上的刻度和指针。其中刻度和12个数字是固定的,我们可以将它们绘制在当作背景的canvas上(示例中id为clock-plate的canvas)。

(1)要使用canvas,首先必须通过容器获取渲染上下文:

var $=function(id){return document.querySelector(id);}//这个函数只是为了方便获取dom元素
const canvasbg=$("#clock-plate"),
      canvas=$("#clock-ui"),
      ctx = canvasbg.getContext("2d"),//背景容器上下文
      ctxUI = canvas.getContext("2d");//指针容器上下文,后面代码要用
//定义画布宽度和高度,时钟圆直径,并设置画布大小
const oW=1000,oH=800,cW=400,r=cW/2,oX=oW/2,oY=oH/2;
canvas.width=oW;
canvas.height=oH;
canvasbg.width=oW;
canvasbg.height=oH;

(2)画钟的边框,为了好看,这里画两个圈:

 //画出时钟外圆框
  ctx.lineWidth = 12;
	ctx.beginPath();
	ctx.arc(oX, oY, r+14, 0, 2 * Math.PI);
	ctx.stroke();
	ctx.closePath();
	ctx.lineWidth = 8;
	//画出时钟内圆框(刻度圈)
	ctx.beginPath();
	ctx.arc(oX, oY, r, 0, 2 * Math.PI);
	ctx.stroke();
	ctx.closePath();
	ctx.beginPath();

边框效果图

(3)绘制刻度线和数字,可以利用三角函数计算出每个刻度的坐标:

利用三角函数计算刻度线的坐标位置

钟面上有12个大格,从正上方12开始,它们的度数分别是270,300,330,0,30,60,90,120,150,180,210,240。然后利用JS的Math.sin和Math.cos分别计算出各大格的坐标。注意:js中Math.sin()和Math.cos()的参数不是角度数弧度。可以使用Math.PI/180*角度来转化,比如将30度转换成弧度=Math.PI/180*30

//绘制钟表中心点
	ctx.beginPath();
	ctx.arc(oX, oY, 8, 0, 2 * Math.PI);//圆心
	ctx.fill();
	ctx.closePath();
	//设置刻度线粗细度
	ctx.lineWidth = 3;
	//设置钟面12个数字的字体、大小和对齐方式
	ctx.font = "30px serif";
	ctx.textAlign="center";
	ctx.textBaseline="middle";
	var kdx,kdy;
	//绘制12个大刻度和12个数字
	//为方便计算,先定义了0-11这12个刻度对应的度数,也可以直接定义对应的弧度。
	const hd=Math.PI/180,degr=[270,300,330,0,30,60,90,120,150,180,210,240];
	for(var i=0;i<12;i++){
		kdx=oX+Math.cos(hd*degr[i])*(r-3);
		kdy=oY+Math.sin(hd*degr[i])*(r-3);
		ctx.beginPath();
		ctx.arc(kdx, kdy, 6, 0, 2 * Math.PI);//画圆形大刻度
		ctx.fill();
    //绘制刻度对应的数字
		ctx.strokeText(i==0? 12 : i,oX+Math.cos(hd*degr[i])*(r-24),oY+Math.sin(hd*degr[i])*(r-24));
		ctx.closePath();
	}
	
	//绘制小刻度
	ctx.lineWidth = 2;
	for(var i=0;i<60;i++){
		if(i % 5 == 0) continue;//跳过与刻度重叠的刻度
		x0=Math.cos(hd*i*6);
		y0=Math.sin(hd*i*6);
		ctx.beginPath();
		ctx.moveTo(oX+x0*(r-10), oY+y0*(r-10)); 
		ctx.lineTo(oX+x0*r, oY+y0*r); //画短刻度线
		ctx.stroke(); 
		ctx.closePath();
	}

效果如图:

钟面效果图

(4)根据当前时间绘制指针

习惯上,时针粗短,分针略粗而长,秒针细长。为加大区别,示例中秒针细长并且绘制成红色。

function drawHp(i){//绘制时针
	const x0=Math.cos(hd*i*30),y0=Math.sin(hd*i*30);
	drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i){//绘制分针
	const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
	drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//绘制秒针
	const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
	drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}
//抽取出绘制三种指针时共同的部分,注意指针绘制在渲染上下文ctxUI中
function drawPointer(ox,oy,tx,ty,width,color){
	ctxUI.strokeStyle = color;
	ctxUI.lineCap = "round";
	ctxUI.lineWidth = width;
	ctxUI.beginPath();
	ctxUI.moveTo(ox, oy);
	ctxUI.lineTo(tx,ty);
	ctxUI.stroke();
	ctxUI.closePath();
}

现在已经有了绘制三种指针的方法,参数是当前时间的时、分和秒,将根据它们的值确定指针的坐标。不过,因为使用的是默认的convas坐标体系,0值实际指向3的位置,需要小小的修正一下。

window.requestAnimationFrame(function fn(){
		var d = new Date();
		ctxUI.clearRect(0,0,oW,oH);
		//度数从0开始,而0在3刻度(15分/秒位置),修正为全值减15,如果小于0则修正回来
    var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;
		hour=hour>11? hour-15 : hour-3;
		drawHp(hour>=0? hour : 12+hour);
		drawMp(minute>=0? minute : 60+minute);
		drawSp(second>=0? second : 60+second);
		window.requestAnimationFrame(fn);
});

接下来,调用window.requestAnimationFrame,在其中绘制并更新指标的位置。看看效果如何:

指针绘制情况与实际时间相符

貌似效果有了,截图时电脑上的时间是10时17分,指针绘制上,时针指向10时,分针指向17。嗯,感觉有点别扭?对了,时针和分针怎么是端端正正地指向它们的整时整分刻度上呢?实际钟表上时针和分针是展示动态进度的,此时时针应该越过10时的位置才对。没关系,我们在绘制时针和分针时别点东西,让它的角度值加上分针和秒针的值试试。

//修改后的绘制三种指针的方法
function drawHp(i,f,m){//绘制时针,参数:时,分,秒
	const x0=Math.cos(hd*(i+(f/60)+(m/600))*30),y0=Math.sin(hd*(i+(f/60)+(m/600))*30);
	drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i,f){//绘制分针,参数,分,秒
	const x0=Math.cos(hd*(i+(f/60))*6),y0=Math.sin(hd*(i+(f/60))*6);
	drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//绘制秒针
	const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
	drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}

再来看看效果,嗯,立竿见影呀:

指针指向更合理了

到此为止,canvas绘制一个简易时钟就完成了。下面继续优化一下。刚才使用requestAnimationFrame方法即时更新绘制情况。这个方法与刷新率有关,看看mdn上面怎么说的:

window.requestAnimationFrame() 方法会告诉浏览器你希望执行一个动画。它要求浏览器在下一次重绘之前,调用用户提供的回调函数。

对回调函数的调用频率通常与显示器的刷新率相匹配。虽然 75hz、120hz 和 144hz 也被广泛使用,但是最常见的刷新率还是 60hz(每秒 60 个周期/帧)。为了提高性能和电池寿命,大多数浏览器都会暂停在后台选项卡或者隐藏的 <iframe> 中运行的 requestAnimationFrame()。

本示例中,更新指针的位置并不需要很高的刷新频率,可以通过节流进行一下优化:

var fps = 5, fpsInterval = 1000 / fps,lastTime = new Date().getTime(); //记录上次执行的时间
function runStep() {
    requestAnimationFrame(runStep);
    var d=new Date(),now = d.getTime()
    var elapsed = now - lastTime;
    if (elapsed > fpsInterval) {
				ctxUI.clearRect(0,0,oW,oH);
        lastTime = now - (elapsed % fpsInterval); 
			//度数从0开始,而0在3刻度(15分/秒位置),修正为全值-15,如果小于0则用60减回
        var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;//console.log(d.getSeconds(),second);
        hour=hour>11? hour-15 : hour-3;
        drawHp(hour>=0? hour : 12+hour,minute+15,second+15);
        drawMp(minute>=0? minute : 60+minute,second+15);
        drawSp(second>=0? second : 60+second);
    }
}
runStep();

当然,实现时钟的方法是很多,比如可以使用画布的旋转(rotate方法)来实现指针的动态转动等等。

完整HTML+JS源码:

先贴上另一位开发者的原文地址,其实里面显示的是2种风格的时钟,一种为传统的挂钟,一种为数字时钟,我就分开来显示了。这里再另外改了个不同背景色的方形时钟,对于数字时钟也进行了改进。

在最后会放出源码,给喜欢研究的小伙伴一个参考。当然咯,最好还是自己能实践一下。




此教程版本是基于原文地址基础上进行小的修改而来,使用的是LESS的Mixin代码方式,使得后期调整大小及颜色会更加方便,只需要调整不同参数即可。

如果你对LESS以及mixin不太了解,建议先学习基础知识。less编译css的软件,推荐使用koala。

第一步,创建文件


结构如上图所示,CSS里创建style.less就可以了(编译引用会生成css文件),另外创建resource文件夹,里面可以再创建mixin_clock.less(不需要编译),文件起名可以根据自己的项目需求。clock.html中正常引用style.css文件就可以了。

把css目录拖到koala软件中,并且开启style.less右边的source map,这样在浏览器上,f12可以看到对应的代码位置,方便调整。


style.less里的引用代码,编译后就可以自动生成同名.css文件了:

//公共文件夹根目录
@resource_path: '../resource';
// 组件扩展
@import '@{resource_path}/mixin_clock';

等以后resource里组件多的话,也可以单独留一个引用的文件。接下来就可以正式开工了。

第二步,按原教程录入内容

原来的css样式的部分,全都放在mixin_clock.less文件中,因为是引用并且一直在编译的,所以都能正常显示。

这里要提几点顺便的调整

1、border-radius,如果是正圆的,则改为50%,而不是具体的数值。

2、background: linear-gradient(top, #f9f9f9, #666),里面的top,改为180deg,因为在部分chrome中可能会报错,而具体的角度不会


3、有些div用了position: absolute,就顺便加上z-index值,具体数字,根据层叠的前后进行设置

4、将最后的数字时钟和挂钟拆分(如果你想和在一起的话,建议改为年月日可能更实用)

第三步,调整为LESS的结构写法

使用less有个好处就是不需要反复写父级名称,部分的修改基础结构如下:

// 表盘
    .frame_face {
      ...
      &:before {
        ...
     }
      &:before {
        ...
     }
   }

tips: 因为要集成到别的框架中,自己定义的名称,建议统一改用下划线,以作区分。

这里的&,相当于.frame_face:before{}

第四步,提取公共部分,改为变量,并改成Mixin形式调用

这一步比较重要,这也是LESS比写标准CSS最显著的优势,当然现在CSS也可以写变量,但是远没有LESS写的方便。

将里面一些需要以后调整的都提取出来作为变量,我也大致罗列下调整的地方:

1、比如钟的大小,如果调整的话,里面的大小也都需要跟着调整,所以上面提到最好是按百分比作为相对的数值,那么调整一个地方,相对的部分也能跟着进行调整。

2、涉及到的颜色,比如背景色,文字颜色等。当然咯这里涉及的地方比较多,并非所有的都需要提取出来,根据自己的需求即可。

3、倒角数值也可以取出来,比如最终需要一个方形的时钟,那就改成数值就可以了。

4、改为Mixin版,以方便参数调用,为了便于区分,可以前缀加上mixin,格式参考:

.mixin_basic_clock(变量名1: 参数; 变量名2: 参数){
  代码部分1: 变量名1;
  代码部分2: 变量名2;
}

第5步,JS更改为jQuery形式,并且改进

其实这个改动不难,并且对数字时钟增加了年月日周。

原来的每个公共的判断方法提取出来,因为一般都是显示2位数,原来的小于2位,就自动在前面加个“0”,改进如下

function checkTime (i) {
 if (i < 10) {
i = "0" + i;
 }
return i;
 }
hour = checkTime(hour);
minute = checkTime(minute);
second = checkTime(second);

最终代码

clock.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>时钟</title>
  <link href="../css/style.css" rel="stylesheet" />
  <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
  <script src="../js/clock.js"></script>
</head>
<body>
  <div class="circle_clock">
    <!-- 圆形挂钟表盘 -->
    <div class="frame_face">
      <!-- 刻度 -->
      <ul class="minute_marks"></ul>
      <!-- 刻度数字 -->
      <ul class="digits">
        <li>3</li>
        <li>5</li>
        <li>9</li>
        <li>12</li>
      </ul>
      <!-- 指针 -->
      <div class="hours_hand"></div>
      <div class="minutes_hand"></div>
      <div class="seconds_hand"></div>
      <!-- 指针中心点 -->
      <div class="clock_center"></div>
    </div>
  </div>
  <div class="squire_clock">
    <!-- 方形挂钟表盘 -->
    <div class="frame_face">
      <!-- 刻度 -->
      <ul class="minute_marks"></ul>
      <!-- 刻度数字 -->
      <ul class="digits">
        <li>3</li>
        <li>6</li>
        <li>9</li>
        <li>12</li>
      </ul>
      <!-- 指针 -->
      <div class="hours_hand"></div>
      <div class="minutes_hand"></div>
      <div class="seconds_hand"></div>
      <!-- 指针中心点 -->
      <div class="clock_center"></div>
    </div>
  </div>
  <br>
  <br>
  <!-- 数字时钟 -->
  <div class="digital_clock">
    <div class="digit_ymd num"></div>
    <div class="digit_hms num"></div>
  </div>
</body>
</html>

mixin_clock.less

//传统挂钟
//@clock_wh: 钟的宽度/高度
//@clock_border: 钟的边框,50%为圆形,也可以设置成具体数值
//@frame_bgc1: 表盘背景渐变色1
//@frame_bgc2: 表盘背景渐变色2
//@mm_bgc: 刻度背景色
//@digits_c: 表盘数字文字颜色
//@hh_bgc: 时针背景颜色
//@mh_bgc:分针背景颜色
//@sh_bgc:秒针背景颜色
.mixin_basic_clock(@clock_wh: 30em; @clock_border: 50%; @frame_bgc1:#fff; @frame_bgc2:#ccc; @mm_bgc: #666; @digits_c: #555; @hh_bgc:#232425; @mh_bgc: #343536; @sh_bgc: #c00) {
    //@digits: 表盘文字中心距离
    //@digits_s: 表盘文字大小
    //@clock_center: 表盘中心大小
    @digits: @clock_wh / 4.2;
    @digits_s: @clock_wh / 20;
    @clock_center: @clock_wh / 8;
    // 表盘
    .frame_face {
        position: relative;
        width: @clock_wh;
        height: @clock_wh;
        border-radius: @clock_border;
        background: linear-gradient(180deg, #f9f9f9, #666);
        box-shadow: 0.5em 0.5em 4em rgba(0, 0, 0, 0.8);
        &:before {
            content: '';
            width: @clock_wh * 0.98;
            height: @clock_wh * 0.98;
            border-radius: @clock_border;
            position: absolute;
            top: @clock_wh * 0.01;
            left: @clock_wh * 0.01;
            background: radial-gradient(
                ellipse at center,
                rgba(246, 248, 249, 1) 0%,
                rgba(229, 235, 238, 1) 65%,
                rgba(205, 212, 217, 1) 66%,
                rgba(245, 247, 249, 1) 100%
            );
        }
        &:after {
            content: '';
            width: @clock_wh * 0.94;
            height: @clock_wh * 0.94;
            border-radius: @clock_border;
            position: absolute;
            top: @clock_wh * 0.03;
            left: @clock_wh * 0.03;
            box-shadow: inset rgba(0, 0, 0, 0.2) 0.2em 0.2em 1em;
            // border: (@clock_wh * 0.001) solid rgba(0, 0, 0, 0.2);
            background: linear-gradient(180deg, @frame_bgc1, @frame_bgc2);
        }
    }
    // 刻度
    .minute_marks li {
        display: block;
        width: 0.2em;
        height: 0.6em;
        background: @mm_bgc;
        position: absolute;
        top: 50%;
        left: 50%;
        margin: -0.4em 0 0 -0.1em;
        z-index: 8;
    }
    // 刻度数字
    .digits {
        width: @clock_wh;
        height: @clock_wh;
        border-radius: 50%;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-top: -@clock_wh / 2;
        margin-left: -@clock_wh / 2;
        padding: 0;
        z-index: 9;
        li {
            font-size: @digits_s;
            display: block;
            width: @digits_s;
            height: @digits_s;
            position: absolute;
            top: 50%;
            left: 50%;
            line-height: @digits_s;
            text-align: center;
            margin: (-@digits_s / 2) 0 0 (-@digits_s / 2);
            font-weight: bold;
            color: darken(@digits_c, 10%);
            &:nth-child(1) {
                transform: translate(@digits, 0);
            }
            &:nth-child(2) {
                transform: translate(0, @digits);
            }
            &:nth-child(3) {
                transform: translate(-@digits, 0);
            }
            &:nth-child(4) {
                transform: translate(0, -@digits);
            }
        }
    }
    // 时针
    .hours_hand {
        width: 0.8em;
        height: 7em;
        border-radius: 0 0 0.9em 0.9em;
        background: @hh_bgc;
        position: absolute;
        bottom: 50%;
        left: 50%;
        margin: 0 0 -0.8em -0.4em;
        box-shadow: @hh_bgc 0 0 2px;
        transform-origin: 0.4em 6.2em;
        transform: rotate(-25deg);
        z-index: 21;
        &:before {
            content: '';
            background: inherit;
            width: 1.8em;
            height: 0.8em;
            border-radius: 0 0 0.8em 0.8em;
            box-shadow: @hh_bgc 0 0 1px;
            position: absolute;
            top: -0.7em;
            left: -0.5em;
        }
        &:after {
            content: '';
            width: 0;
            height: 0;
            border: 0.9em solid @hh_bgc;
            border-width: 0 0.9em 2.4em 0.9em;
            border-left-color: transparent;
            border-right-color: transparent;
            position: absolute;
            top: -3.1em;
            left: -0.5em;
        }
    }
    // 分针
    .minutes_hand {
        width: 0.6em;
        height: 12.5em;
        border-radius: 0.5em;
        background: @mh_bgc;
        position: absolute;
        bottom: 50%;
        left: 50%;
        margin: 0 0 -1.5em -0.3em;
        box-shadow: @mh_bgc 0 0 2px;
        transform-origin: 0.3em 11em;
        z-index: 22;
    }
    // 秒针
    .seconds_hand {
        width: 0.2em;
        height: 14em;
        border-radius: ~'0.1em 0.1em 0 0 / 10em 10em 0 0';
        background: @sh_bgc;
        position: absolute;
        bottom: 50%;
        left: 50%;
        margin: 0 0 -2em -0.1em;
        box-shadow: rgba(0, 0, 0, 0.8) 0 0 0.2em;
        transform-origin: 0.1em 12em;
        z-index: 23;
        &:before {
            content: '';
            width: 0.6em;
            height: 3em;
            border-radius: ~'0.2em 0.2em 0.4em 0.4em / 0.2em 0.2em 2em 2em';
            box-shadow: rgba(0, 0, 0, 0.8) 0 0 0.2em;
            background: inherit;
            position: absolute;
            left: 50%;
            bottom: -3em;
            margin-left: -0.3em;
        }
        &:after {
            content: '';
            width: 1em;
            height: 1em;
            border-radius: 50%;
            background: inherit;
            position: absolute;
            left: 50%;
            bottom: 1.5em;
            margin-left: -0.5em;
        }
    }
    //中心点
    .clock_center {
        &:before {
            content: '';
            width: 1.6em;
            height: 1.6em;
            border-radius: 50%;
            position: absolute;
            top: 50%;
            left: 50%;
            margin: -0.8em 0 0 -0.8em;
            background: #121314;
            z-index: 10;
        }
        &:after {
            content: '';
            width: @clock_center;
            height: @clock_center;
            border-radius: 50%;
            position: absolute;
            top: 50%;
            left: 50%;
            margin: (-@clock_center / 2) 0 0 (-@clock_center / 2);
            border: 0.1em solid #c6c6c6;
            background: radial-gradient(
                ellipse at center,
                rgba(200, 200, 200, 0),
                rgba(190, 190, 190, 1) 90%,
                rgba(130, 130, 130, 1) 100%
            );
            z-index: 11;
        }
    }
}

// 数字时钟
//@clock_w: 时钟宽度
//@clock_fs1: 文字大小1
//@clock_fs2: 文字大小2
//@clock_bgc1: 时钟背景色1
//@clock_bgc2: 时钟背景色2
//@clock_fc: 时钟文字颜色
.mixin_digital_clock(@clock_w: 30em; @clock_fs1: 2em; @clock_fs2: 5em; @clock_bgc1:#0a2e38; @clock_bgc2:#000; @clock_fc: #daf6ff) {
    width: @clock_w;
    border-radius: 0.6em;
    padding: 1em;
    overflow: hidden;
    background: @clock_bgc1;
    background: radial-gradient(ellipse at center, @clock_bgc1 0%, @clock_bgc2 70%);
    .num {
        padding: 0.1em;
        color: @clock_fc;
        text-align: center;
        word-break: keep-all;
        letter-spacing: 0.05em;
        font-family: 'Share Tech Mono', Consolas, monaco, monospace;
        text-shadow: ~'0 0 20px #0aafe6, 0 0 20px rgb(10 175 230 / 0%)';
    }
    .digit_ymd {
        font-size: @clock_fs1;
    }
    .digit_hms {
        font-size: @clock_fs2;
    }
}

style.less

//公共文件夹根目录
@resource_path: '../resource';
// 组件扩展
@import '@{resource_path}/mixin_clock';

//圆形挂钟
.circle_clock {
    .mixin_basic_clock();
    display: inline-block;
    margin: 2em;
}

//方形挂钟
.squire_clock {
    .mixin_basic_clock(@clock_border: 2em; @frame_bgc1:#90bef3; @frame_bgc2:#616fad; @mm_bgc: #333;);
    display: inline-block;
    margin: 2em;
}

//数字时钟
.digital_clock {
    .mixin_digital_clock();
    margin: 2em;
}

clock.js

window.onload = function () {
  // 生成刻度
  var markWrap = $('.minute_marks');
  for (index = 0; index < 60; index++) {
    var markItem = $('<li></li>');
    markItem.css("transform", "rotate(" + index * 6 + "deg) translateY(-12.7em)");
    if (index % 5 == 0) {
      markItem.css({ "width": "0.3em", "height": "1em" });
    }
    markWrap.append(markItem);
  }

  setInterval(function () {
    var today = new Date();
    var year = today.getFullYear();
    var month = today.getMonth() + 1;
    var date = today.getDate();
    var week = "星期" + "日一二三四五六".split(/(?!\b)/)[today.getDay()];
    var hour = today.getHours();
    var minute = today.getMinutes();
    var second = today.getSeconds();
    var hournum;
    // 指针转动
    if (hour > 12) {
      hournum = ((hour - 12) + minute / 60) * 30;
    } else {
      hournum = (hour + minute / 60) * 30;
    }
    var minnum = (minute + second / 60) * 6 + second / 60;
    var sennum = second * 6;
    $('.hours_hand').css('transform', 'rotate(' + hournum + 'deg)');
    $('.minutes_hand').css('transform', 'rotate(' + minnum + 'deg)');
    $('.seconds_hand').css('transform', 'rotate(' + sennum + 'deg)');

    // 数字时钟
    function checkTime (i) {
      if (i < 10) {
        i = "0" + i;
      }
      return i;
    }
    month = checkTime(month);
    date = checkTime(date);
    hour = checkTime(hour);
    minute = checkTime(minute);
    second = checkTime(second);
    $('.digit_ymd').text(year + '/' + month + '/' + date + ' ' + week);
    $('.digit_hms').text(hour + ':' + minute + ':' + second);
  }, 1000);
}

时钟的样式还可以有更丰富的方法,比如给挂钟加个背景,8字形的数字时钟等等,可以在原有引用mixin之后再自己加样式覆盖,更多创意等待你的发现

击查看时钟特效

极简主义,程序员javascript打造极简时钟特效


对于javascript特效的学习,重要的是逻辑思路,所以这个时钟特效不是很华丽,但是功能都展现出来了,而学习javascript并不是单纯的扣代码,很多人都觉得,抠完代码,能看懂了,就算是学会了,但是,说的难听点这样的学习方式其实是自断前程的学习方法,若是一门月薪过万的技术有那么简单学习,那么怎么还会有那么多人找不到工作呢?学习javascript特效最重要的是仔细研究一个特效的思路方法,然后根据这个特效可以扩展最初其他类似功能或者更复杂的特效,才算彻底的掌握好了这方面的知识!我的头条号里面也有许多华丽的特效以及HTML5/javascript游戏,有兴趣的朋友可以去看看!文末附上本次javascript时钟的源码!

如果想要更多的企业求职加分项目,案例,学习方法可以来一下我的前端群570946165,每天都会精挑细选一个特效,项目出来详细讲解,分享!包括答疑解惑!

HTML5/javascript时钟特效源码

代码过长需要文档版源码来我的前端群570946165,已上传到群文件

头条号里有许多web前端学习视频/源码,企业常用特效/案例/项目,敬请关注!