German style railway clock. Appalling use of SVG? - javascript

Don't laugh, my knowledge of SVG practically zero. This is my first attempt at animating svg shadows. All I wanted was to dynamically access the filter feOffset's dx and dy attributes to give the clock hands realistic shadow positions as they move around the dial.
The only way I could do it was to rip apart the svg and reassemble it with JavaScript. It works a treat and runs at about 1.5% to 4% cpu on my machine with a setTimeout cycle of about 30mls (needed for smooth second hand). I discarded requestanimationframe because the time goes to pot with long periods without page focus.
As it stands, the script is creating/replacing (I think!) new svg on each new cycle.
Anyway, my question is there a better/proper way to access and manipulate dx and dy?
Ps: I'm only using svg because the shapes I want obviously can't be generated with css and as the clock is fully resizable, an image png etc is unacceptable.
Thanks for any help.
(function () {
/* German Station Style Clock */
/* ^^^^^^^^^^^^ Config below ^^^^^^^^^^^^ */
var clockSize = 500;
var casecol = 'rgba(40,40,40,1.0)';
var dialcol = 'rgba(255,255,255,1.0)';
var numcol = 'rgba(40,40,40,1.0)';
var seccol = 'rgba(200,0,0,1.0)';
var handcol = 'rgba(40,40,40,1.0)';
var shadowOpacity = 0.3;
var shadowBlur = 0.2;
var shadowAngle = 0.6;
var clockShape = 50;
/* (max) 50 = round (min) 0 = square */
var numoutline = 'no';
/* 'yes' or 'no' */
var numfill = 'rgba(255,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 tmr;
var mls = 1000 / 30;
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.4)+'px;'
+'-webkit-text-stroke-color: '+numcol+';';
var wks = (canstroke && numoutline == "yes")?str:'';
var broff = (clockShape < 20)?2:0;
var presec;
var premin;
var prehou;
var rnd = 'id'+Math.random() * 1;
var idx = d.getElementsByTagName('div').length;
d.write('<div id = "'+rnd+'" style="display:inline-block;line-height:0px;"></div>');
function xy (a) {
return (a * clockSize / 100);
}
/* Clock dial */
var dial = d.createElement('div');
dial.setAttribute('style', 'display:inline-block;'
+'position: relative;'
+'height: '+clockSize+'px;'
+'width: '+clockSize+'px;'
+'background-color: '+dialcol+';'
+'border: '+xy(2)+'px solid '+casecol+';'
+'border-radius: '+clockShape+'%;');
d.getElementById(rnd).appendChild(dial);
/* Clock markers */
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+';'+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';
}
/* Generic container div for all hands */
var handContainers = 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(20)+'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 */
var houHand = d.createElement('div');
houHand.setAttribute('style', handContainers + 'transition: .5s cubic-bezier(0.666, 1.91, 0.333, 0);');
dial.appendChild(houHand);
var houC = d.createElement('div');
var housvg = '<polygon points="94,46 100,40 106,46 106,118 94,118" style="fill:'+handcol+'; stroke:none"/>';
/* Minute hand */
var minHand = d.createElement('div');
minHand.setAttribute('style',handContainers + 'transition: .4s cubic-bezier(0.666, 1.91, 0.333, 0);');
dial.appendChild(minHand);
var minC = d.createElement('div');
var minsvg = '<polygon points="95.5,11.5 100,7 104.5,11.5 104.5,122 95.5,122" style="fill:'+handcol+'; stroke:none"/>';
/* Seconds hand */
var secHand = d.createElement('div');
secHand.setAttribute('style',handContainers);
dial.appendChild(secHand);
var secC = d.createElement('div');
var secsvg = '<polygon points="98.8,11 100,9.8 101.2,11 101.6,42 98.4,42" style="fill:'+seccol+'; stroke:none"/>'+
'<polygon points="98.1,58 101.9,58 102.5,122 97.5,122" style="fill:'+seccol+'; stroke:none"/>'+
'<circle cx="100" cy="50" r="8.5" style="fill:none; stroke:'+seccol+'; stroke-width:6.5"/>';
function dropShadow(s, h) {
var depth = xy(h);
var angle = s * radi - shadowAngle;
var vsa = depth * Math.cos(angle);
var hsa = depth * Math.sin(angle);
return {vsa:vsa, hsa:hsa}
}
var str1 = '<svg height="'+xy(100)+'" width="'+xy(20)+'" viewBox="90.25 -4 20 200" ><defs>';
var str3 = '<feGaussianBlur in="SourceAlpha" stdDeviation="'+shadowBlur+'"/>';
var str5 = '<feFlood flood-color="#000000" flood-opacity="'+shadowOpacity+'"/>'+
'<feComposite in2="offsetblur" operator="in"/>'+
'<feMerge>'+
'<feMergeNode/>'+
'<feMergeNode in="SourceGraphic"/>'+
'</feMerge>'+
'</filter>'+
'</defs>';
var str8 = '</g></svg>';
function dynShad (str2, str4, str6, str7) {
var create = str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8;
return create;
}
function clock() {
var x = new Date();
var time = Math.min(60000, 1.025 * (1000 * x.getSeconds() + x.getMilliseconds()));
var seconds = Math.floor(time / 1000);
var millis = time % 1000;
var germanSec = (6 * seconds + 3 * (1 + Math.cos(Math.PI + Math.PI * (0.001 * millis))));
var minutes = x.getMinutes();
var hours = (x.getHours() * 30) + (minutes / 2);
if (germanSec !== presec) {
var ssy = dropShadow(germanSec, 0.7).vsa;
var ssx = dropShadow(germanSec, 0.7).hsa;
var sf = '<filter id="sf'+idx+'" x="-50%" y="-50%" width="200%" height="200%">';
var se = '<g filter="url(#sf'+idx+')">';
var ss = '<feOffset id="soffset'+idx+'" dx="'+ssx+'" dy="'+ssy+'" result="offsetblur"/>';
secC.innerHTML = dynShad (sf, ss,se, secsvg);
secHand.appendChild(secC);
}
if (minutes !== premin) {
var msy = dropShadow(minutes * 6, 0.5).vsa;
var msx = dropShadow(minutes * 6, 0.5).hsa;
var mf = '<filter id="mf'+idx+'" x="-50%" y="-50%" width="200%" height="200%">';
var me ='<g filter="url(#mf'+idx+')">';
var ms = '<feOffset id="moffset'+idx+'" dx="'+msx+'" dy="'+msy+'" result="offsetblur"/>';
minC.innerHTML = dynShad (mf, ms,me, minsvg);
minHand.appendChild(minC);
}
if (hours !== prehou) {
var hsy = dropShadow(hours, 0.4).vsa;
var hsx = dropShadow(hours, 0.4).hsa;
var hf = '<filter id="hf'+idx+'" x="-50%" y="-50%" width="200%" height="200%">';
var he ='<g filter="url(#hf'+idx+')">';
var hs = '<feOffset id="hoffset'+idx+'" dx="'+hsx+'" dy="'+hsy+'" result="offsetblur"/>';
houC.innerHTML = dynShad (hf, hs,he, housvg);
houHand.appendChild(houC);
}
secHand.style.transform = 'rotate(' + germanSec + 'deg) translateZ(0)';
minHand.style.transform = 'rotate(' + (minutes * 6) + 'deg) translateZ(0)';
houHand.style.transform = 'rotate(' + hours + 'deg) translateZ(0)';
presec = germanSec;
premin = minutes;
prehou = hours;
tmr = setTimeout(clock, mls);
}
window.addEventListener('load', clock, false);
})();

All I wanted was to dynamically access the filter feOffset's dx and dy
attributes to give the clock hands realistic shadow positions as they
move around the dial.
actually you don't have to touch the dx and dy attribute for a realistic shadow. All you have to do is to put your hands into a g-element and apply the shadow to the group (which is not rotating). in this case the shadow don't rotate and so the offset stays fixed.
see this example, where the rect is rotating, but the shadow is aplied to the group:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<defs>
<filter id="gb" filterUnits="userSpaceOnUse" x="-50" y="-50" width="100" height="100">
<feGaussianBlur in="SourceAlpha" stdDeviation="1" />
<feOffset dx="2" dy="2" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g transform="translate(50 50)" filter="url(#gb)">
<rect x="-0.5" y="-45" width="1" height="45" fill="red">
<animateTransform attributeName="transform" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite"/>
</rect>
</g>
</svg>
var r=document.getElementById("rect")
setInterval(function(){
var d = new Date();
var a = d.getSeconds()*6; // 360/60 so every second equals 6 deg
r.setAttribute("transform","rotate("+a+")");
},500);
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<defs>
<filter id="gb" filterUnits="userSpaceOnUse" x="-50" y="-50" width="100" height="100">
<feGaussianBlur in="SourceAlpha" stdDeviation="1" />
<feOffset dx="2" dy="2" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g transform="translate(50 50)" filter="url(#gb)">
<rect id="rect" x="-0.5" y="-45" width="1" height="45" fill="red"/>
</g>
</svg>

If you know the id of the filter you can get it using document.getElementById. In your case I think that would be something like this...
var offset = document.getElementById('hoffset'+idx);
You can set and get the dx/dy using setAttribute/getAttribute e.g.
offset.setAttribute("dx", "13");
Or you can use the SVG DOM which will let you work with numbers rather than strings.
offset.dx.baseVal = 13;

