这天是越来越冷了,人也越发的懒起来,早上起来简直要老命,下班回去也只想进被子里面,游戏都不想打了╮(﹀_﹀)╭,冷呀。。。。
好了,写个时钟来激励一下懒惰的自己吧。
旋转方式
做时钟首先要把样式给搞定,主要是围绕中心旋转的样式。
围绕中心旋转形成等分状态其实有两种做法,假设html样式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <ul class="pox"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> <li>10</li> <li>11</li> <li>12</li> </ul>
|
让li全部定位到pox中心,用css3的旋转rotate让其围绕中心旋转角度,再配合translate偏移,给它一个x轴的偏移量,就变成了围绕中心旋转的样式了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| .box ul{ width: 200px; height: 200px; border-radius: 50%; border:1px solid red; position: relative; display: inline-block; margin: 100px; } .box li{ width: 50px; height:50px; border:1px solid red; border-radius: 50%; line-height: 48px; text-align: center; position: absolute; top: 50%; left:50%; margin: -25px 0 0 -25px; transform-origin:50% 50%; } var lists = document.querySelectorAll(".box .pox li"); for(var i=0;i<lists.length;i++){ lists[i].style.cssText = `transform: rotate(${i*30}deg) translate(98px, -50%);`; }
|
当然这种旋转非常的简单,但是也有一定的缺陷的,其缺点是文字什么的也一起旋转了,时钟的数字可不能一起旋转了,所以这刻度线什么的用这个简单方便,但是数字得用另一种方式。
- 好了万能的数学该来了,用sin和cos实现,我们把父元素所占的空间当成一个坐标轴,其宽的一半当成半径画个圆,如
r = 父元素.offsetHeight/2
,其中心坐标点就是(r,r),1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <ul class="pox2"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> <li>10</li> <li>11</li> <li>12</li> </ul> var lists2 = document.querySelectorAll(".box .pox2 li"); for(var j=0;j<lists2.length;j++){ var r = lists2[0].parentNode.offsetHeight/2, angle = j*30/180*Math.PI; x = r + r*Math.cos(angle); y = r + r*Math.sin(angle); lists2[j].style.cssText = `top:${y}px;left:${x}px;`; }
|
其实理解起来也不难,先得到每个li的弧度值,然后根据三角函数计算出li的在坐标轴中的坐标,x轴的坐标为r+r*cosθ
,y轴的坐标为r+r*sinθ
,这里有点小知识,js的象限是顺时针开始的,初始0度是从时钟的三点方向开始的,和数学的是反着来的,当然你可能不理解,我的图也有点挫,应该画右下角的,你把右下角当成第一象限来理解要好一点,自己画一遍就什么都有了。
好了,准备就绪,开始画时钟了,html结构如下。
1 2 3 4 5 6 7 8 9 10 11 12
| <div class="clock"> <ul class="line-min"></ul> <ul class="line-hour"> </ul> <ol class="number"></ol> <ul class="pointer"> <li class="hour"></li> <li class="min"></li> <li class="sec"></li> <li class="circle"></li> </ul> </div>
|
初始表盘css:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| *{ margin: 0; padding: 0; } ol,ul { margin: 0; padding: 0; list-style: none; } .clock { position: relative; width: 200px; height: 200px; border-radius: 100%; background-color: #292a38; margin: 50px auto; } .pointer li.circle { position: absolute; top: 50%; left: 50%; transform-origin: left center; background: #fff; width: 10px; height: 10px; border-radius: 100%; margin-top: -5px; margin-left: -5px; } .pointer li { position: absolute; top: 50%; left: 50%; transform-origin: left center; background: #fff; } .pointer li.hour { width: 45px; height: 3px; margin-top: -1px; } .pointer li.min { width: 60px; height: 2px; margin-top: -1px; } .pointer li.sec { width: 80px; height: 1px; margin-top: -1px; }
|
.line-min
是分刻度线,.line-hour
是小时刻度线,.number
是1-12的时间数字,.hour
是时针,.min
分针,.sec
秒针,.circle
中心圆点。
这次我们用ES6的class来写吧,先定义一个Time类,后面的方法都是写在Time类里面的,Time里面的构造方法constructor调用初始化函数init,init就先空着吧。
1 2 3 4 5 6 7 8
| var time = class Time{ constructor(){ this.init(); } init(){ } }
|
为了写得方便点,我们先建立两个工具函数,addcss函数是向传入的dom中添加css样式,getclass是根据传入的css获取dom节点:
1 2 3 4 5 6
| addcss(obj,mycss){ obj.style.cssText = mycss; } getclass(cls){ return document.querySelector(cls); }
|
我们先来画时钟刻度线,用第一种旋转方式:
1 2 3 4 5 6 7 8
| drawLines(wrap, total, translateX){ var gap = 360/total; for(var i=0;i<total;i++){ var li = document.createElement('li'); this.addcss(li,`transform:rotate(${i*gap}deg) translate(${translateX}px,-50%)`); wrap.append(li); } }
|
补上刻度css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .line-hour li, .line-min li { position: absolute; left: 50%; top: 50%; transform-origin: left center; background-color: #fff; } .line-hour li { width: 10px; height: 2px; } .line-min li { width: 5px; height: 2px; }
|
我们用drawLines函数绘制刻度线,分别传入wrap(父节点),total(时钟的刻度个数,时针12个,分针是60个),translateX(第一种旋转方式x轴的偏移量),这个函数生成了刻度线li,并且添加css样式后放到了传入的父节点中。
然后我们再绘制时钟数字,当然数字可不能旋转,所以得用第二种旋转方式:
由于初始度数是0,刚好是3点,所以3对应的弧度应该是0,6点是π/2,9点是π,12点是3π/2,通过传入的数字得到其对应的弧度如下:
1 2 3 4 5 6 7 8 9 10
| 时钟 角度 弧度 sin cos // 3:x:2r,y:r; 0 0 sin 0 cos 1 // 6:x:r,y:2r; 90 π/2 sin 1 cos 0 // 9:x:0,y:r; 180 π sin 0 cos -1 // 12:x:r,y:0; 270 3π/2 sin -1 cos 0 我们把弧度全部除以π得到 // 3 0; = 3-3 = 0/6 (num-3)/6 * π // 6 1/2; = 6-3 = 3/6 // 9 1; = 9-3 = 6/6 // 12 3/2; = 12-3 = 9/6
|
我们可以推算出公式为(num-3)/6 * π
,故弧度为 = (i-3)/6*Math.PI
;
1 2 3 4 5 6 7 8 9 10 11
| drawNumbers(wrap){ var r = wrap.offsetHeight/2; var child = ''; for(var i=1;i<=12;i++){ var angle = (i-3)/6*Math.PI; var myX = r + r*Math.cos(angle), myY = r + r*Math.sin(angle); child+=`<li style="left:${myX}px;top:${myY}px;">${i}</li>`; } wrap.innerHTML = child; }
|
数字css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .number { position: absolute; height: 140px; width: 140px; left: 50%; top: 50%; transform: translate(-50%, -50%); font-family: 'Microsoft Yahei'; font-size: 15px; color: #fff; } .number li { position: absolute; transform: translate(-50%, -50%); }
|
这样数字函数也完成了,接下来我们在init初始化函数里面调用,new time(),让其生成出来:
1 2 3 4 5 6
| init(){ this.drawLines(this.getclass('.line-min'), 60, 85); this.drawLines(this.getclass('.line-hour'), 12, 80); this.drawNumbers(this.getclass('.number')); } new time();
|
我们就得到了时钟的大致样式了,只是时钟的针还不会走:
最后我们写个move函数让时钟开始走动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| move(){ var h = this.getclass('.hour'), m = this.getclass('.min'), s = this.getclass('.sec'); setInterval(function(){ var now = new Date(), hour = now.getHours(), min = now.getMinutes(), sec = now.getSeconds(); var hangle = 30*hour + 0.5*min -90, mangle = 6*min + 0.1*sec -90, sangle = 6*sec -90; this.addcss(h,`transform:rotate(${hangle}deg)`); this.addcss(m,`transform:rotate(${mangle}deg)`); this.addcss(s,`transform:rotate(${sangle}deg)`); }.bind(this),1000); }
|
其余的可能没啥问题,只有指针的角度计算这里可能要说一下,
小时是12个小时,所以1个小时=360°/12=30°,当然还要加上分钟的偏移,一个小时60分钟,60分钟就要偏移30°,所以1分钟为0.5°,故小时=30*小时+0.5*分钟
,当然也可以计算秒的,但是太小了(1/120),这里就忽略不计了,分针和秒针同上。由于初始位置是3点那里,以3点为基准,故3点旋转角度为0°,1点为-60°,6点为90°,故所有角度应该减去90°再进行旋转。init()里面调用:
1 2 3 4 5 6
| init(){ this.drawLines(this.getclass('.line-min'), 60, 85); this.drawLines(this.getclass('.line-hour'), 12, 80); this.drawNumbers(this.getclass('.number')); this.move(); }
|
ok,一个简单的时钟就完成了。
本文代码地址:链接