1

How do you place/position/append a js file if you can't find any ref to a parent node? For example, someone wants to use my script on their webpage and wants it positioned in a div or table etc with no id, name or classname. Parent node just returns null.

My only solution is to keep coming back to the trusty old but allegedly evil document.write().I've read about the perils of document.write() but for this sort of script I've never had a problem.

Below is an example, my take on the old BBC analogue clock. I'm trying to keep up with times and the majority of it uses createElement and append but the wrapper/container is created via document.write().

As it stands, you can stick it anywhere you want and, as far as I've tested, without any problem. Any ideas?

(function () {

/* The BBC Analogue Clock - kurt.grigg@yahoo.co.uk */

/* ^^^^^^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^^^^^^ */

var clockSize = 300;
var dialcol = 'rgba(0,0,255,1.0)';
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);
})();
Griggy
  • 123
  • 1
  • 6
  • I like document.write, it's a convenient way to embed a widget into a document when you have no server side processing. If you have no alternative, I can not see any problem about using it, as long as you know how to use it :-) –  Aug 23 '15 at 04:29
  • I would say in that case: "add an ID to the div and then use the script", but that's just an opinion. If they can add scripts, they can add IDs and it shouldn't be a problem. – Sami Kuhmonen Aug 23 '15 at 05:02

3 Answers3

0

One possible alternative to using document.write() is getting the script tag reference.

So instead of d.write('<div id = "'+rndId+'" style="display:inline-block;line-height:0px;"></div>');

You may be able to use

var scriptDom = document.currentScript;
var container = scriptDom.parentNode;
var containerDiv = document.createElement('div');
containerDiv.id = rndId;
containerDiv.style.display = 'inline-block';
containerDiv.style['line-height'] = '0px';
container.appendChild(containerDiv);

See here for more information on referencing the script tag.

If the parent node is null even in this scenario, document.write() may be your best bet.

*Note that the script tag must exist inside the HTML body, as elements appended to head tend not to render.

Community
  • 1
  • 1
Aaron B
  • 859
  • 11
  • 17
0

One potential solution is for you to wrap your entire script as a function that must be directly called, like this:

function drawClock(divID) {

   // some of your code goes here

   var el = document.getElementById(divID);
   if (el) {
       // write your code to the divID
   } else {
      // use your document.write() call as before
   }

   // rest of your code goes here
}

There are two major benefits of this approach:

  1. Your users can now include your script using <script src="yourScript.js"></SCRIPT> instead of directly embedding your code snippet in the spot where they want to render it in their code, which makes things cleaner for your end user.
  2. You present a very obvious interface to your user so they know that a divID is expected. However, as your fallback, if they don't pass in a divID, you can still use document.write()

As an end user, my code would resemble this:

<!-- any amount of HTML goes here -->
<SCRIPT src="yourClockScript.js"></SCRIPT>
<!-- any amount of HTML goes here -->
<DIV id="clockLocation"></DIV>
<!-- any amount of HTML goes here -->
<SCRIPT>
  drawClock('clockLocation');
</SCRIPT>

Personally, I would take things further by making the clock an object that is configurable. However, that's a different discussion that goes beyond the scope of your question.

Steven
  • 2,054
  • 1
  • 18
  • 13
  • Thanks Steven. I had tried various ways similar to your snippet but it was going away from what I wanted - a single line of drop in anywhere code i.e; <script src = "BBC Analogue Clock.js"></script> The benefit to me is stopping endless emails asking for help. Don't forget there's lots of people out there with varying degrees of interest and abilities. Also, what do you mean by configurable? Cheers, Kurt. – Griggy Aug 23 '15 at 16:25
  • I see. I didn't know that was your goal! In that case, you might want to consider a static HTML file that people can place on their web servers and then instruct them to include the file with an IFRAME to use the clock. Sounds roundabout, but it gets around document.write() problems that are often div tag related. As for configurable object, I meant your users could do something like this: var clock = new KurtsClock(); clock.setColor('blue'); clock.disableSecondHand(); clock.display('divTagName'); Lost of my Javascript code is object-oriented, which is uncommon, but I feel it helps. – Steven Aug 25 '15 at 19:37
  • Oh I'm with you now. With this particular script I didn't think it warranted it as it's unlikely to be used more than once on a page, although it can be without conflict. And there are some basic size and colour edits at the top, they just have to right click/edit or open with Notepad. Below, or where ever it will appear, is my original clock the BBC one is based on. Although it isn't OO it's fully, nearly!, configurable. If you fancy making it OO then feel free to have a go. I'd be interested to have a look. – Griggy Aug 26 '15 at 13:21