German railway T&N station clock
(function () {
/*
German Railway Clock
kurt.grigg#yahoo.co.uk
*/
/* ^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^ */
var clockSize = 300;
var caseColour = 'rgb(20,20,20)';
var dialColour = 'rgba(235,240,240,1.0)';
var sechandColour = 'rgba(173,26,20,1.0)';
var handColour = 'rgb(30,30,30)';
var markColour = 'rgb(10,10,10)';
var reflection = '6Reflection.png';
var clockShape = 50;
/* (max) 50 = round (min) 0 = square */
/* ^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^ */
var d = document;
var mrkrs = [];
var tmr;
var mls = 50;
var broff = (clockShape < 20) ? 2 : 0;
var prevmin;
var mincr = new Date().getMinutes() - 1;
var hincr = new Date().getHours();
var rnd = 'id'+Math.random() * 1;
var cbcbzr = '.4s cubic-bezier(0.666, 1.91, 0.333, 0)';
var dum = '';
var vb = '<svg height="'+xy(100)+'" width="'+xy(100)+'" viewBox="0 0 200 200">';
d.write('<div id = "'+rnd+'" style="display:inline-block;line-height:0px;"></div>');
function xy (v) {
return (v * clockSize / 100);
}
function genShadKillClone(c, v, x, y) {
c.style.left = xy(x)+'px';
c.style.top = xy(y)+'px';
c.style.zIndex--;
var s = 'filter="url(#handShadow)"';
var r = v.split('filter="url()"').join("");
r = r.replace(/""/g, s);
c.innerHTML = r;
}
/* Clock case and dial */
var outerRim = d.createElement('div');
outerRim.setAttribute('style', 'display:inline-block;'
+'position: relative;'
+'height: '+xy(115)+'px;'
+'width: '+xy(115)+'px;'
+'background-image: linear-gradient(to left, '
+'rgba(0,0,0,0.4) 5%, '
+'rgba(255,255,255,0.3) 50%, '
+'rgba(0,0,0,0.4) 95%);'
+'background-color: '+caseColour+';'
+'border: '+xy(1)+'px solid transparent;'
+'box-shadow: 0 0 '+xy(0.5)+'px '+xy(0.05)+'px rgba(255,255,255,0.7), '
+'0 '+xy(6)+'px '+xy(1)+'px -'+xy(1)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;');
d.getElementById(rnd).appendChild(outerRim);
var innerRim = d.createElement('div');
innerRim.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(109.8)+'px;'
+'width: '+xy(109.8)+'px;'
+'background-color: '+dialColour+';'
+'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
+'box-shadow: inset 0 0 0 '+xy(3.0)+'px rgba(50,50,50,0.15),'
+'inset 0 '+xy(6)+'px '+xy(5)+'px '+xy(4)+'px rgba(0,0,0,0.4);'
+'border-radius: '+clockShape+'%;'
+'border: '+xy(0.2)+'px solid rgba(255,255,255,0.05);');
outerRim.appendChild(innerRim);
var dial = d.createElement('div');
dial.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'px;'
+'margin: auto; top: 0; bottom: 0;left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'overflow: hidden;');
innerRim.appendChild(dial);
/* Clock markers */
var face = '<svg id="TNClock" xmlns="http://www.w3.org/2000/svg"'+
'viewBox="0 0 200 200" width="100%" height="100%">'+
'<defs>'+
'<clipPath id="dialPath">'+
'<circle cx="100" cy="100" r="100"/>'+
'</clipPath>'+
'</defs>'+
'<filter id="handShadow" color-interpolation-filters="sRGB">'+
'<feFlood result="flood" flood-color="#000" flood-opacity=".4"/>'+
'<feComposite result="composite1" operator="in" in2="SourceGraphic" in="flood"/>'+
'<feGaussianBlur result="blur" stdDeviation="0.5" in="composite1"/>'+
'<feOffset result="offset" dy="0" dx="0"/>'+
'<feComposite result="composite2" operator="atop" in2="offset" in="offset"/>'+
'</filter>'+
'<g id="TNLogo" transform="translate(87.4,141.2) scale(0.5, 0.5)">'+
'<path stroke="#000" fill="none" d="M2.732 19L25 2.06 47.268 19 25 35.94 2.732 19z"/>'+
'<path d="M17.194 10.2h15.612v2.298h-6.713v17.727h-2.186V12.498h-6.713V10.2z"/>'+
'<path d="M17.975 14.95l11.865 8.864V14.95h2.185v13.13L20.16 19.22v8.863h-2.185V14.95z"/>'+
'</g>'+
'</svg>';
dial.innerHTML = face;
for (var i = 0; i < 60; i++) {
var mrkrLength = 30;
if (i % 15) {
mrkrLength = 24;
}
if (i % 5) {
mrkrLength = 8;
}
var mrkrWidth = (i % 5) ? 3.6 : 8.8;
mrkrs[i] = document.createElementNS("http://www.w3.org/2000/svg", 'line');
with(mrkrs[i]) {
setAttribute('x1', '100');
setAttribute('y1', '0');
setAttribute('x2', '100');
setAttribute('y2', mrkrLength);
setAttribute('stroke', markColour);
setAttribute('stroke-width', mrkrWidth);
setAttribute('stroke-linecap', 'butt');
setAttribute("clip-path", "url(#dialPath)");
setAttribute( "transform","rotate("+i * 6+", 100, 100)");
}
TNClock.appendChild(mrkrs[i]);
}
/* Generic container for all hands */
var handContainers = 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'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 */
var houContainer = d.createElement('div');
houContainer.setAttribute('style', handContainers + 'transition: '+cbcbzr+';');
houContainer.style.zIndex = 50;
dial.appendChild(houContainer);
var houHand = d.createElement('div');
var housvg = vb +
'<polygon points="94,46 100,40 106,46 106,118 94,118" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
houHand.innerHTML = housvg;
houContainer.appendChild(houHand);
var houShad = houContainer.cloneNode(true);
dial.appendChild(houShad);
genShadKillClone(houShad,housvg, 0, 3);
/* Minute hand */
var minContainer = d.createElement('div');
minContainer.setAttribute('style',handContainers + 'transition: '+cbcbzr+';');
minContainer.style.zIndex = 52;
dial.appendChild(minContainer);
var minHand = d.createElement('div');
var minsvg = vb +
'<polygon points="95.5,11.5 100,7 104.5,11.5 104.5,122 95.5,122" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
minHand.innerHTML = minsvg;
minContainer.appendChild(minHand);
var minShad = minContainer.cloneNode(true);
dial.appendChild(minShad);
genShadKillClone(minShad,minsvg, 0, 4);
/* Seconds hand */
var secContainer = d.createElement('div');
secContainer.setAttribute('style',handContainers);
secContainer.style.zIndex = 54;
dial.appendChild(secContainer);
var secHand = d.createElement('div');
var secsvg = vb +
'<path d="M100 9.05l-1.2 1.2-.355 27.367c-5.724.77-10.195 5.71-10.195 11.633 0 5.792 4.275 10.643 9.816 11.576L97.5 121.25h5l-.568-60.424c5.54-.933 9.818-5.784 9.818-11.576 0-5.923-4.473-10.862-10.197-11.633L101.2 10.25zM100 44c2.938 0 5.25 2.312 5.25 5.25s-2.312 5.25-5.25 5.25-5.25-2.312-5.25-5.25S97.062 44 100 44z" fill="'+sechandColour+'" stroke="none" stroke-width="0" "'+dum+'" />'+
'</svg>';
secHand.innerHTML = secsvg;
secContainer.appendChild(secHand);
var secShad = secContainer.cloneNode(true);
dial.appendChild(secShad);
genShadKillClone(secShad,secsvg, 0, 5);
var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(108.8)+'px;'
+'width: '+xy(108.8)+'px;'
+'margin: auto; top: 0; bottom: 0; left: 0;right: 0;'
+'border: '+xy(0.2)+'px solid #000;'
+'border-radius: '+clockShape+'%;'
+'background-image: url("http://i61.tinypic.com/300xjcn.png");'
+'background-size: cover;'
+'opacity: 0.3;'
+'z-index: 55;'
+'overflow: hidden;');
innerRim.appendChild(glass);
function clock() {
var x = new Date();
var time = Math.min(60000, 1.025 * (1000 * x.getSeconds() + x.getMilliseconds()));
var seconds = Math.floor(time / 1000);
var millis = time % 1000;
var germanSec = (6 * seconds + 3 * (1 + Math.cos(Math.PI + Math.PI * (0.001 * millis))));
var presmin = x.getMinutes();
if (presmin !== prevmin) {
mincr++;
}
prevmin = presmin;
secContainer.style.transform = 'rotate(' + germanSec + 'deg) translateZ(0)';
secShad.style.transform = 'rotate(' + germanSec + 'deg) translateZ(0)';
minContainer.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
minShad.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
houContainer.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
houShad.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
tmr = setTimeout(clock, mls);
}
window.addEventListener('load', clock, false);
})();
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>German Railway Clock</title>
<style type="text/css">
body {
background-color: rgb(205,179,139);
text-align: center;
}
</style>
</head>
<body>
</body>
</html>

