动态改变CSS关键帧值来创建时钟



这是我第一次尝试关键帧动画。我之前因为无法通过JavaScript动态更改硬编码的CSS值而感到厌烦。

我在谷歌上搜索了一下,发现它"可以"完成,但需要大量繁琐的工作来查找,删除和替换部分或整个样式表。

无论如何,这是我的努力。这个特定脚本的最终目标是时钟指针的弹跳。我已经可以用过渡和三次贝塞尔来做这个但只能得到一个弹跳。我在使用各种js库等中看到过这种效果,但你知道它是怎么回事-你喜欢自己滚动。

我的问题是——我下面的方法有什么明显的错误吗?别管那些琐事,这只是个测试。我想看的是我的GenerateKeyFrames()函数和调用它的两个方法。

谢谢你提供的信息。

    var d = document;
    var incr = 1;
    var step = -6; //Initial start pos.
    var coreCss = 'display: block;position: absolute;'
               +'left: 100px;top: 10px;height: 95px;'
               +'width: 4px;background-color: #000;'
               +'transform-origin: center bottom;';
    var initialAniCss = 'animation: reGen'+incr+' 1s 1 forwards;';
    coreCss += initialAniCss;
    var elementToAnimate = d.createElement('div');
    elementToAnimate.setAttribute('style', coreCss);
    d.body.appendChild(elementToAnimate);
    function GenerateKeyFrames() {
    /* Remove previous 'tmpSheet' stylesheet */
    var currSheet = (d.getElementById('tmpSheet'));
    if (currSheet) {
        //currSheet.parentNode.removeChild(currSheet);// Doesn't seem as smooth as other 2 below!
        //currSheet.remove(); - Not IE, shame.
        currSheet.outerHTML = '';
    }
    /* Movement in degrees */
    var p1 = step;
    var p2 = step+6;
    var p3 = step+4;
    var p4 = step+6;
    var p5 = step+5; 
    var p6 = step+6;
    /* Create new keyframe. Must have new name! Adding an incrementing var to name does ok */
    var frames = '@keyframes reGen'+incr+' { '
    +'0% { transform: rotate('+p1+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'25% { transform: rotate('+p2+'deg) translateZ(0); animation-timing-function: ease-out;}'
    +'45% { transform: rotate('+p3+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'65% { transform: rotate('+p4+'deg) translateZ(0); animation-timing-function: ease-out;}' 
    +'75% { transform: rotate('+p5+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'85%,100% { transform: rotate('+p6+'deg) translateZ(0);animation-timing-function: ease-out;}}';
    /* Create new tmpSheet style sheet to head */
    var s = document.createElement( 'style' );
    s.setAttribute("id", "tmpSheet");
    s.innerHTML = frames;
    document.getElementsByTagName('head')[0].appendChild(s);
    /* Put it all together and it's ready to go */ 
    var newAni = 'animation: reGen'+incr+' 1s 1 forwards;';
    coreCss += newAni;
    elementToAnimate.setAttribute('style', coreCss);
    d.body.appendChild(elementToAnimate);
}
GenerateKeyFrames();
/* Can be called on animation end - or timed function rep().
elementToAnimate.addEventListener("animationend",function(e) {
    incr++;
    step += 6;
    elementToAnimate.removeAttribute("style");
    GenerateKeyFrames();
    },false);
*/
function rep() {
    incr++;
    step += 6;
    elementToAnimate.removeAttribute("style");
    GenerateKeyFrames();
setTimeout(rep, 2000);
}
rep();

我真的不喜欢用唯一名称动态插入所有关键帧的想法。如果我这样做并尝试使用CSS关键帧动画,我会创建两个动画,一个提供你的"双重反弹"效果,另一个围绕中心旋转包装器。

使用HTML和CSS,你几乎可以创建一个完整的工作时钟,尽管你没有任何方法在没有JavaScript的情况下在正确的时间启动它。

这是一个有趣的练习,我能够使用关键帧动画和一点点JavaScript来重新创建整个时钟效果,以确定动画的开始时间,并提供负animation-delay以将动画偏移到适当的时间框架。