0

Original:

(function () {

 /* Analogue Clock - kurt.grigg@yahoo.co.uk */

 /* ^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^ */

var clockSize = 300;
var casecol = 'rgba(255,255,255,1.0)';
var dialcol = 'rgba(255,255,255,1.0)';
var numcol = 'rgba(1,1,1,1.0)';
var seccol = 'rgba(240,0,0,1.0)';
var handcol = 'rgba(60,60,60,1.0)';
var nutcol = 'rgb(220,0,0)';
var clockShape = 50;
/* (max) 50 = round  (min) 0 = square */

/* Optional dial background image */

var dialimg = 'url("")';

/* Dial background options:

'url("")'; 
    [Blank. Defaults to dialcol]
  
'url("abg.jpg")';
    [Image applied. Overides dialcol]
  
'linear-gradient(to right, rgba(0,0,255,1.0) 0%, rgba(255,0,0,1.0) 100%);';
    [Gradient applied. Overides dialcol]

*/       

var numoutline = 'yes';
    /* 'yes' or 'no' */
var numfill = 'rgba(240,0,0,1.0)';
var numshad = 'rgba(0,0,0,0.1)';

/* ^^^^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^^^^^^ */

var d = document;
var dgts = [];
var e = 360/12;
var degr = 0;
var nums = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];
var mls = 100;
var prev = performance.now();
var radi = Math.PI / 180;
var offs = 60 * radi;
var canstroke = ('webkitTextStroke' in d.body.style);
var str = '-webkit-text-fill-color: '+numfill+';'
    +'-webkit-text-stroke-width: '+xy(0.3)+'px;'
    +'-webkit-text-stroke-color: '+numcol+';';
var wks = (canstroke && numoutline == "yes")?str:'';
var broff = (clockShape < 20)?2:0;
var secSpan = '.9s';
var minSpan = '1.5s';
var houSpan = '1.5s';
var secIncr = 0;
var minIncr = 0;
var houIncr = 0;
var secDeg, minDeg, houDeg, preSec, preMin, preHou;
var idx = d.getElementsByTagName('div').length;
var rndId = 'id'+Math.random() * 1;
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;'
    +'background-image: '+dialimg+';' 
    +'background-size: cover;'
    +'background-color: '+dialcol+';'
    +'border: '+xy(2)+'px solid '+casecol+';'
    +'border-radius: '+clockShape+'%;');
d.getElementById(rndId).appendChild(dial);

for (var i = 0; i < 12; i++) {
    dgts[i] = d.createElement('div');
    dgts[i].setAttribute('style', 'display: block;'
        +'position: absolute;'
        +'width: '+xy(16)+'px;'
        +'height: '+xy(14)+'px;'
        +'margin: auto;top: 0;bottom: 0; left: 0;right: 0;'
        +'font: bold '+xy(13)+'px  Arial;'
        +'line-height: '+xy(13)+'px;'
        +'text-align: center !important;'
        +'color: '+numcol+';'
        +'text-shadow: '+xy(1)+'px '+xy(1)+'px 0px '+numshad+';'+wks+';');

    dgts[i].innerHTML = nums[i];
    dial.appendChild(dgts[i]);
    degr += 30;
    dgts[i].style.top = xy(0) + xy(84) * Math.sin(-offs + e * i * radi) + 'px';
    dgts[i].style.left= xy(0) + xy(84) * Math.cos(-offs + e * i * radi) + 'px';
    dgts[i].style.transform = 'rotate(' + (degr) + 'deg)';
    dgts[i].style.transformOrigin = 'center center 0px';
}

/* Hour hand CSS */

var houCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(73)+'px;'
    +'width: '+xy(5)+'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 houClone = houCss;

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(39)+'px;'
    +'width: '+xy(3)+'px;'
    +'border-radius: '+xy(2.5)+'px  '+xy(2.5)+'px 0% 0%;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0;left: 0;right: 0;'
    +'box-shadow: '+xy(.5)+'px '+xy(.5)+'px 0px 0px rgba(0,0,0,0.2);'
    +'background-color: '+handcol+';');
houHand.appendChild(hh);
  
/* Minute hand CSS */

var minCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(95)+'px;'
    +'width: '+xy(3)+'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 minClone = minCss;

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(50)+'px;'
    +'width: '+xy(2)+'px;'
    +'border-radius: '+xy(1.5)+'px '+xy(1.5)+'px 0% 0%;'
    +'margin: auto; top: 0; left: 0;right: 0;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'box-shadow: '+xy(0.8)+'px '+xy(0.8)+'px 0px 0px rgba(0,0,0,0.2);'
    +'background-color: '+handcol+';');
minHand.appendChild(mh);

/* Seconds hand CSS */

var secCss = 'display: block;'
    +'position: absolute;'
    +'height: '+xy(95)+'px;'
    +'width: '+xy(8)+'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 secClone = secCss;

var secHand = d.createElement('div');
secHand.setAttribute('style', secClone);
dial.appendChild(secHand);

var sh = d.createElement('div');
sh.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(56)+'px;'
    +'width: '+xy(1)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; top: 0; left: 0; right: 0;'
    +'box-shadow:'
    +' '+xy(1)+'px 0px 0px 0px rgba(0,0,0,0.2);'
    +'background-color: '+seccol+';');
   secHand.appendChild(sh);

var st = d.createElement('div');
st.setAttribute('style', 'display: block;'
    +'position:  absolute;'
    +'top: '+xy(55.5)+'px;'
    +'height: '+xy(6)+'px;'
    +'width: '+xy(6)+'px;'
    +'border: '+xy(2/2)+'px solid '+seccol+';'
    +'border-radius: '+xy(6)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto; left: 0; right: 0;'
    +'box-shadow:'
    +' '+xy(.8)+'px '+xy(.8)+'px 0px 0px rgba(0,0,0,0.2),'
    +'inset '+xy(.8)+'px '+xy(.8)+'px 0px 0px rgba(0,0,0,0.2);');
secHand.appendChild(st);

var nutbase = d.createElement('div');
nutbase.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(3)+'px;'
    +'width: '+xy(3)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
    +'background-color: '+nutcol+';'
    +'border-radius: 50%;'
    +'z-index: 5;');
dial.appendChild(nutbase);

var nut = d.createElement('div');
nut.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(1)+'px;'
    +'width: '+xy(1)+'px;'
    +'border-radius: 50%;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
    +'background: '+nutcol+';'
    +'box-shadow:'
    +'0px -'+xy(.2)+'px 0px rgba(225,225,225,0.7),'
    +'inset 0px -'+xy(.3)+'px 0px rgba(0,0,0,0.2),'
    +'z-index: 6;');
dial.appendChild(nut);

var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
    +'position: absolute;'
    +'height: '+xy(100)+'px;'
    +'width: '+xy(100)+'px;'
    +'font-size: 0px;line-height: 0px;padding: 0;'
    +'border-radius: '+(clockShape - broff)+'%;'
    +'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
    +'box-shadow:'
    +'0px 0px '+xy(2)+'px '+xy(1)+'px rgba(0,0,0,0.4),'
    +'inset 0 '+xy(2)+'px rgba(255,255,255,0.01),'
    +'inset 0 '+xy(10)+'px rgba(255,255,255,0.3),'
    +'inset 0 '+xy(10)+'px '+xy(20)+'px rgba(255,255,255,0.25),'
    +'inset 0 -'+xy(10)+'px '+xy(30)+'px rgba(30,30,30,0.3);'
    +'background:rgba(0,0,0,0.1);'
    +'z-index: 7;');
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 = '';
    }
    
    secClone = secCss;
 
    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 reGen'+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: reGen'+secIncr+' '+secSpan+' 1 forwards;';
    secClone += secAni;
    secHand.setAttribute('style', secClone);
    dial.appendChild(secHand);
}

function minKeyFrames() {
    var minSheet = (d.getElementById('tmpMinSheet'+idx));
    if (minSheet) {
        minSheet.outerHTML = '';
    }

    minClone = minCss;
 
    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 minGen'+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: minGen'+minIncr+' '+minSpan+' 1 forwards;';
    minClone += minAni;
    minHand.setAttribute('style', minClone);
    dial.appendChild(minHand);
}

function houKeyFrames() {
    var houSheet = (d.getElementById('tmphouSheet'+idx));
    if (houSheet) {
        houSheet.outerHTML = '';
    }

    houClone = houCss;
 
    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 houGen'+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: houGen'+houIncr+' '+houSpan+' 1 forwards;';
    houClone += houAni;
    houHand.setAttribute('style', houClone);
    dial.appendChild(houHand);
}

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);
})();
Griggy
  • 123
  • 1
  • 6