The Original Hilfiker/MobaTime Swiss Railway Clock. 1953 version.
(function () {
/*
The Hilfiker/MobaTime Swiss Railway Clock
1953 version (Stop To Go)
kurt.grigg#yahoo.co.uk
*/
/* ^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^ */
var clockSize = 300;
var caseColour = 'rgba(200,200,200,1.0)';
var dialColour = 'rgba(235,240,240,1.0)';
var sechandColour = 'rgba(173,26,20,1.0)';
var handColour = 'rgb(20,20,20)';
var markColour = 'rgb(10,10,10)';
var reflection = '6Reflection.png';
var clockShape = 50;
/* (max) 50 = round (min) 0 = square */
/* ^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^ */
var d = document;
var mrkrs = [];
var tmr;
var mls = 50;
var broff = (clockShape < 20) ? 2 : 0;
var prevmin;
var mincr = new Date().getMinutes() - 1;
var hincr = new Date().getHours();
var rnd = 'id'+Math.random() * 1;
var cbcbzr = '.3s cubic-bezier(0.666, 1.91, 0.333, 0)';
var vb = '<svg height="'+xy(100)+'" width="'+xy(100)+'" viewBox="0 0 200 200">';
d.write('<div id = "'+rnd+'" style="display:inline-block;line-height:0px;"></div>');
var dum = '';
function xy (v) {
return (v * clockSize / 100);
}
function genShadKillClone(c, v, x, y) {
c.style.left = xy(x)+'px';
c.style.top = xy(y)+'px';
c.style.zIndex--;
var s = 'filter="url(#handShadow)"';
var r = v.split('filter="url()"').join("");
r = r.replace(/""/g, s);
c.innerHTML = r;
}
/* Clock case and dial */
var outerRim = d.createElement('div');
outerRim.setAttribute('style', 'display:inline-block;'
+'position: relative;'
+'height: '+xy(116)+'px;'
+'width: '+xy(116)+'px;'
+'background-image: linear-gradient(to left, '
+'rgba(0,0,0,0.3) 0%, '
+'rgba(255,255,255,0.6) 50%, '
+'rgba(0,0,0,0.3) 100%);'
+'background-color: '+caseColour+';'
+'border: '+xy(1)+'px solid transparent;'
+'box-shadow: 0 0 '+xy(0.5)+'px '+xy(0.05)+'px rgba(255,255,255,0.7), '
+'0 '+xy(6)+'px '+xy(1)+'px -'+xy(1)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;');
d.getElementById(rnd).appendChild(outerRim);
var innerRim = d.createElement('div');
innerRim.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(113.8)+'px;'
+'width: '+xy(113.8)+'px;'
+'background-color: '+dialColour+';'
+'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
+'box-shadow: inset 0 0 0 '+xy(2.9)+'px rgba(30,30,30,0.3),'
+'inset 0 '+xy(3)+'px '+xy(5)+'px '+xy(3)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;'
+'border: '+xy(0.2)+'px solid rgba(255,255,255,0.05);');
outerRim.appendChild(innerRim);
var dial = d.createElement('div');
dial.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'px;'
+'margin: auto; top: 0; bottom: 0;left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'overflow: hidden;');
innerRim.appendChild(dial);
/* Clock markers */
var face = '<svg id="MobaTimeClock" xmlns="http://www.w3.org/2000/svg"'+
'viewBox="0 0 200 200" width="100%" height="100%">'+
'<defs>'+
'<clipPath id="dialPath">'+
'<circle cx="100" cy="100" r="100"/>'+
'</clipPath>'+
'</defs>'+
'<filter id="handShadow" color-interpolation-filters="sRGB">'+
'<feFlood result="flood" flood-color="#000" flood-opacity=".4"/>'+
'<feComposite result="composite1" operator="in" in2="SourceGraphic" in="flood"/>'+
'<feGaussianBlur result="blur" stdDeviation="0.5" in="composite1"/>'+
'<feOffset result="offset" dy="0" dx="0"/>'+
'<feComposite result="composite2" operator="atop" in2="offset" in="offset"/>'+
'</filter>'+
'</svg>';
dial.innerHTML = face;
for (var i = 0; i < 60; i++) {
var mrkrLength = (i % 5) ? 7.5 : 25;
var mrkrWidth = (i % 5) ? 3 : 7.5;
mrkrs[i] = document.createElementNS("http://www.w3.org/2000/svg", 'line');
with(mrkrs[i]) {
setAttribute('x1', '100');
setAttribute('y1', '0');
setAttribute('x2', '100');
setAttribute('y2', mrkrLength);
setAttribute('stroke', markColour);
setAttribute('stroke-width', mrkrWidth);
setAttribute('stroke-linecap', 'butt');
setAttribute("clip-path", "url(#dialPath)");
setAttribute( "transform","rotate("+i * 6+", 100, 100)");
}
MobaTimeClock.appendChild(mrkrs[i]);
}
var logo = '<svg width="100%" height="100%" viewBox="0 0 160 106" ' +
'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
'<path d="M72.764.744C74.936.347 77.136 0 79.35.052c.94.017 1.88.01 2.82.08 4.8' +
'35.364 9.615 1.48 14.098 3.357 4.685 1.99 9.022 4.85 12.635 8.467 3.488 3.46 6' +
'.303 7.605 8.27 12.123 1.837 4.26 2.964 8.834 3.284 13.47.3 4.69-.077 9.427-1.' +
'208 13.988-.398 1.737-.95 3.43-1.494 5.126-3.685-2.417-7.306-4.932-10.977-7.37' +
'.638-2.657 1.03-5.388.955-8.128-.032-2.894-.504-5.78-1.35-8.545-1.36-4.383-3.75' +
'-8.47-7.038-11.658-3.758-3.765-8.715-6.24-13.914-7.168-2.006-.367-4.047-.537-6' +
'.083-.51-2.38.167-4.755.56-7.04 1.256-.07.018-.212.05-.282.067-4.875 1.52-9.37' +
' 4.36-12.692 8.292-3.532 4.122-5.726 9.365-6.367 14.77-.3 2.187-.26 4.41-.16 6' +
'.61.152 1.61.355 3.218.707 4.797-3.644 2.364-7.266 4.76-10.93 7.09-1.812-4.79-' +
'2.977-9.862-3.083-15.002-.237-8.587 2.43-17.226 7.466-24.152C51.114 11.27 56.7' +
'94 6.69 63.212 3.79c3.06-1.366 6.266-2.402 9.552-3.046z" fill-opacity=".9" fill="'+markColour+'"/>' +
'<path d="M48.772 76.595L55.83 71.9l1.774 1.816c1.023 1.047 2.286 2.145 2.984 2' +
'.595 5.233 3.37 12.434 5.067 20.513 4.835 3.703-.106 5.01-.245 8.036-.856 2.72' +
'-.55 5.2-1.387 7.582-2.557 2.47-1.213 4.22-2.505 5.976-4.41l1.357-1.47 7.045 4' +
'.715 7.045 4.715 11.09.06c6.934.038 11.03.002 10.926-.096-.828-.782-35.83-26.7' +
'53-35.916-26.648-4.85 5.9-8.918 9.252-13.73 11.313-3.472 1.487-6.387 2.055-10.' +
'566 2.058-9.514.007-16.507-3.84-24.292-13.368-.08-.096-31.817 23.46-35.66 26.4' +
'67-.395.308-.217.312 10.66.266l11.064-.047 7.056-4.695z" fill="url(#a)"/>' +
'<path d="M81.42 90.82h-3.505l-5.58 15.26h3.473l1.078-2.32 5.597.02 1.08 2.302h' +
'3.32l-5.462-15.26zm-1.717 4.213l1.667 5.944h-3.285l1.618-5.944zm-22.434-4.23h-' +
'5.174v15.26l6.303.016c1.6.02 3.624-1.607 3.994-3.73.084-2.25-.845-4.16-2.376-4' +
'.446.876-.41 1.45-1.89 1.348-3.854-.238-1.944-2.26-3.392-4.097-3.248m.976 3.73' +
'c.353.662.153 1.337-.05 1.837-.656.768-1.837.714-2.78.714v-3.302c.842 0 2.308-' +
'.16 2.83.75m.625 5.747c.37.606.286 1.73.103 2.16-.893.998-2.16.962-3.523.8v-3.' +
'604c1.618-.108 2.46-.09 3.42.643M15.118 90.8l2.41 15.24-3 .037-1.432-8.89-3.75' +
'8 8.89-.926-.037-3.675-8.496-1.517 8.532L0 106.042l2.36-15.277h3.17l3.166 8.744' +
' 3.42-8.708h3zm19.23 11.673c-2.29 0-4.18-2-4.18-4.427 0-2.427 1.89-4.425 4.18-' +
'4.425 2.293 0 4.18 1.998 4.18 4.425 0 2.426-1.887 4.427-4.18 4.427m0 3.604c4.2' +
'8 0 7.77-3.605 7.77-8.032 0-4.425-3.49-8.048-7.77-8.048-4.28 0-7.768 3.623-7.7' +
'68 8.048 0 4.427 3.488 8.03 7.768 8.03M98.68 91.482h8.56l-.285 1.68h-3.49l-1.8' +
'87 12.883h-1.754l1.924-12.884h-3.374l.306-1.68zm18.623 0h1.753l-2.19 14.563h-1' +
'.738l2.175-14.562zm24.506-1.017l.756 15.58h-1.99l-.115-9.94-5.898 10.242-2.715' +
'-10.242-3.166 9.94h-1.972l5.444-15.58 3 11.796 6.657-11.797zm18.236 1.018l-.43' +
'8 1.68h-5.648l-.608 4.086h5.546l-.32 1.66h-5.494l-.876 5.46h5.798l-.286 1.677h' +
'-7.55l2.174-14.562h7.702z" fill-opacity="1.0" fill="'+markColour+'"/>' +
'<defs>' +
'<pattern xlink:href="#b" id="a" patternTransform="translate(364.52 610.068) scale(6.07904)"/>' +
'<pattern id="b" patternTransform="scale(10)" height="1" width="1.07" patternUnits="userSpaceOnUse">' +
'<path fill="'+markColour+'" d="M0 0h.5v1H0z"/>' +
'</pattern>' +
'</defs>' +
'</svg>';
var mtl = d.createElement('div');
mtl.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(9)+'px;'
+'top: '+xy(68)+'px;'
+'paddingBottom: '+xy(1)+'px;'
+'margin: auto; left: 0;right: 0;');
mtl.innerHTML = logo;
dial.appendChild(mtl);
/* Generic container for all hands */
var handContainers = 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'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 */
var houContainer = d.createElement('div');
houContainer.setAttribute('style', handContainers + 'transition: '+cbcbzr+';');
houContainer.style.zIndex = 50;
dial.appendChild(houContainer);
var houHand = d.createElement('div');
var housvg = vb +
'<polygon points="95,33 105,33 106,125 94,125" transform="translate(0,2)" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
houHand.innerHTML = housvg;
houContainer.appendChild(houHand);
var houShad = houContainer.cloneNode(true);
dial.appendChild(houShad);
genShadKillClone(houShad,housvg, 0, 3);
/* Minute hand */
var minContainer = d.createElement('div');
minContainer.setAttribute('style',handContainers + 'transition: '+cbcbzr+';');
minContainer.style.zIndex = 52;
dial.appendChild(minContainer);
var minHand = d.createElement('div');
var minsvg = vb +
'<polygon points="96,5 104,5 105,125 95,125" transform="translate(0,2)" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
minHand.innerHTML = minsvg;
minContainer.appendChild(minHand);
var minShad = minContainer.cloneNode(true);
dial.appendChild(minShad);
genShadKillClone(minShad,minsvg, 0, 4);
/* Seconds hand */
var secContainer = d.createElement('div');
secContainer.setAttribute('style',handContainers);
secContainer.style.zIndex = 54;
dial.appendChild(secContainer);
var secHand = d.createElement('div');
var secsvg = vb +
'<path d="M100 23.475a10 10 0 0 0-10 10 10 10 0 0 0 8.22 9.832V135h3.56V43.31a10 10 0 0 0 8.22-9.835 10 10 0 0 0-10-10z" transform="translate(0,1)" fill="'+sechandColour+'" "'+dum+'" />'+
'</svg>';
secHand.innerHTML = secsvg;
secContainer.appendChild(secHand);
var secShad = secContainer.cloneNode(true);
dial.appendChild(secShad);
genShadKillClone(secShad,secsvg, 0, 5);
var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(112)+'px;'
+'width: '+xy(112)+'px;'
+'margin: auto; top: 0; bottom: 0; left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'background-image: url("http://i61.tinypic.com/300xjcn.png");'
+'background-size: cover;'
+'opacity: 0.3;'
+'z-index: 55;'
+'overflow: hidden;');
innerRim.appendChild(glass);
function clock() {
var x = new Date();
var StopToGo = (Math.min((x.getSeconds() + x.getMilliseconds() / 1000) * (60 / 58.5), 60));
var presmin = x.getMinutes();
if (presmin !== prevmin) {
mincr++;
}
prevmin = presmin;
secContainer.style.transform = 'rotate(' + (StopToGo * 6) + 'deg) translateZ(0)';
secShad.style.transform = 'rotate(' + (StopToGo * 6) + 'deg) translateZ(0)';
minContainer.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
minShad.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
houContainer.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
houShad.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
tmr = setTimeout(clock, mls);
}
window.addEventListener('load', clock, false);
})();
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Hilfiker MobaTime Swiss Railway Clock</title>
<style type="text/css">
body {
background-color: rgb(205,179,139);
text-align: center;
}
</style>
</head>
<body>
</body>
</html>