时间可以走动一点,但真的没有你想象的那么多。我让动画在Chrome、FF和IE中运行一整晚,然后让我的电脑进入睡眠状态,9个小时后,时钟仍然保持着完美的时间。然而,当我让它在手机的背景标签中运行一整夜时,早上的时候,时钟完全坏了。不过,考虑到整个目的是如何在网页上显示时钟,页面不太可能停留足够长的时间,以至于时钟明显消失。

总之,下面是代码片段:

window.addEventListener("load", function() {
  var now = new Date();
  var secondsDelay = now.getSeconds();
  var minutesDelay = now.getMinutes() * 60 + secondsDelay;
  var hoursDelay = (now.getHours() % 12) * 3600 + minutesDelay;
  var minuteHand = document.querySelector(".minute .hand");
  var minuteWrapper = document.querySelector(".minute");
  var secondWrapper = document.querySelector(".second");
  var hourWrapper = document.querySelector(".hour");
  //set animation offsets with negative delay
  minuteHand.style.animation = "minuteTick 60s -" + secondsDelay + "s infinite";
  secondWrapper.style.animation = "rotateHolder steps(60) 60s -" + secondsDelay + "s infinite";
  minuteWrapper.style.animation = "rotateHolder steps(60) 3600s -" + minutesDelay + "s infinite";
  hourWrapper.style.animation = "rotateHolder steps(43200) 43200s -" + hoursDelay + "s infinite";
  //start running
  document.querySelector(".clock").classList.add("running");
});
.clock {
  width: 200px;
  height: 200px;
  background-color: gray;
  border-radius: 50%;
}
.sectionWrapper {
  width: 200px;
  height: 200px;
  position: absolute;
  transform: rotate(0deg);
}
.clock.running .second {
  animation: rotateHolder 60s steps(60) infinite;
}
.clock.running .second .hand {
  animation: secondTick 1s 0s infinite;
}
.clock.running .minute {
  animation: rotateHolder 3600s steps(60) infinite;
}
.clock.running .minute .hand {
  animation: minuteTick 60s 0s infinite;
}
.clock.running .hour {
  animation: rotateHolder 43200s steps(43200) infinite;
}
.hand {
  display: block;
  position: absolute;
  background-color: #000;
  transform-origin: center bottom;
}
.second .hand {
  left: 99px;
  top: 5px;
  height: 95px;
  width: 2px;
  background-color: red;
}
.minute .hand {
  left: 98px;
  top: 15px;
  height: 85px;
  width: 4px;
}
.hour .hand {
  left: 97px;
  top: 45px;
  height: 55px;
  width: 6px;
}
@keyframes secondTick {
  0% { transform: rotate(0deg); animation-timing-function: ease-in; }
  25% { transform: rotate(6deg); animation-timing-function: ease-out; }
  45% { transform: rotate(4deg); animation-timing-function: ease-in; }
  65% { transform: rotate(6deg); animation-timing-function: ease-out; } 
  75% { transform: rotate(5deg); animation-timing-function: ease-in; }
  85%,100% { transform: rotate(6deg);animation-timing-function: ease-out; }				
}
@keyframes minuteTick {
  0%,98.3% { transform: rotate(0deg); animation-timing-function: ease-in; }
  98.8% { transform: rotate(6deg); animation-timing-function: ease-out; }
  99.1% { transform: rotate(4deg); animation-timing-function: ease-in; }
  99.4% { transform: rotate(6deg); animation-timing-function: ease-out; } 
  99.6% { transform: rotate(5deg); animation-timing-function: ease-in; }
  99.8%,100% { transform: rotate(6deg);animation-timing-function: ease-out; }				
}
@keyframes rotateHolder {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
<div class="clock">
  <div class="hour sectionWrapper">
    <div class="hand"></div>
  </div>
  <div class="minute sectionWrapper">
    <div class="hand"></div>
  </div>
  <div class="second sectionWrapper">
    <div class="hand"></div>
  </div>
</div>

完成时钟

(function () {
    /* Station Style Clock - kurt.grigg@yahoo.co.uk */
    /* ^^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^^ */
    var clockSize = 400;
    var clockColour = 'rgb(255,255,255)';
    var secHandColour = 'rgb(255,255,255)';
    /* ^^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^^^ */
    var d = document;
    var mcon = [];
    var mrkrs = [];
    var e = 360/60;
    var degr = -6;
    var mls = 100;
    var prev = performance.now();
    var radi = Math.PI / 180;
    var offs = 90 * radi;
    var rndId = 'id'+Math.random() * 1;
    var secSpan = '.8s';
    var minSpan = '1s';
    var houSpan = '1s';
    var secIncr = 0;
    var minIncr = 0;
    var houIncr = 0;
    var secDeg, minDeg, houDeg, preSec, preMin, preHou;
    var idx = d.getElementsByTagName('div').length;
    var shdcol = 'rgba(0,0,0,0.6)';
    var eiatf = ' translateZ(0); animation-timing-function: ease-in';
    var eoatf = ' translateZ(0); animation-timing-function: ease-out';
    d.write('<div id = "'+rndId+'" style="display:inline-block;line-height:0px;"></div>');
    function xy (a) {
        return (a * (clockSize * 2) / 100);
    }
    function shdw(s, h) {
        var depth = xy(h);
        var angle = s * radi;
        var vsa = depth * Math.cos(angle);
        var hsa = depth * Math.sin(angle);
        return {vsa:vsa, hsa:hsa}
    }
    var dial = d.createElement('div');
    dial.setAttribute('style', 'display: inline-block;'
        +'position: relative;'
        +'height: '+xy(100)+'px;'
        +'width: '+xy(100)+'px;'
        +'background-color:transparent;'
        +'border-radius: 50%;'
        +'margin: -'+xy(24)+'px -'+xy(24)+'px -'+xy(24)+'px -'+xy(24)+'px;');
    d.getElementById(rndId).style.transform = 'scale3d(.5,.5,1)';
    d.getElementById(rndId).appendChild(dial); 
    for (var i = 0; i < 60; i++) {
        var mky = shdw(i * 6, 0.5).vsa;
        var mkx = shdw(i * 6, 0.5).hsa;
        var len = (i % 5) ? 4 : 8;
        var wid = (i % 5) ? .8 : 4;
        mcon[i] = d.createElement('div');
        mcon[i].setAttribute('style', 'display: block;'
            +'position: absolute;'
            +'width: '+xy(4)+'px;'
            +'height: '+xy(8)+'px;'
            +'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
            +'font-size: 0px;line-height: 0px;padding: 0;'
            +'color: '+clockColour+';');
        mrkrs[i] = d.createElement('div');
        mrkrs[i].setAttribute('style', 'display: block;'
            +'position: absolute;'
            +'width: '+xy(wid)+'px;'
            +'height: '+xy(len)+'px;'
            +'margin: auto; top: 0;left: 0;right: 0;'
            +'font-size: 0px;line-height: 0px;padding: 0;'
            +'box-shadow:'+mkx+'px '+mky+'px 0px 0px rgba(0,0,0,0.7);'
            +'background-color:'+clockColour+';');
        mcon[i].appendChild(mrkrs[i]);
        dial.appendChild(mcon[i]);
        degr += 6;
        mcon[i].style.top = xy(0) + xy(86) * Math.sin(-offs + e * i * radi) + 'px';
        mcon[i].style.left= xy(0) + xy(86) * Math.cos(-offs + e * i * radi) + 'px';
        mcon[i].style.transform = 'rotate(' + (degr) + 'deg)';
        mcon[i].style.transformOrigin = 'center center';
    }
    /* Generic container div for all hands */
    var handContainers = 'display: block;'
        +'position: absolute;'
        +'height: '+xy(100)+'px;'
        +'width: '+xy(16)+'px;'
        +'font-size: 0px; line-height: 0px; padding: 0;'
        +'margin: auto; top: 0;bottom: 0; left: 0; right: 0;'
        +'transform-origin: center center;';
    
    /* Hour hand CSS */
    var houClone = handContainers;
    var houHand = d.createElement('div');
    houHand.setAttribute('style', houClone);
    
    dial.appendChild(houHand);
    var hh = d.createElement('div');
    hh.setAttribute('style', 'display: block;'
        +'position: absolute;'
        +'height: '+xy(48)+'px;'
        +'width: '+xy(5)+'px;'
        +'top: '+xy(15)+'px;'
        +'margin: auto; left: 0; right: 0;'
        +'outline: 1px solid transparent;'
        +'background-color: '+clockColour+';');
    houHand.appendChild(hh);
    var houShad = houHand.cloneNode(true);
    houShad.childNodes[0].style.backgroundColor = shdcol;
    /* Minute hand CSS */
    var minClone = handContainers;
    var minHand = d.createElement('div');
    minHand.setAttribute('style', minClone);
    dial.appendChild(minHand);
    var mh = d.createElement('div');
    mh.setAttribute('style', 'display:block;'
        +'position: absolute;'
        +'height: '+xy(58)+'px;'
        +'width: '+xy(3)+'px;'
        +'top: '+xy(5)+'px;'
        +'margin: auto; left: 0; right: 0;'
        +'outline: 1px solid transparent;'
        +'background-color: '+clockColour+';');
    minHand.appendChild(mh);
    var minShad = minHand.cloneNode(true);
    minShad.childNodes[0].style.backgroundColor = shdcol;
    /* Seconds hand CSS */
    var secClone = handContainers;
    var secHand = d.createElement('div');
    secHand.setAttribute('style', secClone);
    dial.appendChild(secHand);
    var sh = d.createElement('div');
    var svgsec = '<svg height="'+xy(100)+'" width="'+xy(16)+'">'
    +'<g>'
    +'<rect id="hd" x="'+xy(7.45)+'" y="'+xy(3)+'" width="'+xy(1)+'" height="'+xy(60)+'" stroke-width="0" fill="'+secHandColour+'"/>'
    +'<circle id="cw" cx="50%" cy="'+xy(67)+'" r="'+xy(4)+'" stroke-width="0" stroke="'+secHandColour+'" fill="'+secHandColour+'"/>'
    +'</g>'
    +'</svg>';
    sh.innerHTML = svgsec;
    secHand.appendChild(sh);
    var secShad = secHand.cloneNode(true);
    var newColor = '"'+shdcol+'"';
    var clnshd = svgsec.split(secHandColour).join("");
    clnshd = clnshd.replace(/""/g, newColor);
    secShad.innerHTML = clnshd;
    var nut = d.createElement('div');
    nut.setAttribute('style', 'display: block;'
        +'position: absolute;'
        +'height: '+xy(4)+'px;'
        +'width: '+xy(4)+'px;'
        +'border-radius: 50%;'
        +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
        +'background-color: '+secHandColour+';'
        +'box-shadow:'+xy(0)+'px '+xy(0.5)+'px 0px 0px rgba(0,0,0,0.7);'
        +'z-index: 105;');
    dial.appendChild(nut);
    function houKeyFrames() {
        var houSheet = (d.getElementById('tmphouSheet'+idx));
        if (houSheet) {
            houSheet.parentNode.removeChild(houSheet);
        }
        houClone = handContainers;
 
        var p1 = houDeg;
        var p2 = houDeg+1;
        var p3 = houDeg+0.4;
        var p4 = houDeg+1;
        var p5 = houDeg+0.5; 
        var p6 = houDeg+1; 
        var houframes = '@keyframes hou'+idx+'gen'+houIncr+' { '
        +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
        +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
        +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
        +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
        +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
        +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
        var hs = document.createElement( 'style' );
        hs.setAttribute('id', 'tmphouSheet'+idx);
        hs.innerHTML = houframes;
        d.getElementsByTagName('head')[0].appendChild(hs);
        var houAni = 'animation: hou'+idx+'gen'+houIncr+' '+houSpan+' 1 forwards;';
        houClone += houAni;
        houHand.setAttribute('style', houClone);
        houHand.style.zIndex = 100;
        dial.appendChild(houHand);
        houShad.setAttribute('style', houClone);
        houShad.style.top = xy(2.5)+'px';
        houShad.style.zIndex = 99;
        dial.appendChild(houShad);
    }
    function minKeyFrames() {
        var minSheet = (d.getElementById('tmpMinSheet'+idx));
        if (minSheet) {
            minSheet.parentNode.removeChild(minSheet);
        }
        minClone = handContainers;
        var p1 = minDeg;
        var p2 = minDeg+6;
        var p3 = minDeg+4;
        var p4 = minDeg+6;
        var p5 = minDeg+5; 
        var p6 = minDeg+6;
        var minframes = '@keyframes min'+idx+'gen'+minIncr+' { '
        +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
        +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
        +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
        +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
        +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
        +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
        var ms = document.createElement( 'style' );
        ms.setAttribute('id', 'tmpMinSheet'+idx);
        ms.innerHTML = minframes;
        d.getElementsByTagName('head')[0].appendChild(ms);
        var minAni = 'animation: min'+idx+'gen'+minIncr+' '+minSpan+' 1 forwards;';
        minClone += minAni;
        minHand.setAttribute('style', minClone);
        minHand.style.zIndex = 102;
        dial.appendChild(minHand);
        minShad.setAttribute('style', minClone);
        minShad.style.top = xy(3)+'px';
        minShad.style.zIndex = 101;
        dial.appendChild(minShad);
    }
    function secKeyFrames() {
        var secSheet = (d.getElementById('tmpSecSheet'+idx));
        if (secSheet) {
            secSheet.parentNode.removeChild(secSheet);
        }
        
        secClone = handContainers;
 
        var p1 = secDeg;
        var p2 = secDeg+6;
        var p3 = secDeg+4;
        var p4 = secDeg+6;
        var p5 = secDeg+5; 
        var p6 = secDeg+6; 
        var secframes = '@keyframes sec'+idx+'gen'+secIncr+' { '
        +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
        +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
        +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
        +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
        +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
        +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
        var ss = document.createElement( 'style' );
        ss.setAttribute('id', 'tmpSecSheet'+idx);
        ss.innerHTML = secframes;
        document.getElementsByTagName('head')[0].appendChild(ss);
        var secAni = 'animation: sec'+idx+'gen'+secIncr+' '+secSpan+' 1 forwards;';
        secClone += secAni;
        secHand.setAttribute('style', secClone);
        secHand.style.zIndex = 104;
        dial.appendChild(secHand);
        secShad.setAttribute('style', secClone);
        secShad.style.top = xy(3.5)+'px';
        secShad.style.zIndex = 103;
        dial.appendChild(secShad);
    }
    function clock() {
        var x = new Date();
        var seconds = x.getSeconds();
        var minutes = x.getMinutes();
        var hours = (x.getHours() * 30) + (x.getMinutes() / 2);
        
        if (seconds !== preSec) {
            secIncr++;
            secDeg = (seconds-1) * 6;
            secHand.removeAttribute('style');
            secKeyFrames();
            if (secIncr > 59) {
                secIncr = 0;
            }
        }
        if (minutes !== preMin) {
            minIncr++;
            minDeg = (minutes-1) * 6;
            minHand.removeAttribute('style');
            minKeyFrames();
            if (minIncr > 59) {
                minIncr = 0;
            }
        }
        if (hours !== preHou) {
            houIncr++;
            houDeg = (hours-1) * 1;
            houHand.removeAttribute('style');
            houKeyFrames();
            if (houIncr > 59) {
                houIncr = 0;
            }  
        }
        preSec = seconds;
        preMin = minutes;
        preHou = hours;
    }
    function cyc() {
        var pres = performance.now(); 
        if ((pres - prev) > mls) {
            clock();
            prev = performance.now();
        }
        window.requestAnimationFrame(cyc);
    } 
    window.addEventListener('load', cyc, false);
})();
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Clock</title>
    <style type="text/css">
        html {
            height: 100%;
        }
        
        body {
            background-color: #ffff00;
            text-align: center;
        }
    </style>
</head>
<body>
  
  
  
</body>
</html>  

这看起来太复杂了。每当我处理复杂的动画时,我都会使用GSAP。这是我做的一个简单的演示。它使用基本的JQuery和GSAP动画引擎TweenMax。

您可以通过GSAP的轻松可视化工具轻松地调整轻松度

$(document).ready(function() {
  var clock = $('.clock'); // clock container
  var arm = $('.arm'); // seconds arm
  var log = $('.log'); // log beneath clock
  var position =  90; // starting position at 0 seconds
  var time = 0; 
setInterval(function(){
  position += 6; // 360 / 60 = +6 deg per second
  time ++; 
  TweenLite.to(arm, 0.3, {rotation:position, transformOrigin:"right bottom", ease: Back.easeOut.config(2), y: 0 });
  log.text(time + " seconds and " + position +  " degs");
 }, 1000);
});

只关注代码,我觉得它很好。

我唯一关心的是

/* Put it all together and it's ready to go */ 
var newAni = 'animation: reGen'+incr+' 1s 1 forwards;';
coreCss += newAni;

请注意,coreCss最终会有很多动画(在开发工具中验证)

你应该把它清除。

但是考虑到动画是通过forward 来设置位置的,这可能会产生问题…

如果是这种情况,可能只玩2个动画??

如果你想要关于我如何获得这种效果的建议,我会设置2个嵌套元素,一个是你拥有的精心制作的关键帧,并每秒运行。另一幅画了60圈

BBC时钟的例子

(function () {
/* The BBC Analogue Clock - kurt.grigg@yahoo.co.uk */
/* ^^^^^^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^^^^^^ */
var clockSize = 300;
var dialcol = 'rgba(0,0,255,0.9)';
var handcol = 'rgb(230,230,230)';
/* ^^^^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^^^^^^ */
var d = document;
var mrkrs = [];
var e = (360 / 12);
var degr = 0;
var mls = 100;
var prev = performance.now();
var radi = Math.PI / 180;
var offs = 60 * radi;
var rndId = 'id'+Math.random() * 1;
var sSpan = '.9s';
var mSpan = '1s';
var hSpan = '1s';
var sIncr = 0;
var mIncr = 0;
var hIncr = 0;
var sDeg, mDeg, hDeg, sPre, mPre, hPre;
var idx = d.getElementsByTagName('div').length;
d.write('<div id = "'+rndId+'" style="display:inline-block;line-height:0px;"></div>');
function xy(a) {
    return (a * clockSize / 100);
}
var dial = d.createElement('div');
dial.setAttribute('style', 'display: inline-block;'
    +'position: relative;'
    +'height: '+clockSize+'px;'
    +'width: '+clockSize+'px;'
    +'margin: 0px;padding: 0px;'
    +'border-radius: 5%;z-index: 1;'
    +'background-color: '+dialcol+';');
d.getElementById(rndId).appendChild(dial);
for (var i = 0; i < 12; i++) {
    var incr = xy(2.0) + (i * xy(0.2));
    mrkrs[i] = d.createElement('div');
    mrkrs[i].setAttribute('style', 'display: block;'
        +'position: absolute;'
        +'width: '+xy(14)+'px;'
        +'height: '+xy(14)+'px;'
        +'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
        +'font-size: 0px;line-height: 0px;padding: 0;'
        +'text-align: center !important;'
        +'background-color: transparent;');
    mrkrs[i].innerHTML = '<div style = "display: inline-block;'
    +'position: relative;width: '+incr+'px;height: '+xy(14)+'px;'
    +'font-size: 0px;background-color:'+handcol+';'
    +'margin-right: '+xy(0.6)+'px;"></div>'
    +'<div style = "display:inline-block;position: relative;'
    +'width: '+incr+'px;height: '+xy(14)+'px;font-size: 0px;'
    +'margin-left: '+xy(0.6)+'px;'
    +'background-color:'+handcol+';"></div>';
    dial.appendChild(mrkrs[i]);
    degr += 30;
    mrkrs[i].style.top = xy(0) + xy(77) * 
        Math.sin(-offs + e * i * radi) + 'px';
    mrkrs[i].style.left= xy(0) + xy(77) * 
        Math.cos(-offs + e * i * radi) + 'px';
    mrkrs[i].style.transform = 'rotate(' + (degr) + 'deg)';
    mrkrs[i].style.transformOrigin = 'center center';
}
/* Hour CSS */
var hCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(56)+'px;'
    +'width: '+xy(6)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0;bottom: 0; left: 0; right: 0;'
    +'transform-origin: center center 0;'
    +'z-index: 2;';
var hClone = hCss;
var houHand = d.createElement('div');
houHand.setAttribute('style', hClone);
dial.appendChild(houHand);
var hh = d.createElement('div');
hh.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(21)+'px;'
    +'width: '+xy(6)+'px;' 
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0; left: 0; right: 0;'
    +'background-color: '+handcol+';');
houHand.appendChild(hh);
/* Minute CSS */
var mCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(86)+'px;'
    +'width: '+xy(4)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0; bottom: 0; left: 0; right: 0;'
    +'transform-origin: center center;'
    +'z-index: 3;';
var mClone = mCss;
var minHand = d.createElement('div');
minHand.setAttribute('style', mClone);
dial.appendChild(minHand);
var mh = d.createElement('div');
mh.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(36)+'px;'
    +'width: '+xy(4)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0; left: 0; right: 0;'
    +'background-color: '+handcol+';');
minHand.appendChild(mh);
/* Second CSS */
var sCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(90)+'px;'
    +'width: '+xy(2)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0;bottom: 0; left: 0; right: 0;'
    +'transform-origin: center center;'
    +'z-index: 4;';
var sClone = sCss;
var secHand = d.createElement('div');
secHand.setAttribute('style', sClone);
dial.appendChild(secHand);
var sh = d.createElement('div');
sh.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(39)+'px;'
    +'width: '+xy(2)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0; left: 0; right: 0;'
    +'background-color: '+handcol+';');
