web时钟
这天是越来越冷了,人也越发的懒起来,早上起来简直要老命,下班回去也只想进被子里面,游戏都不想打了╮(﹀_﹀)╭,冷呀。。。。
好了,写个时钟来激励一下懒惰的自己吧。
旋转方式
做时钟首先要把样式给搞定,主要是围绕中心旋转的样式。
围绕中心旋转形成等分状态其实有两种做法,假设html样式如下:
<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轴的偏移量,就变成了围绕中心旋转的样式了:
.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),
<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结构如下。
<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:
*{
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就先空着吧。
var time = class Time{
constructor(){
this.init();
}
init(){
}
}
为了写得方便点,我们先建立两个工具函数,addcss函数是向传入的dom中添加css样式,getclass是根据传入的css获取dom节点:
addcss(obj,mycss){
obj.style.cssText = mycss;
}
getclass(cls){
return document.querySelector(cls);
}
我们先来画时钟刻度线,用第一种旋转方式:
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
.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,通过传入的数字得到其对应的弧度如下:
时钟 角度 弧度 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
;
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
.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(),让其生成出来:
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函数让时钟开始走动
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()里面调用:
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,一个简单的时钟就完成了。
123