Deutsche Bahn Clock - Modern.
(function () {
/*
Deutsche Bahn Clock
kurt.grigg#yahoo.co.uk
*/
/* ^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^ */
var clockSize = 300;
var caseColour = 'rgb(0,0,120)';
var dialColour = 'rgba(235,240,240,1.0)';
var sechandColour = 'rgba(173,26,20,1.0)';
var handColour = 'rgb(30,30,30)';
var markColour = 'rgb(10,10,10)';
var handShadowColour = 'rgba(0,0,0,0.3)';
var reflection = '6Reflection.png';
var clockShape = 50;
/* (max) 50 = round (min) 0 = square */
/* ^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^ */
var d = document;
var mrkrs = [];
var tmr;
var mls = 50;
var broff = (clockShape < 20) ? 2 : 0;
var prevmin;
var mincr = new Date().getMinutes() - 1;
var hincr = new Date().getHours();
var rnd = 'id'+Math.random() * 1;
var dum = '';
var cbcbzr = '.3s cubic-bezier(0.666, 1.91, 0.333, 0)';
var vb = '<svg height="'+xy(100)+'" width="'+xy(100)+'" viewBox="0 0 200 200">';
d.write('<div id = "'+rnd+'" style="display:inline-block;line-height:0px;"></div>');
function xy (v) {
return (v * clockSize / 100);
}
function genShadKillClone(c, v, x, y) {
c.style.left = xy(x)+'px';
c.style.top = xy(y)+'px';
c.style.zIndex--;
var s = 'filter="url(#handShadow)"';
var r = v.split('filter="url()"').join("");
r = r.replace(/""/g, s);
c.innerHTML = r;
}
/* Clock case and dial */
var outerRim = d.createElement('div');
outerRim.setAttribute('style', 'display:inline-block;'
+'position: relative;'
+'height: '+xy(115)+'px;'
+'width: '+xy(115)+'px;'
+'background-image: linear-gradient(to left, '
+'rgba(0,0,0,0.6) 5%, '
+'rgba(255,255,255,0.2) 50%, '
+'rgba(0,0,0,0.6) 95%);'
+'background-color: '+caseColour+';'
+'border: '+xy(0.5)+'px solid transparent;'
+'box-shadow: inset 0 0 '+xy(2)+'px '+xy(0.3)+'px rgba(255,255,255,0.5),'
+' 0 '+xy(6)+'px '+xy(1)+'px -'+xy(1)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;');
d.getElementById(rnd).appendChild(outerRim);
var innerRim = d.createElement('div');
innerRim.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(109.8)+'px;'
+'width: '+xy(109.8)+'px;'
+'background-color: '+dialColour+';'
+'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
+'box-shadow: inset 0 0 0 '+xy(3.0)+'px rgba(50,50,50,0.15),'
+'inset 0 '+xy(6)+'px '+xy(5)+'px '+xy(4)+'px rgba(0,0,0,0.4);'
+'border-radius: '+clockShape+'%;'
+'border: '+xy(0.2)+'px solid rgba(255,255,255,0.05);');
outerRim.appendChild(innerRim);
var dial = d.createElement('div');
dial.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'px;'
+'margin: auto; top: 0; bottom: 0;left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'overflow: hidden;');
innerRim.appendChild(dial);
/* Clock markers */
var face = '<svg id="DBClock" xmlns="http://www.w3.org/2000/svg"'+
'viewBox="0 0 200 200" width="100%" height="100%">'+
'<defs>'+
'<clipPath id="dialPath">'+
'<circle cx="100" cy="100" r="100"/>'+
'</clipPath>'+
'</defs>'+
'<filter id="handShadow" color-interpolation-filters="sRGB">'+
'<feFlood result="flood" flood-color="#000" flood-opacity=".4"/>'+
'<feComposite result="composite1" operator="in" in2="SourceGraphic" in="flood"/>'+
'<feGaussianBlur result="blur" stdDeviation="0.5" in="composite1"/>'+
'<feOffset result="offset" dy="0" dx="0"/>'+
'<feComposite result="composite2" operator="atop" in2="offset" in="offset"/>'+
'</filter>'+
'<g id="DBLogo" transform="translate(89.2,35.5) scale(0.5, 0.5)">'+
'<path fill="none" d="M40.26 27.83H2.49V1.964h37.77V27.83z"/>'+
'<path fill="'+sechandColour+'" fill-rule="evenodd" d="M5.916'+
' 5.233h7.566c4.72 0 7.494 3.044 7.494 9.614 0 6.997-2.9 9.8-'+
'7.494 9.8H5.916V5.232zm17.18 0h8.46c3.542 0 5.32 2.134 5.32 '+
'4.594 0 3.228-1.892 4.323-3.356 4.636v.085c2.19.285 4.167 1.'+
'835 4.167 4.807-.015 3.2-2.333 5.29-6.656 5.29h-7.935V5.234z'+
'm-12.5 3.044h1.663c2.687 0 4.11 1.934 4.11 6.485 0 5.22-1.66'+
'5 6.783-4.026 6.783h-1.75V8.277zm17.136-.03h1.79c1.836 0 2.5'+
'9 1.025 2.59 2.22 0 1.45-.782 2.46-2.617 2.46h-1.763v-4.68zm'+
'0 8.335h2.204c2.176 0 2.76 1.052 2.76 2.432 0 1.607-1.167 2.'+
'53-2.732 2.53h-2.232v-4.962zM4.394 0h34.203c2.432 0 4.408 1.'+
'963 4.408 4.394v20.99c0 2.433-1.976 4.41-4.408 4.41H4.394c-2'+
'.43 0-4.394-1.977-4.394-4.41V4.395C0 1.964 1.963 0 4.394 0zm'+
'.057 3h34.104c.754 0 1.365.612 1.365 1.366v21.048c0 .753-.61'+
'2 1.365-1.366 1.365H4.45c-.752 0-1.364-.613-1.364-1.366V4.36'+
'6C3.086 3.612 3.698 3 4.45 3"/></g></svg>';
dial.innerHTML = face;
for (var i = 0; i < 60; i++) {
var mrkrLength = 30;
if (i % 15) {
mrkrLength = 24;
}
if (i % 5) {
mrkrLength = 8;
}
var mrkrWidth = (i % 5) ? 3.6 : 8.8;
mrkrs[i] = document.createElementNS("http://www.w3.org/2000/svg", 'line');
with(mrkrs[i]) {
setAttribute('x1', '100');
setAttribute('y1', '0');
setAttribute('x2', '100');
setAttribute('y2', mrkrLength);
setAttribute('stroke', markColour);
setAttribute('stroke-width', mrkrWidth);
setAttribute('stroke-linecap', 'butt');
setAttribute("clip-path", "url(#dialPath)");
setAttribute( "transform","rotate("+i * 6+", 100, 100)");
}
DBClock.appendChild(mrkrs[i]);
}
/* Generic container for all hands */
var handContainers = 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'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 */
var houContainer = d.createElement('div');
houContainer.setAttribute('style', handContainers + 'transition: '+cbcbzr+';');
houContainer.style.zIndex = 50;
dial.appendChild(houContainer);
var houHand = d.createElement('div');
var housvg = vb +
'<rect x="95" y="40" width="10" height="58" stroke="none" fill="'+handColour+'" "'+dum+'" />'+
'</svg>';
houHand.innerHTML = housvg;
houContainer.appendChild(houHand);
var houShad = houContainer.cloneNode(true);
dial.appendChild(houShad);
genShadKillClone(houShad,housvg, 0, 3);
/* Minute hand */
var minContainer = d.createElement('div');
minContainer.setAttribute('style',handContainers + 'transition: '+cbcbzr+';');
minContainer.style.zIndex = 52;
dial.appendChild(minContainer);
var minHand = d.createElement('div');
var minsvg = vb +
'<rect x="96" y="6" width="8" height="92" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
minHand.innerHTML = minsvg;
minContainer.appendChild(minHand);
var minShad = minContainer.cloneNode(true);
dial.appendChild(minShad);
genShadKillClone(minShad,minsvg, 0, 4);
/* Seconds hand */
var secContainer = d.createElement('div');
secContainer.setAttribute('style',handContainers);
secContainer.style.zIndex = 54;
dial.appendChild(secContainer);
var secHand = d.createElement('div');
var secsvg = vb +
'<path d="M98 2l-.275 29.223C92.2 32.293 88 37.173 88 43c0 5.744 4'+
'.084 10.57 9.492 11.73L97 100h6l-.482-45.27C107.92 53.563 112 48.'+
'74 112 43c0-5.826-4.203-10.707-9.727-11.777L102 2h-4zm2 33c4.442 '+
'0 8 3.558 8 8s-3.558 8-8 8-8-3.558-8-8 3.558-8 8-8z" fill="'+sechandColour+'" "'+dum+'"/></svg>';
secHand.innerHTML = secsvg;
secContainer.appendChild(secHand);
var secShad = secContainer.cloneNode(true);
dial.appendChild(secShad);
genShadKillClone(secShad,secsvg, 0, 5);
var nut = d.createElement('div');
nut.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(10)+'px;'
+'width: '+xy(10)+'px;'
+'border-radius: 50%;'
+'margin: auto;top: 0;bottom: 0;left: 0;right: 0;'
+'background: '+handColour+';'
+'box-shadow: 0 '+xy(2)+'px '+xy(1)+'px rgba(0,0,0,0.35);'
+'z-index: 56;');
innerRim.appendChild(nut);
var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(108.8)+'px;'
+'width: '+xy(108.8)+'px;'
+'margin: auto; top: 0; bottom: 0; left: 0;right: 0;'
+'border: '+xy(0.2)+'px solid #000;'
+'border-radius: '+clockShape+'%;'
+'background-image: url("http://i61.tinypic.com/300xjcn.png");'
+'background-size: cover;'
+'opacity: 0.25;'
+'z-index: 57;'
+'overflow: hidden;');
innerRim.appendChild(glass);
function clock() {
var x = new Date();
var time = Math.min(60000, 1.025 * (1000 * x.getSeconds() + x.getMilliseconds()));
var seconds = Math.floor(time / 1000);
var millis = time % 1000;
var germanSec = (6 * seconds + 3 * (1 + Math.cos(Math.PI + Math.PI * (0.001 * millis))));
var presmin = x.getMinutes();
if (presmin !== prevmin) {
mincr++;
}
prevmin = presmin;
secContainer.style.transform = 'rotate(' + germanSec + 'deg) translateZ(0)';
secShad.style.transform = 'rotate(' + germanSec + 'deg) translateZ(0)';
minContainer.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
minShad.style.transform = 'rotate(' + (mincr * 6) + 'deg) translateZ(0)';
houContainer.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
houShad.style.transform = 'rotate(' + ((hincr * 30) + (mincr / 2)) + 'deg) translateZ(0)';
tmr = setTimeout(clock, mls);
}
window.addEventListener('load', clock, false);
})();
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Deutsche Bahn Clock</title>
<style type="text/css">
body {
background-color: rgb(205,179,139);
text-align: center;
}
</style>
</head>
<body>
</body>
</html>

