2015-08-31 3 views
2

Это мой «самый первый» набег на анимацию ключевого кадра. Раньше я был отстранен от предполагаемой неспособности динамически изменять жестко закодированные значения 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();

+1

Для меня это просто не имеет смысла - все это пишу JavaScript для создания CSS3 анимации. Просто используйте ['jQuery.animate()'] (http://api.jquery.com/animate/) и покончите с этим. – dave

+0

@dave и что не так с тем, как научиться правильно писать код. Говорите, как говорит OP. –

+0

@Griggy Я не уверен, если вы имеете в виду, что он работает не так, как ожидалось, или что он делает, но вы боитесь, что не делаете это правильно. –

ответ

1

Это кажется слишком сложным. Всякий раз, когда я работаю со сложными анимациями, я использую GSAP. Here's a simplied demo that I made. Он использует базовый JQuery и движок анимации GSAP, TweenMax.

Вы можете легко настроить ослабление с помощью GSAP их ease visualizer

$(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); 

}); 
+0

OP уже объяснил, что они знают, что есть библиотеки, но они предпочитают сворачивать свои собственные. Поэтому я должен спросить, как сложная часть JavaScript OP немного сложнее, чем включение всей библиотеки jQuery плюс еще одна библиотека 100K, чтобы сделать то же самое? –

+0

@Matt Wujek - согласно замечанию мистера Листера выше. Мне просто не нравится «средний человек». Я видел работу большинства популярных библиотек и да, это потрясающе, но для меня нет ничего более приятного, чем делать все сами. Ps: Я все еще пишу все подряд в NotePad! – Griggy

2

мне не очень нравится идея вставлять все эти ключевые кадры динамически с уникальными именами. Если бы я делал это и пытаясь использовать анимацию ключевого кадра 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; } \t \t \t \t 
 
} 
 
@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; } \t \t \t \t 
 
} 
 
@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>

+0

Спасибо Дэйву, но он уже был там. Я создал старые часы Би-би-си с его фирменными надписями второго и минутного рук, используя кубический безье. Лучшее, что я мог сделать, это один отскок. Если вы внимательно посмотрите на мой пример выше, вы увидите, что у него есть «магический двойной отскок». Я знаю, что там умирают детишки, но я хочу, чтобы на моих часах был двойной отскок! ЛОЛ. Я поставлю часы BBC в фрагменте, чтобы вы могли посмотреть. Он появится внизу этой страницы. – Griggy

+0

@Griggy Я не заметил двойного отскока. Во всяком случае, я думаю, что нашел лучшее решение, которое не требует JavaScript. Дайте мне знать, что вы думаете о обновленном ответе. – dave

+0

Отлично, приятно немного боком мышления. Теперь, если бы я смог его обновить с помощью getSeconds(), это было бы идеально. Я не увлекаюсь другими методами синхронизации для часов, поскольку они всегда дрейфуют. Я уже обновил мой, опубликованный ниже, но я обязательно буду играть с вашим методом обертки.Еще раз спасибо. – Griggy

1

Фокусировка только в коде, я считаю, это очень хорошо.

моя единственная забота будет

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

Обратите внимание, что coreCss будет в конце есть много анимации (проверить в Дев инструментов)

Вы должны просто очистить его.

Но учитывая, что анимация установки положения с помощью вперед, может быть, что может создать проблемы ...

Если это так, то может играть только с 2-анимации ??

Если вам нужен совет о том, как я получу этот эффект, я бы установил 2 вложенных элемента, один с сложными ключевыми кадрами, которые у вас есть, и работающими каждую секунду. И другой, делающий полный круг, шагнул 60 раз ...

+0

@ vals - Спасибо. Именно то, что я искал, в частности, coreCSS var – Griggy

+0

coreCSS теперь очищается в каждом цикле. Еще раз спасибо за указание на это. – Griggy

0

BBC часы пример для Дэйва.

(function() { 
 

 
/* The BBC Analogue Clock - [email protected] */ 
 

 
/* ^^^^^^^^^^^^^^^^^^^ 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); 
 
})();

1

Закончено часы.

(function() { 
 

 
    /* Station Style Clock - [email protected] */ 
 

 
    /* ^^^^^^^^^^^^^^^ 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>

Смежные вопросы