时间--时钟篇

时间-时钟
这天是越来越冷了,人也越发的懒起来,早上起来简直要老命,下班回去也只想进被子里面,游戏都不想打了╮(﹀_﹀)╭,冷呀。。。。
好了,写个时钟来激励一下懒惰的自己吧。

旋转方式

做时钟首先要把样式给搞定,主要是围绕中心旋转的样式。
围绕中心旋转形成等分状态其实有两种做法,假设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>

  1. 让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%);`;
    }

    当然这种旋转非常的简单,但是也有一定的缺陷的,其缺点是文字什么的也一起旋转了,时钟的数字可不能一起旋转了,所以这刻度线什么的用这个简单方便,但是数字得用另一种方式。

  2. 好了万能的数学该来了,用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;`;
    }

sin和cos
其实理解起来也不难,先得到每个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), // x=r+rcos(θ)
myY = r + r*Math.sin(angle); // y=r+rsin(θ)
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,一个简单的时钟就完成了。

本文代码地址:链接