The Hilfiker/MobaTime Swiss Railway Clock
Exaggerated step and bounce on all hands
(function () {
/*
The Hilfiker/MobaTime Swiss Railway Clock
1953 version (Stop To Go)
(Exaggerated) step and bounce on all hands
kurt.grigg#yahoo.co.uk
*/
/* ^^^^^^^^^^^^^^ Config below ^^^^^^^^^^^^^^ */
var clockSize = 300;
var caseColour = 'rgba(200,200,200,1.0)';
var dialColour = 'rgba(235,240,240,1.0)';
var sechandColour = 'rgba(173,26,20,1.0)';
var handColour = 'rgb(20,20,20)';
var markColour = 'rgb(10,10,10)';
var handShadowColour = 'rgba(0,0,0,0.3)';
var reflection = '6Reflection.png';
var clockShape = 50;
/* (max) 50 = round (min) 0 = square */
/* ^^^^^^^^^^^^^^^^ End config ^^^^^^^^^^^^^^ */
var mls = 100;
var secSpan = '.8s';
var minSpan = '1.0s';
var houSpan = '1.2s';
var secIncr = 0;
var minIncr = 0;
var houIncr = 0;
var d = document;
var mrkrs = [];
var broff = (clockShape < 20) ? 2 : 0;
var rndId = 'id'+Math.random() * 1;
var idx = d.getElementsByTagName('div').length;
var secDeg, minDeg, houDeg, preSec, preMin, preHou;
var rnd = 'id'+Math.random() * 1;
var dum = '';
var vb = '<svg height="'+xy(100)+'" width="'+xy(100)+'" viewBox="0 0 200 200">';
var mobasec = new Date().getSeconds();
var mobaoffset = (58.5/60);
var initcyc = mobaoffset * mobasec;
var mobacycle = 1000 - initcyc;
var tmr, mobaTimer;
var firstrun = true;
var eiatf = 'translateZ(0); animation-timing-function: ease-in';
var eoatf = 'translateZ(0); animation-timing-function: ease-out';
d.write('<div id = "'+rnd+'" style="display:inline-block;line-height:0px;"></div>');
function xy (v) {
return (v * clockSize / 100);
}
function genShadKillClone(c, v, x, y) {
c.style.left = xy(x)+'px';
c.style.top = xy(y)+'px';
c.style.zIndex--;
var s = 'filter="url(#handShadow)"';
var r = v.split('filter="url()"').join("");
r = r.replace(/""/g, s);
c.innerHTML = r;
}
/* Clock case and dial */
var outerRim = d.createElement('div');
outerRim.setAttribute('style', 'display:inline-block;'
+'position: relative;'
+'height: '+xy(116)+'px;'
+'width: '+xy(116)+'px;'
+'background-image: linear-gradient(to left, '
+'rgba(0,0,0,0.3) 0%, '
+'rgba(255,255,255,0.6) 50%, '
+'rgba(0,0,0,0.3) 100%);'
+'background-color: '+caseColour+';'
+'border: '+xy(1)+'px solid transparent;'
+'box-shadow: 0 0 '+xy(0.5)+'px '+xy(0.05)+'px rgba(255,255,255,0.7), '
+'0 '+xy(6)+'px '+xy(1)+'px -'+xy(1)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;');
d.getElementById(rnd).appendChild(outerRim);
var innerRim = d.createElement('div');
innerRim.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(113.8)+'px;'
+'width: '+xy(113.8)+'px;'
+'background-color: '+dialColour+';'
+'margin: auto; top: 0;bottom: 0;left: 0;right: 0;'
+'box-shadow: inset 0 0 0 '+xy(2.9)+'px rgba(30,30,30,0.3),'
+'inset 0 '+xy(3)+'px '+xy(5)+'px '+xy(3)+'px rgba(0,0,0,0.6);'
+'border-radius: '+clockShape+'%;'
+'border: '+xy(0.2)+'px solid rgba(255,255,255,0.05);');
outerRim.appendChild(innerRim);
var dial = d.createElement('div');
dial.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'px;'
+'margin: auto; top: 0; bottom: 0;left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'overflow: hidden;');
innerRim.appendChild(dial);
/* Clock markers */
var face = '<svg id="MobaTimeClock" xmlns="http://www.w3.org/2000/svg"'+
'viewBox="0 0 200 200" width="100%" height="100%">'+
'<defs>'+
'<clipPath id="dialPath">'+
'<circle cx="100" cy="100" r="100"/>'+
'</clipPath>'+
'</defs>'+
'<filter id="handShadow" color-interpolation-filters="sRGB">'+
'<feFlood result="flood" flood-color="#000" flood-opacity=".4"/>'+
'<feComposite result="composite1" operator="in" in2="SourceGraphic" in="flood"/>'+
'<feGaussianBlur result="blur" stdDeviation="0.5" in="composite1"/>'+
'<feOffset result="offset" dy="0" dx="0"/>'+
'<feComposite result="composite2" operator="atop" in2="offset" in="offset"/>'+
'</filter>'+
'</svg>';
dial.innerHTML = face;
for (var i = 0; i < 60; i++) {
var mrkrLength = (i % 5) ? 7.5 : 25;
var mrkrWidth = (i % 5) ? 3 : 7.5;
mrkrs[i] = document.createElementNS("http://www.w3.org/2000/svg", 'line');
with(mrkrs[i]) {
setAttribute('x1', '100');
setAttribute('y1', '0');
setAttribute('x2', '100');
setAttribute('y2', mrkrLength);
setAttribute('stroke', markColour);
setAttribute('stroke-width', mrkrWidth);
setAttribute('stroke-linecap', 'butt');
setAttribute("clip-path", "url(#dialPath)");
setAttribute( "transform","rotate("+i * 6+", 100, 100)");
}
MobaTimeClock.appendChild(mrkrs[i]);
}
var logo = '<svg width="100%" height="100%" viewBox="0 0 160 106" ' +
'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
'<path d="M72.764.744C74.936.347 77.136 0 79.35.052c.94.017 1.88.01 2.82.08 4.8' +
'35.364 9.615 1.48 14.098 3.357 4.685 1.99 9.022 4.85 12.635 8.467 3.488 3.46 6' +
'.303 7.605 8.27 12.123 1.837 4.26 2.964 8.834 3.284 13.47.3 4.69-.077 9.427-1.' +
'208 13.988-.398 1.737-.95 3.43-1.494 5.126-3.685-2.417-7.306-4.932-10.977-7.37' +
'.638-2.657 1.03-5.388.955-8.128-.032-2.894-.504-5.78-1.35-8.545-1.36-4.383-3.75' +
'-8.47-7.038-11.658-3.758-3.765-8.715-6.24-13.914-7.168-2.006-.367-4.047-.537-6' +
'.083-.51-2.38.167-4.755.56-7.04 1.256-.07.018-.212.05-.282.067-4.875 1.52-9.37' +
' 4.36-12.692 8.292-3.532 4.122-5.726 9.365-6.367 14.77-.3 2.187-.26 4.41-.16 6' +
'.61.152 1.61.355 3.218.707 4.797-3.644 2.364-7.266 4.76-10.93 7.09-1.812-4.79-' +
'2.977-9.862-3.083-15.002-.237-8.587 2.43-17.226 7.466-24.152C51.114 11.27 56.7' +
'94 6.69 63.212 3.79c3.06-1.366 6.266-2.402 9.552-3.046z" fill-opacity=".9" fill="'+markColour+'"/>' +
'<path d="M48.772 76.595L55.83 71.9l1.774 1.816c1.023 1.047 2.286 2.145 2.984 2' +
'.595 5.233 3.37 12.434 5.067 20.513 4.835 3.703-.106 5.01-.245 8.036-.856 2.72' +
'-.55 5.2-1.387 7.582-2.557 2.47-1.213 4.22-2.505 5.976-4.41l1.357-1.47 7.045 4' +
'.715 7.045 4.715 11.09.06c6.934.038 11.03.002 10.926-.096-.828-.782-35.83-26.7' +
'53-35.916-26.648-4.85 5.9-8.918 9.252-13.73 11.313-3.472 1.487-6.387 2.055-10.' +
'566 2.058-9.514.007-16.507-3.84-24.292-13.368-.08-.096-31.817 23.46-35.66 26.4' +
'67-.395.308-.217.312 10.66.266l11.064-.047 7.056-4.695z" fill="url(#a)"/>' +
'<path d="M81.42 90.82h-3.505l-5.58 15.26h3.473l1.078-2.32 5.597.02 1.08 2.302h' +
'3.32l-5.462-15.26zm-1.717 4.213l1.667 5.944h-3.285l1.618-5.944zm-22.434-4.23h-' +
'5.174v15.26l6.303.016c1.6.02 3.624-1.607 3.994-3.73.084-2.25-.845-4.16-2.376-4' +
'.446.876-.41 1.45-1.89 1.348-3.854-.238-1.944-2.26-3.392-4.097-3.248m.976 3.73' +
'c.353.662.153 1.337-.05 1.837-.656.768-1.837.714-2.78.714v-3.302c.842 0 2.308-' +
'.16 2.83.75m.625 5.747c.37.606.286 1.73.103 2.16-.893.998-2.16.962-3.523.8v-3.' +
'604c1.618-.108 2.46-.09 3.42.643M15.118 90.8l2.41 15.24-3 .037-1.432-8.89-3.75' +
'8 8.89-.926-.037-3.675-8.496-1.517 8.532L0 106.042l2.36-15.277h3.17l3.166 8.744' +
' 3.42-8.708h3zm19.23 11.673c-2.29 0-4.18-2-4.18-4.427 0-2.427 1.89-4.425 4.18-' +
'4.425 2.293 0 4.18 1.998 4.18 4.425 0 2.426-1.887 4.427-4.18 4.427m0 3.604c4.2' +
'8 0 7.77-3.605 7.77-8.032 0-4.425-3.49-8.048-7.77-8.048-4.28 0-7.768 3.623-7.7' +
'68 8.048 0 4.427 3.488 8.03 7.768 8.03M98.68 91.482h8.56l-.285 1.68h-3.49l-1.8' +
'87 12.883h-1.754l1.924-12.884h-3.374l.306-1.68zm18.623 0h1.753l-2.19 14.563h-1' +
'.738l2.175-14.562zm24.506-1.017l.756 15.58h-1.99l-.115-9.94-5.898 10.242-2.715' +
'-10.242-3.166 9.94h-1.972l5.444-15.58 3 11.796 6.657-11.797zm18.236 1.018l-.43' +
'8 1.68h-5.648l-.608 4.086h5.546l-.32 1.66h-5.494l-.876 5.46h5.798l-.286 1.677h' +
'-7.55l2.174-14.562h7.702z" fill-opacity="1.0" fill="'+markColour+'"/>' +
'<defs>' +
'<pattern xlink:href="#b" id="a" patternTransform="translate(364.52 610.068) scale(6.07904)"/>' +
'<pattern id="b" patternTransform="scale(10)" height="1" width="1.07" patternUnits="userSpaceOnUse">' +
'<path fill="'+markColour+'" d="M0 0h.5v1H0z"/>' +
'</pattern>' +
'</defs>' +
'</svg>';
var mtl = d.createElement('div');
mtl.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(9)+'px;'
+'top: '+xy(68)+'px;'
+'paddingBottom: '+xy(1)+'px;'
+'margin: auto; left: 0;right: 0;');
mtl.innerHTML = logo;
dial.appendChild(mtl);
/* Generic container for all hands */
var handContainers = 'display: block;'
+'position: absolute;'
+'height: '+xy(100)+'px;'
+'width: '+xy(100)+'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 */
var houClone = handContainers;
var houContainer = d.createElement('div');
houContainer.setAttribute('style', houClone);
houContainer.style.zIndex = 50;
dial.appendChild(houContainer);
var houHand = d.createElement('div');
var housvg = vb +
'<polygon points="95,33 105,33 106,125 94,125" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
houHand.innerHTML = housvg;
houContainer.appendChild(houHand);
var houShad = houContainer.cloneNode(true);
dial.appendChild(houShad);
genShadKillClone(houShad,housvg, 0, 3);
/* Minute hand */
var minClone = handContainers;
var minContainer = d.createElement('div');
minContainer.setAttribute('style',minClone);
minContainer.style.zIndex = 52;
dial.appendChild(minContainer);
var minHand = d.createElement('div');
var minsvg = vb +
'<polygon points="96,5 104,5 105,125 95,125" fill="'+handColour+'" stroke="none" "'+dum+'" />'+
'</svg>';
minHand.innerHTML = minsvg;
minContainer.appendChild(minHand);
var minShad = minContainer.cloneNode(true);
dial.appendChild(minShad);
genShadKillClone(minShad,minsvg, 0, 4);
/* Seconds hand */
var secClone = handContainers;
var secContainer = d.createElement('div');
secContainer.setAttribute('style',secClone);
secContainer.style.zIndex = 54;
dial.appendChild(secContainer);
var secHand = d.createElement('div');
var secsvg = vb +
'<path d="M100 23.475a10 10 0 0 0-10 10 10 10 0 0 0 8.22 9.832V135h3.56V43.31a10 10 0 0 0 8.22-9.835 10 10 0 0 0-10-10z" fill="'+sechandColour+'" "'+dum+'" />'+
'</svg>';
secHand.innerHTML = secsvg;
secContainer.appendChild(secHand);
var secShad = secContainer.cloneNode(true);
dial.appendChild(secShad);
genShadKillClone(secShad,secsvg, 0, 5);
/* Clock glass */
var glass = d.createElement('div');
glass.setAttribute('style', 'display: block;'
+'position: absolute;'
+'height: '+xy(112)+'px;'
+'width: '+xy(112)+'px;'
+'margin: auto; top: 0; bottom: 0; left: 0;right: 0;'
+'border-radius: '+clockShape+'%;'
+'background-image: url("http://i61.tinypic.com/300xjcn.png");'
+'background-size: cover;'
+'opacity: 0.3;'
+'z-index: 55;'
+'overflow: hidden;');
innerRim.appendChild(glass);
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 s'+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: s'+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(5)+'px';
secShad.style.left = xy(0)+'px';
}
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 m'+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: m'+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(4)+'px';
minShad.style.left = xy(0)+'px';
}
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 h'+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: h'+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(3)+'px';
houShad.style.left = xy(0)+'px';
}
function mobaSeconds() {
mobasec++;
secIncr++;
secDeg = (mobasec-1) * 6;
secHand.removeAttribute('style');
secKeyFrames();
if (secIncr > 59) {
secIncr = 0;
}
mobaTimer = setTimeout(mobaSeconds, mobacycle);
if (mobasec > 59) {
clearTimeout(mobaTimer);
mobasec = 0;
firstrun = false;
}
}
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) {
mobacycle -= mobaoffset;
if (!firstrun && seconds == 1) {
mobaSeconds();
}
}
if (minutes !== preMin) {
if (firstrun) {
mobaSeconds();
}
if (!firstrun) {
mobacycle = 1000-mobaoffset;
}
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;
tmr = setTimeout(clock, mls);
}
window.addEventListener('load', clock, false);
})();
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Hilfiker/MobaTime Swiss Railway Clock</title>
<style type="text/css">
body {
background-color: rgb(205,179,139);
text-align: center;
}
</style>
</head>
<body>
</body>
</html>

