时间–时钟篇

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

旋转方式

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

当然这种旋转非常的简单,但是也有一定的缺陷的,其缺点是文字什么的也一起旋转了,时钟的数字可不能一起旋转了,所以这刻度线什么的用这个简单方便,但是数字得用另一种方式。
2. 好了万能的数学该来了,用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,一个简单的时钟就完成了。

本文示例:链接1 链接2
本文代码地址:链接

您也可能喜欢...

发表评论

电子邮件地址不会被公开。 必填项已用*标注