secHand.appendChild(sh);
var sectail = d.createElement('div');
sectail.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(12)+'px;'
    +'width: '+xy(2)+'px;'
    +'margin: auto; left: 0; right: 0;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'top: '+xy(52)+'px;'
    +'background-color: '+handcol+';');
secHand.appendChild(sectail);
/* Centre nut & optional glass front CSS */
var nut = d.createElement('div');
nut.setAttribute('style', 'display: inline-block;'
    +'position: absolute;'
    +'height: '+xy(10)+'px;'
    +'width: '+xy(10)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'border: '+xy(3)+'px solid '+handcol+';'
    +'border-radius: 50%;'
    +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
    +'background-color: transparent;'
    +'z-index: 5;');
dial.appendChild(nut);
var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
    +'height:'+clockSize+'px;'
    +'width: '+clockSize+'px;'
    +'border-radius:'+xy(5)+'px;'
    +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
    +'z-index: 6;box-shadow:'
    +'0 '+xy(1)+'px '+xy(1)+'px rgba(0,0,0,0.5),'
    +'inset 0 '+xy(1)+'px rgba(255,255,255,0.3),'
    +'inset 0 '+xy(10)+'px rgba(255,255,255,0.2),'
    +'inset 0 '+xy(10)+'px '+xy(20)+'px rgba(255,255,255,0.25),'
    +'inset 0 -'+xy(15)+'px '+xy(30)+'px rgba(0,0,0,0.3);');