Related

more chaotic upward movement

I have a heart movement on my page starting from the bottom of the page. Each randomly generates the size and speed of movement.
How can I make them, instead of appearing at the bottom of the page, appear when you click on the specified place, and move not evenly, but more chaotically and disappear before reaching the end?
var love = setInterval(function() {
var r_num = Math.floor(Math.random() * 40) + 1;
var r_size = Math.floor(Math.random() * 30) + 10;
var r_left = Math.floor(Math.random() * 100) + 1;
var r_time = Math.floor(Math.random() * 5) + 5;
$('.bg_heart').append("<div class='heart' style='width:" + r_size + "px;height:" + r_size + "px;left:" + r_left + "%;background:#ff94a7;-webkit-animation:love " + r_time + "s ease;-moz-animation:love " + r_time + "s ease;-ms-animation:love " + r_time + "s ease;animation:love " + r_time + "s ease'></div>");
$('.bg_heart').append("<div class='heart' style='width:" + (r_size - 10) + "px;height:" + (r_size - 10) + "px;left:" + (r_left + r_num) + "%;background:#ff94a7;-webkit-animation:love " + (r_time + 5) + "s ease;-moz-animation:love " + (r_time + 5) + "s ease;-ms-animation:love " + (r_time + 5) + "s ease;animation:love " + (r_time + 5) + "s ease'></div>");
$('.heart').each(function() {
var top = $(this).css("top").replace(/[^-\d\.]/g, '');
var width = $(this).css("width").replace(/[^-\d\.]/g, '');
if (top <= -100 || width >= 150) {
$(this).detach();
}
});
}, 500);
html,body{
height:100%
}
.bg_heart {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden
}
.heart {
position: absolute;
top: -50%;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-m-transform: rotate(-45deg);
transform: rotate(-45deg)
}
.heart:before {
position: absolute;
top: -50%;
left: 0;
display: block;
content: "";
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
}
.heart:after {
position: absolute;
top: 0;
right: -50%;
display: block;
content: "";
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
}
#-webkit-keyframes love {
0%{top:110%}
}
#-moz-keyframes love {
0%{top:110%}
}
#-ms-keyframes love {
0%{top:110%}
}
#keyframes love {
0%{top:110%}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="header-plugin"></div>
<div class="bg_heart"></div>
To fly more chaotically use setInterval. You can also change the speed to whatever you need.
var brd = document.createElement("DIV");
document.body.insertBefore(brd, document.getElementById("board"));
const duration = 3000;
const speed = 0.5;
const cursorXOffset = 0;
const cursorYOffset = -5;
var hearts = [];
function generateHeart(x, y, xBound, xStart, scale)
{
var heart = document.createElement("DIV");
heart.setAttribute('class', 'heart');
brd.appendChild(heart);
heart.time = duration;
heart.x = x;
heart.y = y;
heart.bound = xBound;
heart.direction = xStart;
heart.style.left = heart.x + "px";
heart.style.top = heart.y + "px";
heart.scale = scale;
heart.style.transform = "scale(" + scale + "," + scale + ")";
if(hearts == null)
hearts = [];
hearts.push(heart);
return heart;
}
var down = false;
var event = null;
document.onmousedown = function(e) {
down = true;
event = e;
}
document.onmouseup = function(e) {
down = false;
}
document.onmousemove = function(e) {
event = e;
}
document.ontouchstart = function(e) {
down = true;
event = e.touches[0];
}
document.ontouchend = function(e) {
down = false;
}
document.ontouchmove = function(e) {
event = e.touches[0];
}
var before = Date.now();
var id = setInterval(frame, 5);
var gr = setInterval(check, 100);
function frame()
{
var current = Date.now();
var deltaTime = current - before;
before = current;
for(i in hearts)
{
var heart = hearts[i];
heart.time -= deltaTime;
if(heart.time > 0)
{
heart.y -= speed;
heart.style.top = heart.y + "px";
heart.style.left = heart.x + heart.direction * heart.bound * Math.sin(heart.y * heart.scale / 30) / heart.y * 100 + "px";
}
else
{
heart.parentNode.removeChild(heart);
hearts.splice(i, 1);
}
}
}
function check()
{
if(down)
{
var start = 1 - Math.round(Math.random()) * 2;
var scale = Math.random() * Math.random() * 0.8 + 0.2;
var bound = 30 + Math.random() * 20;
generateHeart(event.pageX - brd.offsetLeft + cursorXOffset, event.pageY - brd.offsetTop + cursorYOffset, bound, start, scale);
}
}
html,body{
height:100%
}
#keyframes heartfade {
0% {
opacity : 1;
}
50% {
opacity : 0;
}
}
.heart {
z-index : 999;
animation : heartfade 6s linear;
position : absolute;
}
.heart:before,
.heart:after {
content : "";
background-color : #ff94a7;
position : absolute;
height : 30px;
width : 45px;
border-radius : 15px 0px 0px 15px;
}
.heart:before {
transform : rotate(45deg);
}
.heart:after {
left : 10.5px;
transform : rotate(135deg);
}

Draw a line from one element to multiple elements on click

I'm trying to draw a line from an element [.identifier] to the clicked element [ A, B, C series ]. I'm able to display the line but in the other direction, not sure why it is displaying in such a direction.
Here is my fiddle: https://jsfiddle.net/SampathPerOxide/u2afymxs/11/
Can someone help me to display a line between ".identifier" and the respective series element?
Expected result on clicking A series:
on clicking B series:
$('.seriesli').click(function() {
function adjustLine(from, to, line) {
var fT = from.offsetTop + from.offsetHeight / 2;
var tT = to.offsetTop + to.offsetHeight / 2;
var fL = from.offsetLeft + from.offsetWidth / 2;
var tL = to.offsetLeft + to.offsetWidth / 2;
var CA = Math.abs(tT - fT);
var CO = Math.abs(tL - fL);
var H = Math.sqrt(CA * CA + CO * CO);
var ANG = 180 / Math.PI * Math.acos(CA / H);
if (tT > fT) {
var top = (tT - fT) / 2 + fT;
} else {
var top = (fT - tT) / 2 + tT;
}
if (tL > fL) {
var left = (tL - fL) / 2 + fL;
} else {
var left = (fL - tL) / 2 + tL;
}
if ((fT < tT && fL < tL) || (tT < fT && tL < fL) || (fT > tT && fL > tL) || (tT > fT && tL > fL)) {
ANG *= -1;
}
top -= H / 2;
line.style["-webkit-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-moz-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-ms-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-o-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-transform"] = 'rotate(' + ANG + 'deg)';
line.style.top = top + 'px';
line.style.left = left + 'px';
line.style.height = H + 'px';
}
adjustLine(
document.getElementById('div1'),
document.getElementById('div2'),
document.getElementById('line')
);
});
.identifier {
width: 10px;
height: 10px;
background-color: red;
position: absolute;
right: 45%;
top: 50%;
}
.series-div {
position: absolute;
right: 5%;
bottom: 30%;
}
.series-ul li {
list-style: none;
color: grey;
font-size: 1em;
font-weight: 600;
border: 2px solid grey;
display: table;
padding: 0.3em 0.1em;
text-align: center;
margin: 0.5em;
cursor: pointer;
}
#line {
position: absolute;
width: 2px;
margin-top: -1px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="position;relative;">
<div class="identifier" id="div2"></div>
<div class="series-div">
<ul class="series-ul">
<li class="seriesli" id="div1">A series</li>
<li class="seriesli">B series</li>
<li class="seriesli">C series</li>
</ul>
</div>
<div id="line"></div>
<img src="https://stat.overdrive.in/wp-content/odgallery/2020/06/57263_2020_Mercedes_Benz_GLS.jpg" class="img-responsive firstcar-detail" style="width: 100%;">
</div>
I fixed your fiddle: https://jsfiddle.net/c4ju6a0p/
Code changes:
// Get actual position relative to viewport.
// See https://stackoverflow.com/a/11396681/117030
fromBCR = from.getBoundingClientRect();
toBCR = to.getBoundingClientRect();
var fT = fromBCR.top + from.offsetHeight / 2;
var tT = toBCR.top + to.offsetHeight / 2;
// Don't add offsetWidth. This connects to the middle, not the left edge.
var fL = fromBCR.left //+ from.offsetWidth / 2;
var tL = toBCR.left + to.offsetWidth / 2;
The problem was the line was being calculated with the incorrect position due to relative positioning. This can be seen more clearly when the relative CSS is commented out: https://jsfiddle.net/vust5nxf/
Also, don't add the offsetWidth if you want the line to go to the left edge.
update: didn't notice the code snippet... applied changes there, too. I also made one more change:
You need to pass the element that was clicked to adjustLine(), otherwise currently the line is drawn between the same two elements every time because the elements are hardcoded with ids.
As a style note: I would move the definition of function adjustLine() outside the click handler. This will make the code easier to read, and the function will only be created once, instead of every time a click is handled.
adjustLine(
this, // Element that was clicked.
document.getElementById('div2'),
document.getElementById('line')
);
$('.seriesli').click(function() {
function adjustLine(from, to, line) {
// Get actual position relative to viewport.
// See https://stackoverflow.com/a/11396681/117030
fromBCR = from.getBoundingClientRect();
toBCR = to.getBoundingClientRect();
var fT = fromBCR.top + from.offsetHeight / 2;
var tT = toBCR.top + to.offsetHeight / 2;
// Don't add offsetWidth. This connects to the middle, not the left edge.
var fL = fromBCR.left //+ from.offsetWidth / 2;
var tL = toBCR.left + to.offsetWidth / 2;
var CA = Math.abs(tT - fT);
var CO = Math.abs(tL - fL);
var H = Math.sqrt(CA * CA + CO * CO);
var ANG = 180 / Math.PI * Math.acos(CA / H);
if (tT > fT) {
var top = (tT - fT) / 2 + fT;
} else {
var top = (fT - tT) / 2 + tT;
}
if (tL > fL) {
var left = (tL - fL) / 2 + fL;
} else {
var left = (fL - tL) / 2 + tL;
}
if ((fT < tT && fL < tL) || (tT < fT && tL < fL) || (fT > tT && fL > tL) || (tT > fT && tL > fL)) {
ANG *= -1;
}
top -= H / 2;
line.style["-webkit-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-moz-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-ms-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-o-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-transform"] = 'rotate(' + ANG + 'deg)';
line.style.top = top + 'px';
line.style.left = left + 'px';
line.style.height = H + 'px';
}
adjustLine(
this, // Element that was clicked.
document.getElementById('div2'),
document.getElementById('line')
);
});
.identifier {
width: 10px;
height: 10px;
background-color: red;
position: absolute;
right: 45%;
top: 50%;
}
.series-div {
position: absolute;
right: 5%;
bottom: 30%;
}
.series-ul li {
list-style: none;
color: grey;
font-size: 1em;
font-weight: 600;
border: 2px solid grey;
display: table;
padding: 0.3em 0.1em;
text-align: center;
margin: 0.5em;
cursor: pointer;
}
#line {
position: absolute;
width: 2px;
margin-top: -1px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="position;relative;">
<div class="identifier" id="div2"></div>
<div class="series-div">
<ul class="series-ul">
<li class="seriesli" id="div1">A series</li>
<li class="seriesli">B series</li>
<li class="seriesli">C series</li>
</ul>
</div>
<div id="line"></div>
<img src="https://stat.overdrive.in/wp-content/odgallery/2020/06/57263_2020_Mercedes_Benz_GLS.jpg" class="img-responsive firstcar-detail" style="width: 100%;">
</div>

controling svg clock with setInterval

I made an svg clock :
<svg baseProfile="basic" viewBox="0 0 200 200" preserveAspectRatio="xMidYMin" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="aiguilles">
<g id="heures" visibility="hidden">
<path fill="#555" d="M94.9,38.8v11l-6,8.2l6.3,9.3L95,92.9c-2.2,1.6-3.7,4.2-3.7,7.1s1.4,5.5,3.6,7l-0.1,12.7l5.3,3.5v-14.5 c0-4.6,0-13.1,0-17.5V33.9L94.9,38.8z"/>
<path fill="#bbb" d="M105,92.9l-0.2-25.6l6.3-9.3l-6-8.2v-11l-5.1-5v57.4c0,5.7,0,12,0,17.5v14.5l5.3-3.5l-0.1-12.7 c2.2-1.6,3.6-4.1,3.6-7C108.7,97.1,107.3,94.5,105,92.9z"/>
<polygon fill="#fff" points="100,69.7 92.6,58.1 100,47.5 107.4,58.1 "/>
</g>
<g id="minutes" visibility="hidden">
<path fill="#777" d="M95.6,9.7v84.9c-1.6,1.3-2.5,3.2-2.5,5.4s1,4.1,2.5,5.4v14.8l4.4,2.6V5.3L95.6,9.7z"/>
<path fill="#ddd" d="M106.9,100c0-2.1-1-4.1-2.5-5.3v-85L100,5.3V93l0,0c0,3,0,10.4,0,13.9l0,0v15.9l4.4-2.6v-14.9 C105.9,104.1,106.9,102.2,106.9,100z"/>
<polygon fill="#fff" points="97.7,17.5 97.7,69.4 100,71.9 102.3,69.4 102.3,17.5 100,15.4 "/>
</g>
<g id="secondes" visibility="hidden">
<path fill="#bbb" d="M101,95.5c0-33.1,0-54.1,0-67.4c2.5-0.5,4.4-2.7,4.4-5.3s-1.9-4.8-4.4-5.3c0-12.4,0-12.7,0-13.3 c0-0.8-0.5-1.8-1-2c-0.6,0.3-1,1.2-1,2c0,0.6,0,0.9,0,13.3c-2.5,0.5-4.4,2.7-4.4,5.3s1.9,4.8,4.4,5.3c0,13.3,0,34.3,0,67.4 c-2.2,0.5-3.8,2.4-3.8,4.7c0,1.2,0.5,2.3,1.2,3.1V122l3.7,3.3l3.7-3.3v-18.7c0.7-0.8,1.2-1.9,1.2-3.1 C104.8,97.9,103.2,95.9,101,95.5z"/>
<circle fill="#FFF" cx="100" cy="22.7" r="3.7"/>
</g>
</g>
</svg>
and I suceeded in animating the hands so that they first go from 12:00 to the current time with the "toTimeNow" function and then show the time continuously with the "timeNow" function :
var tailleAiguilles = 2;
var aiguillesGauche = 250;
var aiguillesHaut = 250;
var aiguilles = document.getElementById("aiguilles");
function transformSvg() {
aiguilles.setAttribute("transform", "matrix(" + tailleAiguilles + " 0 0 " + tailleAiguilles + " " + aiguillesGauche + " " + aiguillesHaut + ")");
}
function toTimeNow() {
var hr = 0;
var mn = 0;
var sc = 0;
var interval = setInterval(function() {
var maintenant = new Date();
var heures = maintenant.getHours();
var minutes = maintenant.getMinutes();
var secondes = maintenant.getSeconds();
var milliSecondes = maintenant.getMilliseconds();
var secondes2 = 6 * secondes;
if (heures * 30 + minutes * 0.5 > 359) {
var angleHeures = heures * 30 + minutes * 0.5 - 359;
}
else {
var angleHeures = heures * 30 + minutes * 0.5;
}
var angleMinutes = minutes * 6 + (0.1 * secondes);
var angleSecondes = secondes2 += 0.006 * milliSecondes;
var max = Math.max(angleHeures, angleMinutes, angleSecondes)
if (hr < angleHeures) {
hr += angleHeures / max * 2;
rotation('heures', hr, 100);
}
if (mn < angleMinutes) {
mn += angleMinutes / max * 2;
rotation('minutes', mn, 100);
}
if (sc < angleSecondes) {
sc += angleSecondes / max * 2;
rotation('secondes', sc, 100);
}
else {
clearInterval(interval);
timeNow();
}
}, 5);
}
function timeNow() {
setInterval(function() {
var maintenant = new Date();
var heures = maintenant.getHours();
var minutes = maintenant.getMinutes();
var secondes = maintenant.getSeconds();
var milliSecondes = maintenant.getMilliseconds();
var secondes2 = 6 * secondes;
rotation('heures', heures * 30 + minutes * 0.5, 100);
rotation('minutes', minutes * 6 + (0.1 * secondes), 100);
rotation('secondes', secondes2 += 0.006 * milliSecondes, 100);
}, 50);
}
function rotation(id, angle, centre) {
var element = document.getElementById(id);
if (element) {
element.setAttribute('transform', 'rotate(' + angle + ', ' + centre + ', ' + centre + ')');
if (element.getAttribute('visibility') == 'hidden') {
element.setAttribute('visibility', 'visible');
}
}
}
window.addEventListener('load', toTimeNow, false);
But I noticed that just before the 2nd function takes over the hands move slightly backwards. If somebody could tell me why I'd appreciate it.
It is almost certainly because of this code:
if (mn < angleMinutes) {
mn += angleMinutes / max * 2;
rotation('minutes', mn, 100);
}
If mn is slightly less than angleMinutes, then this code can result in it stepping well past it. You should check mn after you increment it.
if (mn < angleMinutes) {
mn = Math.min(angleMinutes, mn + angleMinutes / max * 2);
rotation('minutes', mn, 100);
}

Uncaught SyntaxError: Unexpected token < using for loop in video js thumbnail

i am using for loop to create thumbnail object array to shoe thumbnails on progress bar.But it gives the error of "Uncaught SyntaxError: Unexpected token <" at the for loop.Why it is giving this error?
here is the code
<script>
// initialize video.js
var video = videojs('video');
// here's an example of generating thumbnails from a sprited image:
var l=40;
var t=60;
var c=0;
var tp=0;
var rt=80;
var bt=45;
var lt=0;
var i;
var j;
var op={};
video.thumbnails({
for(i=0,j=1;i<=95;i=i+5)
{
op[i]={src: 'M'+c+'.jpg',style: {left: '-'+l+'px',width: '800px',height: '90px',top: '-'+t+'px',clip: 'rect('+tp+'px,'+ rt+'px,'+ bt+'px,'+lt+ 'px)'}}
l=l+80;
rt=rt+80;
lt=lt+80;
if(j%10==0){t=t+45;rt=80;lt=0;l=40;}
if(j%100==0)
{t=60;c=c+1;
tp=0;rt=80;bt=45;lt=0;
}
j++;
}
)}
</script>
Also i want to create thumbnail object array like this.How can i do this dynamically or using loop etc?
/*
0:{src: 'M0.jpg',style: {left: '-40px',width: '800px',height: '450px',top: '-60px',clip: 'rect(0, 80px, 45px, 0px)'}},
5:{src: 'M0.jpg',style: {left: '-120px',width: '800px',height: '450px',top: '-60px',clip: 'rect(0, 160px, 45px, 80px)'}},
10:{src: 'M0.jpg',style: {left: '-200px',width: '800px',height: '450px',top: '-60px',clip: 'rect(0, 240px, 45px, 160px)'}},
15:{src: 'M0.jpg',style: {left: '-280px',width: '800px',height: '450px',top: '-60px',clip: 'rect(0, 320px, 45px, 240px)'}},
20:{src: 'M0.jpg',style: {left: '-360px',width: '800px',height: '450px',top: '-60px',clip: 'rect(0, 400px, 45px, 320px)'}}*/
});*/
I am not sure this is what you wanted, but this code doesn't have the errors:
var video = videojs('video');
// here's an example of generating thumbnails from a sprited image:
var l = 40;
var t = 60;
var c = 0;
var tp = 0;
var rt = 80;
var bt = 45;
var lt = 0;
var i;
var j;
var op = {};
video.thumbnails((function() {
for (i = 0, j = 1; i <= 95; i = i + 5) {
op[i] = {
src: 'M' + c + '.jpg',
style: {
left: '-' + l + 'px',
width: '800px',
height: '90px',
top: '-' + t + 'px',
clip: 'rect(' + tp + 'px,' + rt + 'px,' + bt + 'px,' + lt + 'px)'
}
}
l = l + 80;
rt = rt + 80;
lt = lt + 80;
if (j % 10 == 0) {
t = t + 45;
rt = 80;
lt = 0;
l = 40;
}
if (j % 100 == 0) {
t = 60;
c = c + 1;
tp = 0;
rt = 80;
bt = 45;
lt = 0;
}
j++;
}
return op;
}()));
In your code the function thumbnails received invalid object, you can't put a for loop in the start of the object.

Interactive Doughnut Web Chart