dial.appendChild(glass);
var eiatf = 'translateZ(0); animation-timing-function: ease-in';
var eoatf = 'translateZ(0); animation-timing-function: ease-out';
function secKeyFrames() {
    var secSheet = (d.getElementById('tmpSecSheet'+idx));
    if (secSheet) {
        secSheet.outerHTML = '';
    }
    
    sClone = sCss;
 
    var p1 = sDeg;
    var p2 = sDeg+6;
    var p3 = sDeg+4;
    var p4 = sDeg+6;
    var p5 = sDeg+5; 
    var p6 = sDeg+6; 
    var secframes = '@keyframes reGen'+sIncr+' { '
    +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
    +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
    +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
    +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
    +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
    +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
    var ss = document.createElement( 'style' );
    ss.setAttribute('id', 'tmpSecSheet'+idx);
    ss.innerHTML = secframes;
    document.getElementsByTagName('head')[0].appendChild(ss);
    var secAni = 'animation: reGen'+sIncr+' '+sSpan+' 1 forwards;';
    sClone += secAni;
    secHand.setAttribute('style', sClone);
    dial.appendChild(secHand);
}
function minKeyFrames() {
    var minSheet = (d.getElementById('tmpMinSheet'+idx));
    if (minSheet) {
        minSheet.outerHTML = '';
    }
    mClone = mCss;
 
    var p1 = mDeg;
    var p2 = mDeg+6;
    var p3 = mDeg+4;
    var p4 = mDeg+6;
    var p5 = mDeg+5; 
    var p6 = mDeg+6;
    var minframes = '@keyframes minGen'+mIncr+' { '
    +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
    +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
    +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
    +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
    +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
    +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
    var ms = document.createElement( 'style' );
    ms.setAttribute('id', 'tmpMinSheet'+idx);
    ms.innerHTML = minframes;
    d.getElementsByTagName('head')[0].appendChild(ms);
    var minAni = 'animation: minGen'+mIncr+' '+mSpan+' 1 forwards;';
    mClone += minAni;
    minHand.setAttribute('style', mClone);
    dial.appendChild(minHand);
}
function houKeyFrames() {
    var houSheet = (d.getElementById('tmphouSheet'+idx));
    if (houSheet) {
        houSheet.outerHTML = '';
    }
    hClone = hCss;
 
    var p1 = hDeg;
    var p2 = hDeg+1;
    var p3 = hDeg+0.4;
    var p4 = hDeg+1;
    var p5 = hDeg+0.5; 
    var p6 = hDeg+1; 
    var houframes = '@keyframes houGen'+hIncr+' { '
    +'0% { transform: rotate('+p1+'deg) '+eiatf+';}'
    +'30% { transform: rotate('+p2+'deg) '+eoatf+';}'
    +'45% { transform: rotate('+p3+'deg) '+eiatf+';}'
    +'60% { transform: rotate('+p4+'deg) '+eoatf+';}' 
    +'70% { transform: rotate('+p5+'deg) '+eiatf+';}'
    +'80%,100% { transform: rotate('+p6+'deg) '+eoatf+';}}';
    var hs = document.createElement( 'style' );
    hs.setAttribute('id', 'tmphouSheet'+idx);
    hs.innerHTML = houframes;
    d.getElementsByTagName('head')[0].appendChild(hs);
    var houAni = 'animation: houGen'+hIncr+' '+hSpan+' 1 forwards;';
    hClone += houAni;
    houHand.setAttribute('style', hClone);
    dial.appendChild(houHand);
}
function animate() {
    var x = new Date();
    var seconds = x.getSeconds();
    var minutes = x.getMinutes();
    var hours = (x.getHours() * 30) + (x.getMinutes() / 2);
    
    if (seconds !== sPre) {
        sIncr++;
        sDeg = (seconds-1) * 6;
        secHand.removeAttribute('style');
        secKeyFrames();
        if (sIncr > 59) {
            sIncr = 0;
        }
    }
    if (minutes !== mPre) {
        mIncr++;
        mDeg = (minutes-1) * 6;
        minHand.removeAttribute('style');
        minKeyFrames();
        if (mIncr > 59) {
            mIncr = 0;
        }
    }
    if (hours !== hPre) {
        hIncr++;
        hDeg = (hours-1) * 1;
        houHand.removeAttribute('style');
        houKeyFrames();
        if (hIncr > 59) {
            hIncr = 0;
        }    
    }
    sPre = seconds;
    mPre = minutes;
    hPre = hours;
}
function cyc() {
    var pres = performance.now(); 
    if ((pres - prev) > mls) {
        animate();
        prev = performance.now();
    }
    window.requestAnimationFrame(cyc);
} 
window.addEventListener('load', cyc, false);
})();

最新更新