I have a chart that i'm trying to make more user friendly and I keep running into issues trying to add one thing, something else goes wrong.
what im trying to accomplish is: Chart starts with one in 'hovered' state. When one is hovered on, it has a border as well as the text in the middle of the chart updates with the label and percentage. I would also like the background to be a SVG image (not important if not possible) .
I've made a fiddle - I would like to remove the tooltip too.
Any help would be greatly appreciated!
IMG of what im trying to accomplish:
my HTML code:
<div id="doughnutChart" class="chart"></div>
jQuery
jQuery(function(){
jQuery("#doughnutChart").drawDoughnutChart([
{ title: "Holiday Fund", value : 5, color: "#2C3E50" },
{ title: "Emergencies", value: 20, color: "#FC4349" },
{ title: "Loans", value: 20, color: "#6DBCDB" },
{ title: "Widows", value : 27, color: "#F7E248" },
{ title: "Medical Support", value : 28, color: "#D7DADB" },
]);
});
/*!
* jquery.drawDoughnutChart.js
* Version: 0.4.1(Beta)
* Inspired by Chart.js(http://www.chartjs.org/)
*
* Copyright 2014 hiro
* https://github.com/githiro/drawDoughnutChart
* Released under the MIT license.
*
*/
;(function($, undefined) {
$.fn.drawDoughnutChart = function(data, options) {
var $this = this,
W = $this.width(),
H = $this.height(),
centerX = W/2,
centerY = H/2,
cos = Math.cos,
sin = Math.sin,
PI = Math.PI,
settings = $.extend({
segmentShowStroke : true,
segmentStrokeColor : "#0C1013",
segmentStrokeWidth : 1,
baseColor: "rgba(0,0,0,0.5)",
baseOffset: 4,
edgeOffset : 10,//offset from edge of $this
percentageInnerCutout : 75,
animation : true,
animationSteps : 90,
animationEasing : "easeInOutExpo",
animateRotate : true,
tipOffsetX: -8,
tipOffsetY: -45,
tipClass: "doughnutTip",
summaryClass: "doughnutSummary",
summaryTitle: "",
summaryTitleClass: "doughnutSummaryTitle",
summaryNumberClass: "doughnutSummaryNumber",
beforeDraw: function() { },
afterDrawed : function() { },
onPathEnter : function(e,data) { },
onPathLeave : function(e,data) { }
}, options),
animationOptions = {
linear : function (t) {
return t;
},
easeInOutExpo: function (t) {
var v = t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t;
return (v>1) ? 1 : v;
}
},
requestAnimFrame = function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}();
settings.beforeDraw.call($this);
var $svg = $('<svg width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>').appendTo($this),
$paths = [],
easingFunction = animationOptions[settings.animationEasing],
doughnutRadius = Min([H / 2,W / 2]) - settings.edgeOffset,
cutoutRadius = doughnutRadius * (settings.percentageInnerCutout / 100),
segmentTotal = 0;
//Draw base doughnut
var baseDoughnutRadius = doughnutRadius + settings.baseOffset,
baseCutoutRadius = cutoutRadius - settings.baseOffset;
$(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"d": getHollowCirclePath(baseDoughnutRadius, baseCutoutRadius),
"fill": settings.baseColor
})
.appendTo($svg);
//Set up pie segments wrapper
var $pathGroup = $(document.createElementNS('http://www.w3.org/2000/svg', 'g'));
$pathGroup.attr({opacity: 0}).appendTo($svg);
//Set up tooltip
var $tip = $('<div class="' + settings.tipClass + '" />').appendTo('body').hide(),
tipW = $tip.width(),
tipH = $tip.height();
for (var i = 0, len = data.length; i < len; i++) {
segmentTotal += data[i].value;
$paths[i] = $(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"stroke-width": settings.segmentStrokeWidth,
"stroke": settings.segmentStrokeColor,
"fill": data[i].color,
"data-order": i,
"class": 'counter-'+i
})
.appendTo($pathGroup)
.on("mouseenter", pathMouseEnter)
.on("mouseleave", pathMouseLeave)
.on("mousemove", pathMouseMove);
}
//Set up center text area
var summarySize = (cutoutRadius - (doughnutRadius - cutoutRadius)) * 2,
$summary = $('<div class="' + settings.summaryClass + '" />')
.appendTo($this)
.css({
width: summarySize + "px",
height: summarySize + "px",
"margin-left": -(summarySize / 2) + "px",
"margin-top": -(summarySize / 2) + "px"
});
var $summaryTitle = $('<p class="' + settings.summaryTitleClass + '">' + data[0].title + "<br />" + data[0].value + '%' + '</p>').appendTo($summary);
//var $summaryNumber = $('<p class="' + settings.summaryNumberClass + '"></p>').appendTo($summary).css({opacity: 0});
//Animation start
animationLoop(drawPieSegments);
//Functions
function getHollowCirclePath(doughnutRadius, cutoutRadius) {
//Calculate values for the path.
//We needn't calculate startRadius, segmentAngle and endRadius, because base doughnut doesn't animate.
var startRadius = -1.570,// -Math.PI/2
segmentAngle = 6.2831,// 1 * ((99.9999/100) * (PI*2)),
endRadius = 4.7131,// startRadius + segmentAngle
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,
'A', doughnutRadius, doughnutRadius, 0, 1, 1, endX, endY,//Draw outer circle
'Z',//Close path
'M', startX2, startY2,//Move pointer
'A', cutoutRadius, cutoutRadius, 0, 1, 0, endX2, endY2,//Draw inner circle
'Z'
];
cmd = cmd.join(' ');
return cmd;
};
function pathMouseEnter(e) {
var order = $(this).data().order;
$tip.text(data[order].title + ": " + data[order].value)
.fadeIn(200);
settings.onPathEnter.apply($(this),[e,data]);
$('.doughnutSummaryTitle').html(data[order].title + "<br />" + data[order].value + '%')
}
function pathMouseLeave(e) {
$tip.hide();
settings.onPathLeave.apply($(this),[e,data]);
}
function pathMouseMove(e) {
$tip.css({
top: e.pageY + settings.tipOffsetY,
left: e.pageX - $tip.width() / 2 + settings.tipOffsetX
});
}
function drawPieSegments (animationDecimal) {
var startRadius = -PI / 2,//-90 degree
rotateAnimation = 1;
if (settings.animation && settings.animateRotate) rotateAnimation = animationDecimal;//count up between0~1
//drawDoughnutText(animationDecimal, segmentTotal);
$pathGroup.attr("opacity", animationDecimal);
//If data have only one value, we draw hollow circle(#1).
if (data.length === 1 && (4.7122 < (rotateAnimation * ((data[0].value / segmentTotal) * (PI * 2)) + startRadius))) {
$paths[0].attr("d", getHollowCirclePath(doughnutRadius, cutoutRadius));
return;
}
for (var i = 0, len = data.length; i < len; i++) {
var segmentAngle = rotateAnimation * ((data[i].value / segmentTotal) * (PI * 2)),
endRadius = startRadius + segmentAngle,
largeArc = ((endRadius - startRadius) % (PI * 2)) > PI ? 1 : 0,
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,//Move pointer
'A', doughnutRadius, doughnutRadius, 0, largeArc, 1, endX, endY,//Draw outer arc path
'L', startX2, startY2,//Draw line path(this line connects outer and innner arc paths)
'A', cutoutRadius, cutoutRadius, 0, largeArc, 0, endX2, endY2,//Draw inner arc path
'Z'//Cloth path
];
$paths[i].attr("d", cmd.join(' '));
startRadius += segmentAngle;
}
}
//function drawDoughnutText(animationDecimal, segmentTotal) {
// $summaryNumber
// .css({opacity: animationDecimal})
// .text((segmentTotal * animationDecimal).toFixed(1));
//}
function animateFrame(cnt, drawData) {
var easeAdjustedAnimationPercent =(settings.animation)? CapValue(easingFunction(cnt), null, 0) : 1;
drawData(easeAdjustedAnimationPercent);
}
function animationLoop(drawData) {
var animFrameAmount = (settings.animation)? 1 / CapValue(settings.animationSteps, Number.MAX_VALUE, 1) : 1,
cnt =(settings.animation)? 0 : 1;
requestAnimFrame(function() {
cnt += animFrameAmount;
animateFrame(cnt, drawData);
if (cnt <= 1) {
requestAnimFrame(arguments.callee);
} else {
settings.afterDrawed.call($this);
}
});
}
function Max(arr) {
return Math.max.apply(null, arr);
}
function Min(arr) {
return Math.min.apply(null, arr);
}
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function CapValue(valueToCap, maxValue, minValue) {
if (isNumber(maxValue) && valueToCap > maxValue) return maxValue;
if (isNumber(minValue) && valueToCap < minValue) return minValue;
return valueToCap;
}
return $this;
};
})(jQuery);
CSS
.chart {
position: absolute;
width: 450px;
height: 450px;
top: 50%;
left: 50%;
margin: -225px 0 0 -225px;
}
.doughnutTip {
position: absolute;
min-width: 30px;
max-width: 300px;
padding: 5px 15px;
border-radius: 1px;
background: rgba(0,0,0,.8);
color: #ddd;
font-size: 17px;
text-shadow: 0 1px 0 #000;
text-transform: uppercase;
text-align: center;
line-height: 1.3;
letter-spacing: .06em;
box-shadow: 0 1px 3px rgba(0,0,0,0.5);
pointer-events: none;
&::after {
position: absolute;
left: 50%;
bottom: -6px;
content: "";
height: 0;
margin: 0 0 0 -6px;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
border-top: 6px solid rgba(0,0,0,.7);
line-height: 0;
}
}
.doughnutSummary {
position: absolute;
top: 50%;
left: 50%;
color: #000;
text-align: center;
text-shadow: 0 -1px 0 #111;
cursor: default;
}
.doughnutSummaryTitle {
position: absolute;
top: 50%;
width: 100%;
margin-top: -27%;
font-size: 22px;
letter-spacing: .06em;
}
.doughnutSummaryNumber {
position: absolute;
top: 50%;
width: 100%;
margin-top: -15%;
font-size: 55px;
}
.chart path:hover { opacity: 0.65; }
JSFIDDLE
Without modifying the original plugin drawDoughnutChart, you could overwrite the default settings.
For the out stroke you could draw an other chart, hide it, and use afterDrawed, onPathEnter, onPathLeave callbacks exposed by the plugin to do the logic.
And for the background of each pie segment, you could use svg pattern.
Javascript:
var firstSelected = 0;
var seed = [
{ title: "Holiday Fund", value : 5, color: "url(#dots2)" },
{ title: "Emergencies", value: 20, color: "url(#diagonal1)" },
{ title: "Loans", value: 20, color: "url(#dots1)" },
{ title: "Widows", value : 27, color: "url(#diagonal2)" },
{ title: "Medical Support", value : 28, color: "url(#hatch1)" },
];
var seed2 = [
{ value : 5, color: "#9fa1ac" },
{ value: 20, color: "#ef5123" },
{ value: 20, color: "#ef5123" },
{ value : 27, color: "#9fa1ac" },
{ value : 28, color: "#ef5123" },
];
var chartOptions = {
baseOffset: 0,
segmentShowStroke : false,
segmentStrokeColor : 'transparent',
baseColor: 'transparent',
percentageInnerCutout : 60,
onPathEnter: function (e, data) {
var order = $(this).data().order;
$('#doughnutChart .doughnutSummaryTitle').html(data[order].title);
$('#doughnutChart .doughnutSummaryNumber').html(data[order].value + '%');
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutBg g').find('path:eq('+(order)+')').fadeIn(500)
},
onPathLeave: function (e, data) {
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutChart .doughnutSummary').hide();
},
afterDrawed : function () {
$('#doughnutChart .doughnutSummaryTitle').html(seed[firstSelected].title);
$('#doughnutChart .doughnutSummaryNumber').html(seed[firstSelected].value + '%');
$('#doughnutChart .doughnutSummary').css({width: '160px', height: '60px', marginLeft: '-80px', marginTop: '-30px'});
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path:eq('+firstSelected+')').fadeIn(500);
}
} ;
var chartOptions2 = {
baseOffset: 0,
segmentStrokeColor : 'transparent',
segmentShowStroke : false,
percentageInnerCutout : 95
} ;
jQuery("#doughnutChart").drawDoughnutChart(seed, chartOptions);
jQuery("#doughnutBg").drawDoughnutChart(seed2, chartOptions2);
CSS:
.chart {
position: absolute;
width: 400px;
height: 400px;
top: 50%;
left: 50%;
margin: -200px 0 0 -200px;
}
.bgchart {
position: absolute;
width: 430px;
height: 430px;
top: 50%;
left: 50%;
margin: -215px 0 0 -215px;
}
.chart .doughnutSummary,
.bgchart .doughnutSummary{
display: none;
}
.chart path:hover { opacity: 0.65; }
.bgchart path { display: none }
HTML:
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="hatch1" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#ef5123; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="hatch2" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#9fa1ac; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="diagonal1" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="diagonal2" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#9fa1ac;" />
</pattern>
<pattern id="dots1" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="dots2" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#9fa1ac;" />
</pattern>
</defs>
</svg>
<div class="bgchart" id="doughnutBg"></div>
<div class="chart" id="doughnutChart"></div>
DEMO

Categories