Animation with Text Function - javascript

I've created Jquery plugin countdown timer so i'd like add some effects and animation to countdown like rotate or fade:
example for what i need:
Animation Demo
Note:
i need animation work with Days, Hours, Mintues and Seconds
n
(function ($) {
jQuery.fn.countdown = function (options, callback) {
var settings = { 'date': null };
if (options) {
$.extend(settings, options);
}
this_sel = $(this);
function count_exec() {
eventDate = Date.parse(settings['date']) / 1000;
currentDate = Math.floor($.now() / 1000);
if (eventDate <= currentDate) {
callback.call(this);
clearInterval(interval);
}
seconds = eventDate - currentDate;
days = Math.floor(seconds / (60 * 60 * 24));
seconds -= days * 60 * 60 * 24;
hours = Math.floor(seconds / (60 * 60));
seconds -= hours * 60 * 60 ;
minutes = Math.floor(seconds / 60);
seconds -= minutes * 60;
// add 0 value to left of value
if (!isNaN(eventDate)) {
this_sel.find('.days').text(days);
this_sel.find('.hours').text(hours);
this_sel.find('.mins').text(minutes);
this_sel.find('.secs').animate({ 'font-size': '100px' },1000).text(seconds);
}
}
count_exec();
interval = setInterval(count_exec, 1000);
};
})(jQuery);
$(document).ready(function () {
$("#countdown").countdown({
date: "4 january 2017 7:15:00"
},
function () {
$("#countdown").text("merry christmas");
}
);
})
#countdown{
width:1000px;
margin:50px auto;
border:1px solid #14e170;
}
#countdown .countdown-container{
width:25%;
height:200px;
float:left;
position:relative;
border:1px solid #14e170;
text-align:center;
}
.countdown-container > div{
text-align:center;
font-size:100px;
}
.countdown-container > span{
display:block;
top:0;
left:0;
font-size:40px;
color:rgba(73, 73, 73, 0.82);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="countdown">
<div class="countdown-container">
<div class="days">
00
</div>
<span>Days</span>
</div>
<div class="countdown-container">
<div class="hours">
00
</div>
<span>Hours</span>
</div>
<div class="countdown-container">
<div class="mins">
00
</div>
<span>Minutes</span>
</div>
<div class="countdown-container">
<div class="secs">
00
</div>
<span>Seconds</span>
</div>
</div>

Please visit this link : http://www.jqueryscript.net/time-clock/Animated-Responsive-jQuery-Countdown-Timer-Plugin-mbCoimingsoon.html
Just download this countdown, It's work like you want.
I hope it's helpful for you

/*
* flipclock
* Version: 1.0.1
* Authors: #gokercebeci
* Licensed under the MIT license
* Demo: http://
*/
(function($) {
var pluginName = 'flipclock';
var methods = {
pad: function(n) {
return (n < 10) ? '0' + n : n;
},
time: function(date) {
if (date) {
var e = new Date(date);
var b = new Date();
var d = new Date(e.getTime() - b.getTime());
} else
var d = new Date();
var t = methods.pad(date ? d.getFullYear() - 70 : d.getFullYear())
+ '' + methods.pad(date ? d.getMonth() : d.getMonth() + 1)
+ '' + methods.pad(date ? d.getDate() - 1 : d.getDate())
+ '' + methods.pad(d.getHours())
+ '' + methods.pad(d.getMinutes())
+ '' + methods.pad(d.getSeconds());
return {
'Y': {'d2': t.charAt(2), 'd1': t.charAt(3)},
'M': {'d2': t.charAt(4), 'd1': t.charAt(5)},
'D': {'d2': t.charAt(6), 'd1': t.charAt(7)},
'h': {'d2': t.charAt(8), 'd1': t.charAt(9)},
'm': {'d2': t.charAt(10), 'd1': t.charAt(11)},
's': {'d2': t.charAt(12), 'd1': t.charAt(13)}
};
},
play: function(c) {
$('body').removeClass('play');
var a = $('ul' + c + ' section.active');
if (a.html() == undefined) {
a = $('ul' + c + ' section').eq(0);
a.addClass('ready')
.removeClass('active')
.next('section')
.addClass('active')
.closest('body')
.addClass('play');
}
else if (a.is(':last-child')) {
$('ul' + c + ' section').removeClass('ready');
a.addClass('ready').removeClass('active');
a = $('ul' + c + ' section').eq(0);
a.addClass('active')
.closest('body')
.addClass('play');
}
else {
$('ul' + c + ' section').removeClass('ready');
a.addClass('ready')
.removeClass('active')
.next('section')
.addClass('active')
.closest('body')
.addClass('play');
}
},
// d1 is first digit and d2 is second digit
ul: function(c, d2, d1) {
return '<ul class="flip ' + c + '">' + this.li('d2', d2) + this.li('d1', d1) + '</ul>';
},
li: function(c, n) {
//
return '<li class="' + c + '"><section class="ready"><div class="up">'
+ '<div class="shadow"></div>'
+ '<div class="inn"></div></div>'
+ '<div class="down">'
+ '<div class="shadow"></div>'
+ '<div class="inn"></div></div>'
+ '</section><section class="active"><div class="up">'
+ '<div class="shadow"></div>'
+ '<div class="inn">' + n + '</div></div>'
+ '<div class="down">'
+ '<div class="shadow"></div>'
+ '<div class="inn">' + n + '</div></div>'
+ '</section></li>';
}
};
// var defaults = {};
function Plugin(element, options) {
this.element = element;
this.options = options;
// this.options = $.extend({}, defaults, options);
// this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
var t, full = false;
if (!this.options || this.options == 'clock') {
t = methods.time();
} else if (this.options == 'date') {
t = methods.time();
full = true;
} else {
t = methods.time(this.options);
full = true;
}
$(this.element)
.addClass('flipclock')
.html(
(full ?
methods.ul('year', t.Y.d2, t.Y.d1)
+ methods.ul('month', t.M.d2, t.M.d1)
+ methods.ul('day', t.D.d2, t.D.d1)
: '')
+ methods.ul('hour', t.h.d2, t.h.d1)
+ methods.ul('minute', t.m.d2, t.m.d1)
+ methods.ul('second', t.s.d2, t.s.d1)
+ '<audio id="flipclick">'
+ '<source src="https://github.com/gokercebeci/flipclock/blob/master/js/plugins/flipclock/click.mp3?raw=true" type="audio/mpeg"/>'
+ '</audio>');
setInterval($.proxy(this.refresh, this), 1000);
},
refresh: function() {
var el = $(this.element);
var t;
if (this.options
&& this.options != 'clock'
&& this.options != 'date') {
t = methods.time(this.options);
} else
t = methods.time()
// second sound
setTimeout(function() {
document.getElementById('flipclick').play()
}, 500);
// second first digit
el.find(".second .d1 .ready .inn").html(t.s.d1);
methods.play('.second .d1');
// second second digit
if ((t.s.d1 === '0')) {
el.find(".second .d2 .ready .inn").html(t.s.d2);
methods.play('.second .d2');
// minute first digit
if ((t.s.d2 === '0')) {
el.find(".minute .d1 .ready .inn").html(t.m.d1);
methods.play('.minute .d1');
// minute second digit
if ((t.m.d1 === '0')) {
el.find(".minute .d2 .ready .inn").html(t.m.d2);
methods.play('.minute .d2');
// hour first digit
if ((t.m.d2 === '0')) {
el.find(".hour .d1 .ready .inn").html(t.h.d1);
methods.play('.hour .d1');
// hour second digit
if ((t.h.d1 === '0')) {
el.find(".hour .d2 .ready .inn").html(t.h.d2);
methods.play('.hour .d2');
// day first digit
if ((t.h.d2 === '0')) {
el.find(".day .d1 .ready .inn").html(t.D.d1);
methods.play('.day .d1');
// day second digit
if ((t.D.d1 === '0')) {
el.find(".day .d2 .ready .inn").html(t.D.d2);
methods.play('.day .d2');
// month first digit
if ((t.D.d2 === '0')) {
el.find(".month .d1 .ready .inn").html(t.M.d1);
methods.play('.month .d1');
// month second digit
if ((t.M.d1 === '0')) {
el.find(".month .d2 .ready .inn").html(t.M.d2);
methods.play('.month .d2');
// year first digit
if ((t.M.d2 === '0')) {
el.find(".year .d1 .ready .inn").html(t.Y.d1);
methods.play('.year .d1');
// year second digit
if ((t.Y.d1 === '0')) {
el.find(".year .d2 .ready .inn").html(t.Y.d2);
methods.play('.year .d2');
}
}
}
}
}
}
}
}
}
}
}
},
};
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$(this).data('plugin_' + pluginName)) {
$(this).data('plugin_' + pluginName,
new Plugin(this, options));
}
});
};
})(typeof jQuery !== 'undefined' ? jQuery : Zepto);
// RUN
$('#container').flipclock();
html, body {
margin: 0;
padding:0;
height: 100%;
color: #fff;
font: 11px/normal sans-serif;
background-image: url('https://github.com/gokercebeci/flipclock/raw/master/css/background.jpg');
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
#mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('https://github.com/gokercebeci/flipclock/raw/master/css/mask.png');
z-index: 2;
}
h1 {
margin: 0 10px;
font-size: 70px;
font-weight: bold;
text-shadow: 0 0 2px #fff;
}
.clearfix {
clear: both;
}
#page {
margin: 0 auto;
width: 600px;
}
#container {
opacity: .9;
}
#usage li {
position: relative;
margin: 5px 0;
padding: 10px;
color: #222;
background: #fff;
}
#usage code {
position: absolute;
top:0;
right:0;
padding: 10px;
color: #eee;
border: 1px solid #333;
background: #000;
}
/*
* flipclock
* Version: 1.0.0
* Authors: #gokercebeci
* Licensed under the MIT license
* Demo: http://
*/
/*==============================================================================
FLIP CLOCK
==============================================================================*/
.flipclock {
}
.flipclock hr {
position: absolute;
left: 0;
top: 65px;
width: 100%;
height: 3px;
border: 0;
background: #000;
z-index: 10;
opacity: 0;
}
ul.flip {
position: relative;
float: left;
margin: 10px;
padding: 0;
width: 180px;
height: 130px;
font-size: 120px;
font-weight: bold;
line-height: 127px;
}
ul.flip li {
float: left;
margin: 0;
padding: 0;
width: 49%;
height: 100%;
-webkit-perspective: 200px;
list-style: none;
}
ul.flip li.d1 {
float: right;
}
ul.flip li section {
z-index: 1;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
ul.flip li section:first-child {
z-index: 2;
}
ul.flip li div {
z-index: 1;
position: absolute;
left: 0;
width: 100%;
height: 49%;
overflow: hidden;
}
ul.flip li div .shadow {
display: block;
position: absolute;
width: 100%;
height: 100%;
z-index: 2;
}
ul.flip li div.up {
-webkit-transform-origin: 50% 100%;
top: 0;
}
ul.flip li div.down {
-webkit-transform-origin: 50% 0%;
bottom: 0;
}
ul.flip li div div.inn {
position: absolute;
left: 0;
z-index: 1;
width: 100%;
height: 200%;
color: #fff;
text-shadow: 0 0 2px #fff;
text-align: center;
background-color: #000;
border-radius: 6px;
}
ul.flip li div.up div.inn {
top: 0;
}
ul.flip li div.down div.inn {
bottom: 0;
}
/*--------------------------------------
PLAY
--------------------------------------*/
body.play ul section.ready {
z-index: 3;
}
body.play ul section.active {
-webkit-animation: index .5s .5s linear both;
z-index: 2;
}
#-webkit-keyframes index {
0% {
z-index: 2;
}
5% {
z-index: 4;
}
100% {
z-index: 4;
}
}
body.play ul section.active .down {
z-index: 2;
-webkit-animation: flipdown .5s .5s linear both;
}
#-webkit-keyframes flipdown {
0% {
-webkit-transform: rotateX(90deg);
}
80% {
-webkit-transform: rotateX(5deg);
}
90% {
-webkit-transform: rotateX(15deg);
}
100% {
-webkit-transform: rotateX(0deg);
}
}
body.play ul section.ready .up {
z-index: 2;
-webkit-animation: flipup .5s linear both;
}
#-webkit-keyframes flipup {
0% {
-webkit-transform: rotateX(0deg);
}
90% {
-webkit-transform: rotateX(0deg);
}
100% {
-webkit-transform: rotateX(-90deg);
}
}
/*--------------------------------------
SHADOW
--------------------------------------*/
body.play ul section.ready .up .shadow {
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, .1)), color-stop(100%, rgba(0, 0, 0, 1)));
background: linear-gradient(top, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
background: linear-gradient(to bottom, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
-webkit-animation: show .5s linear both;
}
body.play ul section.active .up .shadow {
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, .1)), color-stop(100%, rgba(0, 0, 0, 1)));
background: linear-gradient(top, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
background: linear-gradient(to bottom, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
-webkit-animation: hide .5s .3s linear both;
}
/*DOWN*/
body.play ul section.ready .down .shadow {
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, 1)), color-stop(100%, rgba(0, 0, 0, .1)));
background: linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
-webkit-animation: show .5s linear both;
}
body.play ul section.active .down .shadow {
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, 1)), color-stop(100%, rgba(0, 0, 0, .1)));
background: linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
-webkit-animation: hide .5s .3s linear both;
}
#-webkit-keyframes show {
0% {
opacity: 0;
}
90% {
opacity: .10;
}
100% {
opacity: 1;
}
}
#-webkit-keyframes hide {
0% {
opacity: 1;
}
80% {
opacity: .20;
}
100% {
opacity: 0;
}
}
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.0/zepto.min.js"></script>
<div id="mask">
<div id="page">
<h1>flipclock</h1>
<div id="container"></div>
<div class="clearfix"></div>
<h2>USAGE</h2>
<ul id="usage">
<li class="selected">
clock
<code>$('#container').flipclock();</code>
</li>
<li>
fulldate
<code>$('#container').flipclock('date');</code>
</li>
<li>
countdown
<code>$('#container').flipclock('2013 01 17 12:00:00');</code>
</li>
</ul>
</div>
</div>
Would you please try above code?

Related

How to conform top glare to all child elements

Goal
Make the glare layer on all visible children like a clip-path
––––––––––––
Heads Up
Child elements can be any shape with any animation
Child elements can be any svg shape with any kind of animation attached to it
So glare must be automatically dynamic and conforming
––––––––––––
What I've Done
I create an apple TV effect…
But the glare only works as a box on top of other boxes.
The glare does not conform to other shapes
Example Below
––––––––––––
What I Can't Use
Canvas - No Canvas Please - I'm not familiar with it
Clip-Path - Because child elements can be anything overflowing outside of the glare
––––––––––––
What I'm looking for
Some kind of magical CSS line of code that makes the glare layer conform to all elements under it… like a normal glare would work.
Is this possible?
Is there some way Javascript can glare it automatically?
Is there some kind of mix-blend-mode I can use to make the glare just work?
Or is this something that is just impossible?
Glare should not look like a box
––––––––––––
What I tried
I tried to scale the glare layer to scale(1.1) and use some mix-blend-mode
But I couldn't figure out how to make it work.
appleTV();
function appleTV(){
appleTVComponents = 0;
function rotateX(n) {return ' rotateX('+n+'deg)'}
function rotateY(n) {return ' rotateY('+n+'deg)'}
function translateX(n) {return ' translateX('+n+'px)'}
function translateY(n) {return ' translateY('+n+'px)'}
function perspective(n) {return 'perspective('+n+'px)'}
function scale(n) {return ' scale3d('+n+','+n+','+n+')'}
function section(s='',e) {e=document.createElement('section');e.className='appletv_'+s;return e;}
function getWidth(e) {return e.clientWidth || e.offsetWidth || e.scrollWidth}
function setPerspective(e) {e.style.transform = perspective(getWidth(e)*3);}
function preventScroll(state) {if(supportsTouch){win.preventScroll=state||false;}}
function preventDefault(e) {if (supportsTouch&&win.preventScroll){e.preventDefault();}}
function isTouchScreen() {return 'ontouchstart' in window || navigator.msMaxTouchPoints}
function child(e) {return e.firstChild;}
function children(e) {return [...e.children]}
let body = document.body,
win = window,
imgs = document.querySelectorAll('.appletv'),
totalImgs = imgs.length,
supportsTouch = isTouchScreen(),
move = 'mousemove',
start = 'mouseenter',
end = 'mouseleave';
if(supportsTouch){move='touchmove'; start='touchstart'; end='touchend';}
if(totalImgs <= 0){return;}
for(var l=0;l<totalImgs;l++){
var thisImg = imgs[l],
layerElems = [...thisImg.querySelectorAll('.appletv_layer')];
if(!layerElems.length){continue;}
while(thisImg.firstChild) {thisImg.removeChild(thisImg.firstChild);}
var containerHTML = section(''),
shineHTML = section('gloss'),
shadowHTML = section('shadow'),
layersHTML = section('layer'),
layers = [];
thisImg.id = 'appletv_'+(++appleTVComponents);
layerElems.forEach((e,i)=>{
let layer_ = section('rendered_layer')
layer = section(''),
img = e.getAttribute('data-img');
layer_.setAttribute('data-layer',i);
[...e.children].forEach(c=>{layer.appendChild(c)})
if (img) {layer.style.backgroundImage = 'url('+img+')';}
layer_.appendChild(layer);
layersHTML.appendChild(layer_);
layers.push(layer);
});
[shadowHTML,layersHTML,shineHTML].forEach(e=>{containerHTML.appendChild(e)});
thisImg.appendChild(containerHTML);
var w = getWidth(thisImg);
setPerspective(thisImg)
preventScroll();
(function enableMovements(_thisImg,_layers,_totalLayers,_shine) {
thisImg.addEventListener(move, e=>{processMovement(e,supportsTouch,_thisImg,_layers,_totalLayers,_shine);});
thisImg.addEventListener(start, e=>{processEnter(_thisImg);});
thisImg.addEventListener(end, e=>{processExit(_thisImg,_layers,_totalLayers,_shine);});
})(thisImg,layers,layerElems.length,shineHTML);
};
function processMovement(e, touchEnabled, elem, layers, totalLayers, shine){
preventDefault(e)
let bdst = body.scrollTop,
bdsl = body.scrollLeft,
pageX = (touchEnabled)? e.touches[0].pageX : e.pageX,
pageY = (touchEnabled)? e.touches[0].pageY : e.pageY,
offsets = elem.getBoundingClientRect(),
w = elem.clientWidth || elem.offsetWidth || elem.scrollWidth, // width
h = elem.clientHeight || elem.offsetHeight || elem.scrollHeight, // height
wMultiple = 320/w,
offsetX = 0.52 - (pageX - offsets.left - bdsl)/w, //cursor position X
offsetY = 0.52 - (pageY - offsets.top - bdst)/h, //cursor position Y
dy = (pageY - offsets.top - bdst) - h / 2, //#h/2 = center of container
dx = (pageX - offsets.left - bdsl) - w / 2, //#w/2 = center of container
yRotate = (offsetX - dx)*(0.07 * wMultiple), //rotation for container Y
xRotate = (dy - offsetY)*(0.1 * wMultiple), //rotation for container X
imgCSS = rotateX(xRotate)+rotateY(yRotate), //img transform
arad = Math.atan2(dy, dx), //angle between cursor and center of container in RAD
angle = arad * 180 / Math.PI - 90; //convert rad in degrees
if (angle < 0) {angle = angle + 360;}
if(elem.firstChild.className.indexOf(' over') != -1){imgCSS += scale(1.07);}
elem.firstChild.style.transform = imgCSS;
shine.style.background = 'linear-gradient(' + angle + 'deg, rgba(255,255,255,' + (pageY - offsets.top - bdst)/h * 0.4 + ') 0%,rgba(255,255,255,0) 80%)';
shine.style.transform = translateX((offsetX * totalLayers) - 0.1)+translateY((offsetY * totalLayers) - 0.1);
var revNum = totalLayers;
for(var ly=0;ly<totalLayers;ly++){
layers[ly].style.transform = translateX((offsetX * revNum) * ((ly * 2.5) / wMultiple))+translateX((offsetY * totalLayers) * ((ly * 2.5) / wMultiple));
revNum--;
}
}
function processEnter(e){preventScroll(true);setPerspective(e);child(e)&&child(e).classList.add('over');}
function processExit(elem, layers, totalLayers, shine){preventScroll();
child(elem).classList.remove('over')
child(elem).style.transform = '';
shine.style = '';
layers.forEach(e=>{e.style.transform = ''})
}
}
body,
html {
height: 100%;
min-height: 100%;
}
body {background: linear-gradient(to bottom, #f6f7fc 0%, #d5e1e8 40%);}
.center{
position: absolute;
left: 50%;
margin: 10px auto;
transform: translateX(-50%);
}
.appletv {
position: relative !important;
margin: 0 auto !important;
display: inline-block;
width: 300px;
height: 150px;
border-radius: 5px;
transform-style: preserve-3d;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
cursor: pointer;
backface-visibility: hidden;
}
.appletv.depressed {
margin-top: 25px;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.4);
}
.appletv_ {
position: relative;
width: 100%;
height: 100%;
border-radius: 5px;
transition: all 0.2s ease-out;
background: teal;
}
.appletv_container.over {z-index: 1;}
.appletv_container.over .appletv_shadow {box-shadow: 0 45px 100px rgba(14, 21, 47, 0.4), 0 16px 40px rgba(14, 21, 47, 0.4);}
.appletv_layer {
position: relative;
width: 100%;
height: 100%;
border-radius: 5px;
/*overflow: hidden;*/
transform-style: preserve-3d;
}
.appletv_rendered_layer {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
border-radius: 5px;
transition: all 0.1s ease-out;
transform-style: preserve-3d;
}
.appletv_rendered_layer > :first-child {
position: absolute;
width: 104%;
height: 104%;
top: -2%;
left: -2%;
background-repeat: no-repeat;
background-position: center;
background-color: transparent;
background-size: cover;
transition: all 0.1s ease-out;
}
.appletv_shadow {
position: absolute;
top: 5%;
left: 5%;
width: 90%;
height: 90%;
transition: all 0.2s ease-out;
box-shadow: 0 8px 30px rgba(14, 21, 47, 0.6);
}
.appletv_gloss {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 5px;
/*display: none !important;*/
background: linear-gradient(135deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0) 40%);
}
[data-layer="1"] {overflow: visible !important;}
[data-layer="1"] > section > section {
position: absolute;
background: rgb(50, 141, 210);
width: 60px;
height: 60px;
border-radius: 10px;
}
[data-layer="1"] > section > section:first-child {
left: -30px;
top: -10px;
}
[data-layer="1"] > section > section:last-child {
right: -20px;
top: 50px;
}
#keyframes rotate {
0% {transform: rotate(0);}
100% {transform: rotate(359deg);}
}
.appletv_gloss {
/*display: none;*/
background-blend-mode: multiply;
}
.appletv [data-layer="1"] {
transform: scale(0.5);
transition: .3s ease-in-out 0s;
}
.appletv:hover [data-layer="1"] {
transform: scale(1);
}
.appletv:hover [data-layer="1"] > section > section {
animation: rotate 10s linear 0s infinite;
}
.appletv:hover [data-layer="1"] > section > section:last-child {
animation: rotate 25s linear 0s infinite;
}
#hover {
font-size: 30px;
position: absolute;
top: 37%;
text-align: center;
width: 100%;
color: white;
text-shadow: 0 2px 2px rgba(0,0,0,0.3) ;
}
<html>
<body>
<section class="center">
<section class="appletv">
<section class="appletv appletv_layer" data-img="https://source.unsplash.com/random">
<section id="hover">Hover Corners</section>
</section>
<section class="appletv appletv_layer">
<section></section>
<section></section>
</section>
</section>
</section>
</body>
</html>

Modify countdown script to allow for multiple countdowns per page

I am utilizing the following script from CodePen
// Create Countdown
var Countdown = {
// Backbone-like structure
$el: $('.countdown'),
// Params
countdown_interval: null,
total_seconds : 0,
// Initialize the countdown
init: function() {
// DOM
this.$ = {
hours : this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours : this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;
// Animate countdown to the end
this.count();
},
count: function() {
var that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if(that.total_seconds > 0) {
--that.values.seconds;
if(that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if(that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
}
else {
clearInterval(that.countdown_interval);
}
}, 1000);
},
animateFigure: function($el, value) {
var that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX : '-180deg',
transformPerspective: 300,
ease : Quart.easeOut,
onComplete : function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, { rotationX: 0 });
}
});
TweenMax.to($back_top, 0.8, {
rotationX : 0,
transformPerspective: 300,
ease : Quart.easeOut,
clearProps : 'all'
});
},
checkHour: function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if(value >= 10) {
// Animate only if the figure has changed
if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
}
else {
// If we are under 10, replace first figure with 0
if(fig_1_value !== '0') this.animateFigure($el_1, 0);
if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
};
// Let's go !
Countdown.init();
I have been trying to figure out for several hours how to modify it to support multiple countdown timers per page.
My approach so far was to try adding a numeric counter so that each "countdown" element gets a unique class, and then modifying the script to run on each element but this did not work and I don't think it will.
I'm not sure how else to approach it though so would appreciate some input.
You can create a new instance of this object with just a little bit of refactoring by converting it into a function.
For example, if you clone your <div class="countdown"/> HTML, and in JS you call:
new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();
Or, alternatively you could also initialize all .countdowns on page with:
$('.countdown').each((_, el) => (new Countdown($(el)).init()));
you will have two unique instances of the countdown.
// Create Countdown
function Countdown(node) {
this.$el = node;
this.countdown_interval = null;
this.total_seconds = 0;
this.init = function() {
// DOM
this.$ = {
hours: this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours: this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = (this.values.hours * 60 * 60) +
(this.values.minutes * 60) +
this.values.seconds;
// Animate countdown to the end
this.count();
};
this.count = function() {
let that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if (that.total_seconds > 0) {
--that.values.seconds;
if (that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if (that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
} else {
clearInterval(that.countdown_interval);
}
}, 1000);
};
this.animateFigure = function($el, value) {
let that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX: '-180deg',
transformPerspective: 300,
ease: Quart.easeOut,
onComplete: function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, {
rotationX: 0
});
}
});
TweenMax.to($back_top, 0.8, {
rotationX: 0,
transformPerspective: 300,
ease: Quart.easeOut,
clearProps: 'all'
});
};
this.checkHour = function(value, $el_1, $el_2) {
let val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if (value >= 10) {
// Animate only if the figure has changed
if (fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if (fig_2_value !== val_2) this.animateFigure($el_2, val_2);
} else {
// If we are under 10, replace first figure with 0
if (fig_1_value !== '0') this.animateFigure($el_1, 0);
if (fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
}
// Let's go !
new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();
// Alternatively you could also initialize all countdowns on page with:
// $('.countdown').each((i, el) => (new Countdown($(el)).init()));
body {
background-color: #f2f1ed;
}
.wrap {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
margin: auto;
height: 310px;
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 60px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
width: 720px;
margin: 4px 0;
display: inline-block;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure>span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after,
.countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top,
.countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<h1>Draft <strong>Countdown</strong></h1>
<!-- Countdown #1 -->
<div class="countdown">
<div class="bloc-time hours" data-init-value="24">
<span class="count-title">Hours</span>
<div class="figure hours hours-1">
<span class="top">2</span>
<span class="top-back">
<span>2</span>
</span>
<span class="bottom">2</span>
<span class="bottom-back">
<span>2</span>
</span>
</div>
<div class="figure hours hours-2">
<span class="top">4</span>
<span class="top-back">
<span>4</span>
</span>
<span class="bottom">4</span>
<span class="bottom-back">
<span>4</span>
</span>
</div>
</div>
<div class="bloc-time min" data-init-value="0">
<span class="count-title">Minutes</span>
<div class="figure min min-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure min min-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
<div class="bloc-time sec" data-init-value="0">
<span class="count-title">Seconds</span>
<div class="figure sec sec-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure sec sec-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
</div>
<div class="countdown">
<div class="bloc-time hours" data-init-value="4">
<span class="count-title">Hours</span>
<div class="figure hours hours-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure hours hours-2">
<span class="top">4</span>
<span class="top-back">
<span>4</span>
</span>
<span class="bottom">4</span>
<span class="bottom-back">
<span>4</span>
</span>
</div>
</div>
<div class="bloc-time min" data-init-value="30">
<span class="count-title">Minutes</span>
<div class="figure min min-1">
<span class="top">3</span>
<span class="top-back">
<span>3</span>
</span>
<span class="bottom">3</span>
<span class="bottom-back">
<span>3</span>
</span>
</div>
<div class="figure min min-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
<div class="bloc-time sec" data-init-value="30">
<span class="count-title">Seconds</span>
<div class="figure sec sec-1">
<span class="top">3</span>
<span class="top-back">
<span>3</span>
</span>
<span class="bottom">3</span>
<span class="bottom-back">
<span>3</span>
</span>
</div>
<div class="figure sec sec-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
</div>
</div>
Here's a link to the updated codepen.
Hope this helps,
As a jQuery plugin it could go this way (you can customize it further):
// Create Countdown Plugin
$.fn.fancyCountdown = function() {
return this.each(function() {
var that=this;
var $el=$(this);
that.values = {
titleHours: 'Hours',
titleMinutes: 'Minutes',
titleSeconds: 'Seconds'
};
if( $el.data('settings') ) {
that.values = $el.data('settings');
} else {
that.values = $.extend( {}, that.values, $el.data() );
};
var explodeTime = that.values.time.split(':');
that.values.hours = explodeTime[0]*1;
that.values.minutes = explodeTime[1]*1;
that.values.seconds = explodeTime[2]*1;
that.values.hours1 = explodeTime[0][0];
that.values.hours2 = explodeTime[0][1];
that.values.minutes1 = explodeTime[1][0];
that.values.minutes2 = explodeTime[1][1];
that.values.seconds1 = explodeTime[2][0];
that.values.seconds2 = explodeTime[2][1];
that.values.totalSeconds = that.values.hours*60*60 + that.values.minutes*60 + that.values.seconds;
that.values.template = '\
<span class="top">#</span>\
<span class="top-back">\
<span>#</span>\
</span>\
<span class="bottom">#</span>\
<span class="bottom-back">\
<span>#</span>\
</span>\
';
that.countdownInterval = null;
if( !$el.hasClass('countdown-engaged') ) {
$el.addClass('countdown-engaged');
// Initialize the countdown
that.init=function() {
// DOM
that.createDom();
that.$ = {
hours: $el.find('.bloc-time.hours .figure'),
minutes: $el.find('.bloc-time.min .figure'),
seconds: $el.find('.bloc-time.sec .figure')
};
// Animate countdown to the end
that.count();
};
that.createDom = function() {
var html = '\
<div class="bloc-time hours">\
<span class="count-title">' + that.values.titleHours + '</span>\
<div class="figure hours hours-1">\
' + that.values.template.replace(/#/g, that.values.hours1) + '\
</div>\
<div class="figure hours hours-2">\
' + that.values.template.replace(/#/g, that.values.hours2) + '\
</div>\
</div>\
<div class="bloc-time min">\
<span class="count-title">' + that.values.titleMinutes + '</span>\
<div class="figure min min-1">\
' + that.values.template.replace(/#/g, that.values.minutes1) + '\
</div>\
<div class="figure min min-2">\
' + that.values.template.replace(/#/g, that.values.minutes2) + '\
</div>\
</div>\
<div class="bloc-time sec">\
<span class="count-title">' + that.values.titleSeconds + '</span>\
<div class="figure sec sec-1">\
' + that.values.template.replace(/#/g, that.values.seconds1) + '\
</div>\
<div class="figure sec sec-2">\
' + that.values.template.replace(/#/g, that.values.seconds2) + '\
</div>\
</div>\
';
$el.html(html);
};
that.count = function() {
var $hour_1 = that.$.hours.eq(0),
$hour_2 = that.$.hours.eq(1),
$min_1 = that.$.minutes.eq(0),
$min_2 = that.$.minutes.eq(1),
$sec_1 = that.$.seconds.eq(0),
$sec_2 = that.$.seconds.eq(1);
that.countdownInterval = setInterval(function() {
if (that.values.totalSeconds > 0) {
--that.values.seconds;
if (that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if (that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.values.totalSeconds;
} else {
clearInterval(that.countdownInterval);
};
}, 1000);
};
that.animateFigure = function($el, value) {
var $top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX: '-180deg',
transformPerspective: 300,
ease: Quart.easeOut,
onComplete: function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, {
rotationX: 0
});
}
});
TweenMax.to($back_top, 0.8, {
rotationX: 0,
transformPerspective: 300,
ease: Quart.easeOut,
clearProps: 'all'
});
};
that.checkHour=function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if (value >= 10) {
// Animate only if the figure has changed
if (fig_1_value !== val_1) that.animateFigure($el_1, val_1);
if (fig_2_value !== val_2) that.animateFigure($el_2, val_2);
} else {
// If we are under 10, replace first figure with 0
if (fig_1_value !== '0') that.animateFigure($el_1, 0);
if (fig_2_value !== val_1) that.animateFigure($el_2, val_1);
}
};
};
that.init();
});
};
$('.countdown').fancyCountdown();
body {
background-color: #f2f1ed;
}
.wrap {
margin: 0 auto;
height: 310px;
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 60px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
width: 720px;
margin: 0 auto;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure>span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after,
.countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top,
.countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<h1>Draft <strong>Countdown</strong></h1>
<div class="countdown" data-time="22:30:00"></div>
</div>
<div class="wrap">
<h1>Second <strong>Countdown</strong></h1>
<div class="countdown" data-settings='{"time": "01:22:50", "titleHours": "Sati", "titleMinutes": "Minuti", "titleSeconds": "Sekunde"}'></div>
</div>
Also on JSFiddle.
I only kept the visual aspect in CSS (with some modifications) and I completely rewrote all the code in "pure" Javascript (no jQuery) and keeping the GSAP / TweenMax library.
You can put as many countDown as you want by filling in an array indicating the titles and durations etc.
There is only one setInterval handling the different countDown and it will stop with the last active countDown.
I chose this solution because using several setInterval at the same time seemed to me disproportionate for that, and unnecessarily overload the OS.
For greater accuracy, all countDowns are based on the system clock (and not on the call cycles of the setInterval, because they are "naturally" shifted and are therefore incompatible for any use of time measurement).
This script makes it possible to carry out 2 types of countDown:
- for a fixed duration (eg 6 minutes for eggs)
- either on a date (or time) end (ex: birthday, appointment ...)
The other interest of this script is that it generates on demand the set of elements html useful to the display of countDown on the page, and it allows to choose the display with the number of desired units
const myCountDowns= [ { title: 'timer <strong>24h</strong>'
, type : 'Hours'
, timer: '24h'
}
, { title: 'Tea cup <strong>2\' 45"</strong>'
, type : 'Minutes'
, timer: '2m 45s'
}
, { title: 'until the new year <strong>2020</strong>'
, type : 'Days'
, date : '01 01 2020' // local Month Day Year
}
]
CountDown.BuildsAndRun( myCountDowns )
// ->type : 'Days' or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration otherwise set a "date" value
// timer string format is _number_UNIT where UNIT = 'd','h','m','s' for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s' = 3 days 0 hours 25 minutes, 6 seconds (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m' = the same, there is no order
// date format is JS Date format see new Date( _STRING_ )
FULL CODE (on snippet below)
(function( CountDown )
{
// Private vars
const domEndBody = document.body.querySelector('script') || document.body // for countDowns insert place
, eWrapp = document.createElement('div')
, eTitle = document.createElement('h1')
, eCountDown = document.createElement('div')
, eTimeBlock = document.createElement('div')
, eCountTitle = document.createElement('span')
, eFigure = document.createElement('div')
, counters = [] // list of CountDowns
, one_Sec = 1000
, one_Min = one_Sec * 60
, one_Hour = one_Min * 60
, one_Day = one_Hour * 24
, padZ =(val,sz) => ('0'.repeat(sz)+val.toString(10)).slice(-sz) // return string with leading zeros
, Interface = [ { xL:8, Title:'Days', Fig:3 } // titles & counts of figures
, { xL:5, Title:'Hours', Fig:2 }
, { xL:3, Title:'Minutes', Fig:2 }
, { xL:0, Title:'Seconds', Fig:2 }
]
, animOpt = { rotationX: 0, transformPerspective: 300, ease: Quart.easeOut, clearProps: 'all' }
var activeCounters = 0
// finalize countDown elements
eWrapp.className = 'wrap'
eTitle.innerHTML = 'F<strong>D</strong>' // 'Draft <strong>Countdown</strong>'
eCountDown.className = 'countdown'
eTimeBlock.className = 'bloc-time'
eCountTitle.className = 'count-title'
eFigure.className = 'figure'
eFigure.innerHTML = '<span class="top" > </span>'
+ ' <span class="top-back" > <span> </span> </span>'
+ ' <span class="bottom" > </span>'
+ ' <span class="bottom-back"> <span> </span> </span>'
//Public Method ........................................................................
CountDown.BuildsAndRun = function( TimerArray )
{
for (let TimerParms of TimerArray)
{ CountDown_Build ( TimerParms ) }
setTimeout(() => { CountDown_Run() }, 300); // the Timeout is just for start spectacle
}
// Private Methods......................................................................
CountDown_Build = function( parms )
{
let len = parms.type==='Hours'?6:parms.type==='Minutes'?4:parms.type==='seconds'?2:9
, ctD = { lg : len // countDown number of figure (digits)
, face : ' '.repeat(len) // actuel face of countDown
, fig : [] // array of firures (DOM elements)
, ref : counters.length // ID of this countDown
, time : null // time to add to compute taget time for CountDown
, target : null // target Timie value
, activ : true // to check if count down is activ or not ( finished )
}
// generate all Figures of CountDown
for(let i=len;i--;) { // from len to 0 (just my fav ninja)
ctD.fig.push( eFigure.cloneNode(true) )
}
// CountDown DOM making
let xWrapp = eWrapp.cloneNode(true)
, xTitle = eTitle.cloneNode(true)
, xCountDown = eCountDown.cloneNode(true)
, noFig = 0 // ref on the first ctD.fig list (of figures)
xTitle.innerHTML = parms.title
xWrapp.style.width = len===9?'1105px':len===6?'740px':len===4?'485px':'230px'
//xCountDown.style.width = len===9?'1090px':len===6?'730px':len===4?'470px':'230px'
xWrapp.appendChild(xTitle)
xWrapp.appendChild(xCountDown)
// making of bloc-time elements
for(eBlk of Interface)
{
if(len>eBlk.xL)
{
let xTimeBlock = eTimeBlock.cloneNode(true)
, xCountTitle = eCountTitle.cloneNode(true)
xCountTitle.textContent = eBlk.Title
xTimeBlock.appendChild(xCountTitle)
for(let f=eBlk.Fig;f--;) // (fav ninja again)
{ xTimeBlock.appendChild(ctD.fig[noFig++]) } // move figures inside
xCountDown.appendChild(xTimeBlock)
}
}
document.body.insertBefore(xWrapp, domEndBody) // insert CountDowm on page
// set count down initial values
if (parms.timer) // in case of timer...
{
let TimeInfos = get_DHMS(parms.timer, len )
ctD.time = TimeInfos.add
counters.push( ctD )
activeCounters++
updateInterface( ctD.ref, TimeInfos.dis ) // show first figure faces
}
else if (parms.date) // in case of CountDown until date
{
ctD.target = new Date(parms.date);
counters.push( ctD )
if (showFaceOnNow( ctD.ref ))
{ activeCounters++ }
}
}
CountDown_Run = function()
{
for (let elm of counters)
{
if (elm.time)
{ elm.target = new Date().getTime() + elm.time }
}
let timerInterval = setInterval(_=>
{
counters.forEach((elm,ref)=>
{
if ( elm.activ )
{
if (!showFaceOnNow( ref ))
{ activeCounters-- }
}
if ( activeCounters<=0 )
{ clearInterval(timerInterval) }
})
}
, one_Sec )
}
showFaceOnNow = function(ref)
{
let now = new Date().getTime()
, tim = counters[ref].target - now
, face = '0'.repeat( counters[ref].lg )
if (tim >= 0)
{
face = padZ(Math.floor(tim / one_Day), 3)
face += padZ((Math.floor((tim % one_Day ) / one_Hour)), 2)
face += padZ((Math.floor((tim % one_Hour) / one_Min )), 2)
face += padZ((Math.floor((tim % one_Min ) / one_Sec )), 2)
face = padZ( face, counters[ref].lg )
}
else
{
counters[ref].activ = false
}
updateInterface ( ref, face)
return counters[ref].activ
}
updateInterface = function(ref, newVal)
{
for(let p = counters[ref].lg ; p--;) // update faces figures backward
{
if (counters[ref].face.charAt(p) !== newVal.charAt(p))
{
animateFigure( counters[ref].fig[p], newVal.charAt(p) )
}
}
counters[ref].face = newVal
}
get_DHMS = function (timer_val, lg)
{
let vDelay = { d:0, h:0, m:0, s:0 }
, vNum = '0'
, ret = { add: 0, dis: ''}
for (const c of timer_val)
{
if (/[0-9]/.test(c) ) vNum += c
if (/[dhms]/.test(c) )
{
vDelay[c] = parseInt(vNum)
vNum = '0'
}
}
ret.add = (vDelay.d*one_Day)+(vDelay.h*one_Hour)+(vDelay.m*one_Min)+(vDelay.s*one_Sec)
ret.dis = (padZ(vDelay.d,3)+padZ(vDelay.h,2)+padZ(vDelay.m,2)+padZ(vDelay.s,2)).slice(-lg)
return ret
}
animateFigure = function (domElm, newChar)
{
let eTop = domElm.querySelector('.top')
, eBottom = domElm.querySelector('.bottom')
, eBack_top = domElm.querySelector('.top-back')
// Before we begin, change the back value and the back bottom value
eBack_top.querySelector('span').textContent = newChar
domElm.querySelector('.bottom-back span').textContent = newChar
TweenMax.to(eTop, 0.8, // Then animate
{ rotationX : '-180deg'
, transformPerspective: 300
, ease : Quart.easeOut
, onComplete : function()
{
eTop.textContent = newChar
eBottom.textContent = newChar
TweenMax.set(eTop, { rotationX: 0 })
}
})
TweenMax.to(eBack_top, 0.8, animOpt)
}
}( window.CountDown = window.CountDown || {}));
/********************************************************************************************/
const myCountDowns= [ { title: 'timer <strong>24h</strong>'
, type : 'Hours'
, timer: '24h'
}
, { title: 'Tea cup <strong>2\' 45"</strong>'
, type : 'Minutes'
, timer: '2m 45s'
}
, { title: 'until the new year <strong>2020</strong>'
, type : 'Days'
, date : '01 01 2020' // local Month Day Year
}
]
CountDown.BuildsAndRun( myCountDowns )
// ->type : 'Days' or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration otherwise set a "date" value
// timer string format is _number_UNIT where UNIT = 'd','h','m','s' for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s' = 3 days 0 hours 25 minutes, 6 seconds (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m' = the same, there is no order
// date format is JS Date format see new Date( _STRING_ )
body {
background-color: #f2f1ed;
margin: 0;
}
.wrap {
margin: 2em auto;
height: 270px;
width: 1500px; /* be re-calculate on JS */
border-radius: 1em;
padding: 10px 5px 0 5px;
box-shadow: 0px 0px 1px 1px rgba(170, 170, 170, 0.64);
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 30px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
/* width: 100%; or be re-calculate on JS */
margin: 0 auto;
padding: 0 10px 10px 10px;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure > span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after, .countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top, .countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<link href='https://fonts.googleapis.com/css?family=Lato:300,400,700' rel='stylesheet' type='text/css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<!-- no more HTML code -->
// Create Countdown
var Countdown = {
// Backbone-like structure
$el: $('.countdown'),
// Params
countdown_interval: null,
total_seconds : 0,
// Initialize the countdown
init: function() {
// DOM
this.$ = {
hours : this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours : this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;
// Animate countdown to the end
this.count();
},
count: function() {
var that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if(that.total_seconds > 0) {
--that.values.seconds;
if(that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if(that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
}
else {
clearInterval(that.countdown_interval);
}
}, 1000);
},
animateFigure: function($el, value) {
var that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX : '-180deg',
transformPerspective: 300,
ease : Quart.easeOut,
onComplete : function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, { rotationX: 0 });
}
});
TweenMax.to($back_top, 0.8, {
rotationX : 0,
transformPerspective: 300,
ease : Quart.easeOut,
clearProps : 'all'
});
},
checkHour: function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if(value >= 10) {
// Animate only if the figure has changed
if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
}
else {
// If we are under 10, replace first figure with 0
if(fig_1_value !== '0') this.animateFigure($el_1, 0);
if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
};
function initializeCountdown ( $element ){
let uniqueCountdown = $.extend( {}, Countdown );
uniqueCountdown.$el = $element;
uniqueCountdown.init();
}
$('.countdown').each( function(){
initializeCountdown( $(this) );
});
I've changed the logic with the last function and its subsequent invocation. The method makes a copy of the Countdown to provide a unique this for each object. It then sets the $el it corresponds to before initializing. We then call this method for each of our countdown elements, and since the this is unique, each countdown will operate independently of each other and will allow for countdowns to have different starting times.

CSS 360 rotating progress radial using JS

var ele = document.getElementById("filler");
var deg = 0;
var myInterval = setInterval(function() {
deg = deg + 10;
if (deg > 360) {
clearInterval(myInterval);
}
ele.style.transform = `rotate(${deg}deg)`;
}, 500);
.filler-wrapper {
height: 100px;
width: 100px;
position: relative;
border-radius: 50%;
overflow: hidden;
background: linear-gradient(to left, red 50%, green 50%);
}
.filler {
border-radius: 0 100% 100% 0 / 50%;
display: block;
height: 100%;
margin-left: 50%;
transform-origin: left;
background: green;
transform: rotate(0deg)
}
<div class="filler-wrapper">
<div id="filler" class="filler"></div>
</div>
I have created this radial progress but this works for only 180. How can I make it to rotate 360 deg.
Here is an idea based on this previous answer where you can do this with only background:
var ele = document.getElementById("box");
var deg = -90;
var s = 1;
var myInterval = setInterval(function() {
if(deg >= 90 && s) {
ele.style.setProperty("--s", --s);
deg = -90;
}
deg = deg + 10;
ele.style.setProperty("--v", deg+'deg');
if(deg >= 90 && !s) {
clearInterval(myInterval);
}
}, 500);
#box {
width:100px;
height:100px;
border-radius:50%;
background:
linear-gradient(var(--v), green 50%,transparent 0) center/calc(var(--s)*100%),
linear-gradient(var(--v), red 50%, transparent 0) center/calc(100% - var(--s)*100%),
linear-gradient(to right, green 50%,red 0);
}
<div id="box" style="--v:-90eg;--s:1"></div>
<!-- first cycle : from -90deg to 90deg with s=1 -->
<!-- second cycle : from -90deg to 90deg with s=0 -->
Shortly this will be something trivial with conic-gradient():
var ele = document.getElementById("box");
var deg = 0;
var myInterval = setInterval(function() {
deg = deg + 10;
ele.style.setProperty("--v", deg+'deg');
if(deg >= 360 ) {
clearInterval(myInterval);
}
}, 500);
#box {
width:100px;
height:100px;
border-radius:50%;
background:
conic-gradient(red var(--v,0deg),green var(--v,0deg),green 360deg);
}
<div id="box" ></div>
The above should work only on Chrome
For JS
isCompleted = false;
progressCount = 10;
function updateProgress() {
progressCount = progressCount + 10;
const _count = progressCount * 1.8;
console.log(_count)
if (_count > 180) {
isCompleted = true;
}
if (this.isCompleted) {
return;
}
_rotateSpinner(_count);
}
var elCircleFullFill = document.getElementById("circleFullFill");
var elCircleHalfFill = document.getElementById("circleHalfFill");
var elCircleMaskFull = document.getElementById("circleMaskFull");
var elCircleFillFix = document.getElementById("circleFillFix");
function _rotateSpinner(__progressCount) {
const fillRotation = __progressCount;
const fixRotation = __progressCount * 2;
elCircleFullFill.style = `transform:rotate(${fillRotation}deg)`;
elCircleHalfFill.style = `transform:rotate(${fillRotation}deg)`;
elCircleMaskFull.style = `transform:rotate(${fillRotation}deg)`;
elCircleFillFix.style = `transform:rotate(${fixRotation}deg)`;
}
SCSS
.progress-radial {
width: 50px;
height: 50px;
background-color: #fff;
border-radius: 50%;
.circle {
.circle-mask,
.circle-fill {
width: 50px;
height: 50px;
position: absolute;
border-radius: 50%;
transition: -webkit-transform 1s;
transition: -ms-transform 1s;
transition: transform 1s;
-webkit-backface-visibility: hidden;
}
.circle-mask {
clip: rect(0px, 50px, 50px, 50px/2);
.circle-fill {
clip: rect(0px, 50px/2, 50px, 0px);
background-color: #0096FF;
}
}
}
}
HTML
<div class="progress-radial">
<div class="circle">
<div class="circle-mask" id="circleMaskFull">
<div class="circle-fill" id="circleFullFill"></div>
</div>
<div class="circle-mask">
<div class="circle-fill" id="circleHalfFill"></div>
<div class="circle-fill" id="circleFillFix"></div>
</div>
</div>
</div>
<button onclick="updateProgress()">Update Spinner</button>

Single line with multiple colors based on time in using jquery

I need to generate a graph like I have shown here
Single line with multiple colors over time
The X axis will be time series . Can anyone suggest a JQuery plugin to generate such a graph ?
Thanks
Try below chart and change as per your requirement
var graph = (function(){
var urgentTitle = "Urgent",
$graph = $('.graph'),
$barContainer = $graph.find('.graph-bars'),
$markers = $('.markers'),
$graphTitles = $('.graph-titles'),
max = null,
limit = null;
var init = function(data){
max = getMaxValue(data);
limit = max + Math.ceil(max * 0.05);
$barContainer.empty();
$markers.empty();
$graphTitles.empty();
$('#urgent-title').text(urgentTitle);
setMarkers($markers, limit);
if (data.length) buildTeamRows($barContainer, $graphTitles, data, limit);
else buildUserRows($barContainer, $graphTitles, data, limit);
};
// return a values percentage in relation to the limit
var getPercentage = function(value, limit) {
return value / limit * 100 + "%";
};
var getMaxValue = function(data) {
var largest = 0;
var sum = 0;
if (data.length) {
for (x=0;x<data.length;x++) {
sum = data[x].active + data[x].newCount + data[x].newFromBatch;
if (sum > largest) {
largest = sum;
}
}
} else {
largest = Math.max(data.active, data.newCount, data.newFromBatch);
}
return largest;
};
var setMarkers = function($selector, limit) {
var increment = limit / 5;
var value = 0;
var values = [];
var leftOffset = 0;
// Create array of marker values
while(value < limit) {
values.push(Math.round(value));
value += increment;
}
values.push(limit);
for (var x=0;x<values.length;x++) {
var $markerTmpl = $('<div class="marker"><span class="marker-number"></span></div>');
leftOffset = getPercentage(values[x], limit);
$markerTmpl.css({ 'left': leftOffset }).find('.marker-number').text(values[x]);
$selector.append($markerTmpl);
}
$selector.addClass('loaded');
};
//Build each individual graph based on selector, data, and max value
var buildTeamRows = function($barSelector, $titleSelector, data, limit) {
var percentage;
// Loop through data
for (var x=0;x<data.length;x++) {
var titleClass = null;
var titleCount = 0;
var $graphBar = $('<div class="graph-bar"></div>')
.attr('id', 'userGraph-' + data[x].userId);
$barSelector.append($graphBar);
// Render each fragment
renderFragment($graphBar, 'urgent', data[x].urgent, limit);
renderFragment($graphBar, 'active', data[x].active - data[x].urgent, limit);
renderFragment($graphBar, 'newCount', data[x].newCount, limit);
renderFragment($graphBar, 'newFromBatch', data[x].newFromBatch, limit);
// Calculate largest fragment value
var largest = 0;
$.each(data[x], function(index, value){
if ($.isNumeric(value)){
if (value > largest) {
largest = value;
titleClass = index;
titleCount = value;
}
}
});
// If Active is greatest value, Check if urgent portion of active is greater than active
if (titleClass === 'active' && data[x].urgent >= (data[x].active - data[x].urgent)) {
titleClass = 'urgent';
titleCount = data[x].urgent;
}
// Render row meta-data
var $titleSet = $('<div class="graph-title"><div class="graph-title-name"></div><div class="graph-title-count"></div></div>');
$titleSet.find('.graph-title-name').text(data[x].userName);
$titleSet.find('.graph-title-count').addClass(titleClass).text(titleCount);
$titleSelector.append($titleSet);
}
};
var renderFragment = function($selector, type, value, limit) {
var $rowFragmentTmpl = $('<div class="graph-bar-fragment"></div>');
var percentage = getPercentage(value, limit);
$rowFragmentTmpl.attr('data-value', value);
$selector.append($rowFragmentTmpl.addClass(type));
setTimeout(function(){
$rowFragmentTmpl.css({'width': percentage});
}, 1);
};
var buildUserRows = function($barSelector, $titleSelector, data, limit) {
renderUserRow($barSelector, $titleSelector, 'urgent', data.urgent, limit, urgentTitle);
renderUserRow($barSelector, $titleSelector, 'active', data.active, limit, 'Active');
renderUserRow($barSelector, $titleSelector, 'newCount', data.newCount, limit, 'New');
renderUserRow($barSelector, $titleSelector, 'newFromBatch', data.newFromBatch, limit, 'New From Batch');
};
var renderUserRow = function($barSelector, $titleSelector, type, value, limit, title) {
var percentage = getPercentage(value, limit);
var $graphBar = $('<div class="graph-bar graph-bar-single"></div>').attr({'id' : 'userGraph-' + type, 'data-value': value});
$barSelector.append($graphBar);
setTimeout(function(){
$graphBar.css({'width': percentage}).addClass(type);
},1);
var $titleSet = $('<div class="graph-title"><div class="graph-title-name"></div><div class="graph-title-count"></div></div>');
$titleSet.find('.graph-title-name').text(title);
$titleSet.find('.graph-title-count').addClass(type).text(value);
$titleSelector.append($titleSet);
};
return {
init: init
}
})();
// Document ready
$(function(){
// Dummy Data
var dataSet = [
{
active: 5,
newCount: 4,
newFromBatch: 40,
urgent: 1,
userId: "molly",
userName: "Molly"
},
{
active: 21,
newCount: 2,
newFromBatch: 5,
urgent: 10,
userId: "jack",
userName: "Jack"
},
{
active: 25,
newCount: 4,
newFromBatch: 3,
urgent: 20,
userId: "tracy",
userName: "Tracy"
},
{
active: 10,
newCount: 24,
newFromBatch: 4,
urgent: 2,
userId: "nolan",
userName: "Nolan"
},
];
var dataSingle = {
active: 25,
newCount: 4,
newFromBatch: 3,
urgent: 20,
userId: "ryan",
userName: "Ryan Scofield"
};
// Initialize Graph
graph.init(dataSet);
$('#teamGraph').on('click', function(e){
graph.init(dataSet);
});
$('#userGraph').on('click', function(e){
graph.init(dataSingle);
});
});
body {
padding: 20px;
}
/* Opportunity Graphs */
.graph-titles {
display: inline-block;
width: 200px;
vertical-align: top;
margin: 20px 0 20px;
padding: 0;
}
.graph-title {
margin-bottom: 1em;
width: 100%;
line-height: 30px;
overflow: hidden;
}
.graph-title-name {
float: left;
}
.graph-title-count {
float: right;
padding: 0 10px;
height: 30px;
border-radius: 20px;
color: #fff;
}
.graph {
display: inline-block;
position: relative;
margin: 20px 20px 20px 10px;
padding: 0;
width: 500px;
}
.graph-bar {
display: block;
overflow: hidden;
margin-bottom: 1em;
}
.graph-bar-fragment {
width: 0;
height: 30px;
float: left;
background-color: #ccc;
-webkit-transition: width .4s ease-in;
}
.graph-bar-single {
height: 30px;
background-color: #ccc;
-webkit-transition: width .4s ease-in;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.graph-bar-fragment:last-child {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.urgent {
background: #c9575e;
background: -moz-linear-gradient(top, #c9575e 0%, #c12e41 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #c9575e), color-stop(100%, #c12e41));
background: -webkit-linear-gradient(top, #c9575e 0%, #c12e41 100%);
background: -o-linear-gradient(top, #c9575e 0%, #c12e41 100%);
background: -ms-linear-gradient(top, #c9575e 0%, #c12e41 100%);
background: linear-gradient(to bottom, #c9575e 0%, #c12e41 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#c9575e', endColorstr='#c12e41',GradientType=0 );
}
.active {
background: #d6ac6e;
background: -moz-linear-gradient(top, #d6ac6e 0%, #cc9e52 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #d6ac6e), color-stop(100%, #cc9e52));
background: -webkit-linear-gradient(top, #d6ac6e 0%, #cc9e52 100%);
background: -o-linear-gradient(top, #d6ac6e 0%, #cc9e52 100%);
background: -ms-linear-gradient(top, #d6ac6e 0%, #cc9e52 100%);
background: linear-gradient(to bottom, #d6ac6e 0%, #cc9e52 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d6ac6e', endColorstr='#cc9e52',GradientType=0 );
}
.newCount {
background: #6db683;
background: -moz-linear-gradient(top, #6db683 0%, #569b6d 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #6db683), color-stop(100%, #569b6d));
background: -webkit-linear-gradient(top, #6db683 0%, #569b6d 100%);
background: -o-linear-gradient(top, #6db683 0%, #569b6d 100%);
background: -ms-linear-gradient(top, #6db683 0%, #569b6d 100%);
background: linear-gradient(to bottom, #6db683 0%, #569b6d 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6db683', endColorstr='#569b6d',GradientType=0 );
}
.newFromBatch {
background: #7f8cc4;
background: -moz-linear-gradient(top, #7f8cc4 0%, #6477ac 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #7f8cc4), color-stop(100%, #6477ac));
background: -webkit-linear-gradient(top, #7f8cc4 0%, #6477ac 100%);
background: -o-linear-gradient(top, #7f8cc4 0%, #6477ac 100%);
background: -ms-linear-gradient(top, #7f8cc4 0%, #6477ac 100%);
background: linear-gradient(to bottom, #7f8cc4 0%, #6477ac 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7f8cc4', endColorstr='#6477ac',GradientType=0 );
}
.markers {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
opacity: 0;
visibility: hidden;
-webkit-transition: opacity .4s ease-in;
}
.markers.loaded {
visibility: visible;
opacity: 1;
}
.marker {
-webkit-box-sizing: border-box;
position: absolute;
bottom: -2em;
top: 0;
border-left: 2px solid #e6e6e6;
}
.marker-number {
position: absolute;
padding-left: .5em;
bottom: 0;
text-align: right;
}
.marker:last-child .marker-number {
right: 0;
padding-left: 0;
padding-right: .5em;
}
.graph-key {
margin: 20px 0 0 210px;
}
.graph-key-item {
display: inline-block;
margin-right: 1.5em;
}
.graph-key-dot {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 50%;
margin-right: .5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="graph-container">
<div class="graph-titles">
<!-- Populated -->
</div>
<div class="graph">
<div class="graph-bars">
<!-- Populated -->
</div>
<div class="markers">
<!-- Populated -->
</div>
</div>
<div class="graph-key">
<div class="graph-key-item">
<span class="graph-key-dot urgent"></span><span id="urgent-title">Urgent</span>
</div>
<div class="graph-key-item">
<span class="graph-key-dot active"></span><span>Active</span>
</div>
<div class="graph-key-item">
<span class="graph-key-dot newCount"></span><span>New</span>
</div>
<div class="graph-key-item">
<span class="graph-key-dot newFromBatch"></span><span>New From Batch</span>
</div>
</div>
</div>
<button id="teamGraph">Team Graph</button>
<button id="userGraph">User Graph</button>
Try below chart and change value as per your requirement
var chart = new Chartist.Bar('#chart01',
{
labels: ['C-Level', 'Executive', 'Director', 'Manager', 'Professional', 'Other'],
series: [
[3,9,5,8,4,2],
[2,8,4,19,25,6],
[2,16,6,53,57,12]
]
},
{
stackBars: true,
seriesBarDistance: 10,
reverseData: false,
horizontalBars: true,
low: 0,
fullWidth: true,
chartPadding: {
right: 30,
left: 30
},
axisX: {
showGrid: true,
showLabel: true
},
axisY: {
showGrid: false,
showLabel: true,
offset: 60,
onlyInteger: true,
labelInterpolationFnc: function(value) {
return value;
}
}
});
$('#chart01').on('click', '.ct-chart-bar .ct-labels foreignobject', function(evt) {
var index = $(this).index();
var label = $(this).find('span.ct-label').text();
graphClicked(index, label, null);
});
$('#chart01').on('mouseover', '.ct-chart-bar .ct-series-a line, .ct-chart-bar .ct-series-b line, .ct-chart-bar .ct-series-c line', function(evt) {
var index = $(this).index();
$(this).closest('.ct-chart-bar').find('.ct-labels foreignobject:nth-child('+(index+1)+') span').addClass('hover');
});
$('#chart01').on('mouseleave', '.ct-chart-bar .ct-series-a line, .ct-chart-bar .ct-series-b line, .ct-chart-bar .ct-series-c line', function(evt) {
var index = $(this).index();
$(this).closest('.ct-chart-bar').find('.ct-labels foreignobject:nth-child('+(index+1)+') span').removeClass('hover');
});
$('#chart01').on('click', '.ct-chart-bar .ct-series-a line, .ct-chart-bar .ct-series-b line, .ct-chart-bar .ct-series-c line', function(evt) {
var index = $(this).index();
var label = $(this).closest('.ct-chart-bar').find('.ct-labels foreignobject:nth-child('+(index+1)+') span').text();
var value = $(this).attr('ct:value');
graphClicked(index, label, value);
});
function graphClicked(index, label, value) {
console.log('---');
console.log('index:', index);
console.log('label:', label);
alert('Index: '+index+', Label: '+label+', Value: '+value);
}
html {
background-color: lightgrey;
}
.chart-wrapper {
width: 50%;
margin: 1rem auto;
background-color: white;
padding: 0.1rem 0.5rem 1rem 0.5rem;
}
h3 {
text-align: center;
}
h4 {
text-align: center;
}
.center-link {
text-align: center;
display: block;
font-size: 0.7rem;
}
.ct-line {
stroke-dasharray: 2000;
stroke-dashoffset: 2000;
}
.ct-series-a .ct-line {
animation: dash 5s linear forwards;
animation-delay: 1s;
}
.ct-series-a .ct-line, .ct-series-a .ct-point, .ct-series-a .ct-bar {
stroke: #5b9bd5;
}
.ct-series-b .ct-line {
animation: dash 5s linear forwards;
animation-delay: 2s;
}
.ct-series-b .ct-line, .ct-series-b .ct-point, .ct-series-b .ct-bar {
stroke: #ed7d31;
}
.ct-series-c .ct-line {
animation: dash 5s linear forwards;
animation-delay: 3s;
}
.ct-series-c .ct-line, .ct-series-c .ct-point, .ct-series-c .ct-bar {
stroke: #a5a5a5;
}
.chart-title {
text-align: center;
color: #555;
margin-bottom: 0.5rem;
}
.key {
font-size: 0.7rem;
color: #555;
padding: 0 30px 0 90px;
}
.key .key-element {
width: 32%;
display: inline-block;
padding-left: 22px;
box-sizing: border-box;
position: relative;
}
.key .key-element:before {
content: "";
display: block;
width: 16px;
height: 16px;
position: absolute;
top: -2px;
left: 0;
}
.key .key-element.key-series-a:before {
background-color: #5b9bd5;
}
.key .key-element.key-series-b:before {
background-color: #ed7d31;
}
.key .key-element.key-series-c:before {
background-color: #a5a5a5;
}
.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end {
display: block;
position: relative;
left: -50%;
text-align: center;
}
.ct-chart-bar .ct-labels foreignobject {
cursor: pointer;
}
.ct-chart-bar .ct-labels foreignobject span {
text-decoration: none;
}
.ct-chart-bar .ct-labels foreignobject span:hover, .ct-chart-bar .ct-labels foreignobject span.hover {
text-decoration: underline;
}
.ct-chart-bar .ct-series line {
cursor: pointer;
}
#keyframes dash {
to {
stroke-dashoffset: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartist/0.9.7/chartist.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/chartist/0.9.7/chartist.min.css" rel="stylesheet" />
<div class="chart-wrapper">
<h4>Click on the bars to get their index, label and value</h4>
<div id="chart01" class="ct-chart ct-chart01 ct-octave"></div>
<div class="key">
<div class="key-element key-series-a">Account Topic Score</div>
<div class="key-element key-series-b">#Unique Contacts</div>
<div class="key-element key-series-c">#Interactions</div>
</div>
</div>

Displaying caption for this image plugin

This plugins default technique of displaying caption involves, extracting the content of the "alt" attribute from the corresponding image which it targets.
captionOn = function()
{
var description = $( 'a[href="' + $( '#imagelightbox' ).attr( 'src' ) + '"] img' ).attr( 'alt' );
if( description.length > 0 )
$( '<div id="imagelightbox-caption">' + description + '</div>' ).appendTo( 'body' );
},
captionOff = function()
{
$( '#imagelightbox-caption' ).remove();
},
The design I am working on requires more content to be included for the caption, like comments, date, etc.
So obviously those details can't be included in the "alt" tag of an image. Will require separate "div" for that.
How can I modify the above "description" variable in the JS which would pick the "div#caption" for that image, and display its content?
<img class="social-img" src="cwc/21.jpg" alt="lorem sit amet" /><div id="caption">lorem sit amet</div>
Since this is an image gallery, there will be lot of that HTML code replicated. So the concern I am facing is that when somebody clicks that image, it should only show the "div#caption" for that particular image.
http://codepen.io/arjunmenon/pen/NqqyJe - Default implementation
$(function() {
// ACTIVITY INDICATOR
var activityIndicatorOn = function() {
$('<div id="imagelightbox-loading"><div></div></div>').appendTo('body');
},
activityIndicatorOff = function() {
$('#imagelightbox-loading').remove();
},
// OVERLAY
overlayOn = function() {
$('<div id="imagelightbox-overlay"></div>').appendTo('body');
},
overlayOff = function() {
$('#imagelightbox-overlay').remove();
},
// CLOSE BUTTON
closeButtonOn = function(instance) {
$('<button type="button" id="imagelightbox-close" title="Close"></button>').appendTo('body').on('click touchend', function() {
$(this).remove();
instance.quitImageLightbox();
return false;
});
},
closeButtonOff = function() {
$('#imagelightbox-close').remove();
},
// CAPTION
captionOn = function() {
var description = $('a[href="' + $('#imagelightbox').attr('src') + '"] img').attr('alt');
if (description.length > 0)
$('<div id="imagelightbox-caption">' + description + '</div>').appendTo('body');
},
captionOff = function() {
$('#imagelightbox-caption').remove();
},
// NAVIGATION
navigationOn = function(instance, selector) {
var images = $(selector);
if (images.length) {
var nav = $('<div id="imagelightbox-nav"></div>');
for (var i = 0; i < images.length; i++)
nav.append('<button type="button"></button>');
nav.appendTo('body');
nav.on('click touchend', function() {
return false;
});
var navItems = nav.find('button');
navItems.on('click touchend', function() {
var $this = $(this);
if (images.eq($this.index()).attr('href') != $('#imagelightbox').attr('src'))
instance.switchImageLightbox($this.index());
navItems.removeClass('active');
navItems.eq($this.index()).addClass('active');
return false;
})
.on('touchend', function() {
return false;
});
}
},
navigationUpdate = function(selector) {
var items = $('#imagelightbox-nav button');
items.removeClass('active');
items.eq($(selector).filter('[href="' + $('#imagelightbox').attr('src') + '"]').index(selector)).addClass('active');
},
navigationOff = function() {
$('#imagelightbox-nav').remove();
},
// ARROWS
arrowsOn = function(instance, selector) {
var $arrows = $('<button type="button" class="imagelightbox-arrow imagelightbox-arrow-left"></button><button type="button" class="imagelightbox-arrow imagelightbox-arrow-right"></button>');
$arrows.appendTo('body');
$arrows.on('click touchend', function(e) {
e.preventDefault();
var $this = $(this),
$target = $(selector + '[href="' + $('#imagelightbox').attr('src') + '"]'),
index = $target.index(selector);
if ($this.hasClass('imagelightbox-arrow-left')) {
index = index - 1;
if (!$(selector).eq(index).length)
index = $(selector).length;
} else {
index = index + 1;
if (!$(selector).eq(index).length)
index = 0;
}
instance.switchImageLightbox(index);
return false;
});
},
arrowsOff = function() {
$('.imagelightbox-arrow').remove();
};
// WITH ACTIVITY INDICATION
$('a[data-imagelightbox="a"]').imageLightbox({
onLoadStart: function() {
activityIndicatorOn();
},
onLoadEnd: function() {
activityIndicatorOff();
},
onEnd: function() {
activityIndicatorOff();
}
});
// WITH OVERLAY & ACTIVITY INDICATION
$('a[data-imagelightbox="b"]').imageLightbox({
onStart: function() {
overlayOn();
},
onEnd: function() {
overlayOff();
activityIndicatorOff();
},
onLoadStart: function() {
activityIndicatorOn();
},
onLoadEnd: function() {
activityIndicatorOff();
}
});
// WITH "CLOSE" BUTTON & ACTIVITY INDICATION
var instanceC = $('a[data-imagelightbox="c"]').imageLightbox({
quitOnDocClick: false,
onStart: function() {
closeButtonOn(instanceC);
},
onEnd: function() {
closeButtonOff();
activityIndicatorOff();
},
onLoadStart: function() {
activityIndicatorOn();
},
onLoadEnd: function() {
activityIndicatorOff();
}
});
// WITH CAPTION & ACTIVITY INDICATION
$('a[data-imagelightbox="d"]').imageLightbox({
onLoadStart: function() {
captionOff();
activityIndicatorOn();
},
onLoadEnd: function() {
captionOn();
activityIndicatorOff();
},
onEnd: function() {
captionOff();
activityIndicatorOff();
}
});
// WITH ARROWS & ACTIVITY INDICATION
var selectorG = 'a[data-imagelightbox="g"]';
var instanceG = $(selectorG).imageLightbox({
onStart: function() {
arrowsOn(instanceG, selectorG);
},
onEnd: function() {
arrowsOff();
activityIndicatorOff();
},
onLoadStart: function() {
activityIndicatorOn();
},
onLoadEnd: function() {
$('.imagelightbox-arrow').css('display', 'block');
activityIndicatorOff();
}
});
// WITH NAVIGATION & ACTIVITY INDICATION
var selectorE = 'a[data-imagelightbox="e"]';
var instanceE = $(selectorE).imageLightbox({
onStart: function() {
navigationOn(instanceE, selectorE);
},
onEnd: function() {
navigationOff();
activityIndicatorOff();
},
onLoadStart: function() {
activityIndicatorOn();
},
onLoadEnd: function() {
navigationUpdate(selectorE);
activityIndicatorOff();
}
});
// ALL COMBINED
var selectorF = 'a[data-imagelightbox="f"]';
var instanceF = $(selectorF).imageLightbox({
onStart: function() {
overlayOn();
closeButtonOn(instanceF);
arrowsOn(instanceF, selectorF);
},
onEnd: function() {
overlayOff();
captionOff();
closeButtonOff();
arrowsOff();
activityIndicatorOff();
},
onLoadStart: function() {
captionOff();
activityIndicatorOn();
},
onLoadEnd: function() {
captionOn();
activityIndicatorOff();
$('.imagelightbox-arrow').css('display', 'block');
}
});
});
#imagelightbox {
cursor: pointer;
position: fixed;
z-index: 10000;
-ms-touch-action: none;
touch-action: none;
-webkit-box-shadow: 0 0 3.125em rgba(0, 0, 0, .75);
/* 50 */
box-shadow: 0 0 3.125em rgba(0, 0, 0, .75);
/* 50 */
}
/* ACTIVITY INDICATION */
#imagelightbox-loading,
#imagelightbox-loading div {
border-radius: 50%;
}
#imagelightbox-loading {
width: 2.5em;
/* 40 */
height: 2.5em;
/* 40 */
background-color: #444;
background-color: rgba(0, 0, 0, .5);
position: fixed;
z-index: 10003;
top: 50%;
left: 50%;
padding: 0.625em;
/* 10 */
margin: -1.25em 0 0 -1.25em;
/* 20 */
-webkit-box-shadow: 0 0 2.5em rgba(0, 0, 0, .75);
/* 40 */
box-shadow: 0 0 2.5em rgba(0, 0, 0, .75);
/* 40 */
}
#imagelightbox-loading div {
width: 1.25em;
/* 20 */
height: 1.25em;
/* 20 */
background-color: #fff;
-webkit-animation: imagelightbox-loading .5s ease infinite;
animation: imagelightbox-loading .5s ease infinite;
}
#-webkit-keyframes imagelightbox-loading {
from {
opacity: .5;
-webkit-transform: scale(.75);
}
50% {
opacity: 1;
-webkit-transform: scale(1);
}
to {
opacity: .5;
-webkit-transform: scale(.75);
}
}
#keyframes imagelightbox-loading {
from {
opacity: .5;
transform: scale(.75);
}
50% {
opacity: 1;
transform: scale(1);
}
to {
opacity: .5;
transform: scale(.75);
}
}
/* OVERLAY */
#imagelightbox-overlay {
background-color: #fff;
background-color: rgba(255, 255, 255, .9);
position: fixed;
z-index: 9998;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
/* "CLOSE" BUTTON */
#imagelightbox-close {
width: 2.5em;
/* 40 */
height: 2.5em;
/* 40 */
text-align: left;
background-color: #666;
border-radius: 50%;
position: fixed;
z-index: 10002;
top: 2.5em;
/* 40 */
right: 2.5em;
/* 40 */
-webkit-transition: color .3s ease;
transition: color .3s ease;
}
#imagelightbox-close:hover,
#imagelightbox-close:focus {
background-color: #111;
}
#imagelightbox-close:before,
#imagelightbox-close:after {
width: 2px;
background-color: #fff;
content: '';
position: absolute;
top: 20%;
bottom: 20%;
left: 50%;
margin-left: -1px;
}
#imagelightbox-close:before {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
#imagelightbox-close:after {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
/* CAPTION */
#imagelightbox-caption {
text-align: center;
color: #fff;
background-color: #666;
position: fixed;
z-index: 10001;
left: 0;
right: 0;
bottom: 0;
padding: 0.625em;
}
/* 10 */
#caption {
color: #fff;
background-color: #666;
position: fixed;
z-index: 10001;
top: 0;
right: 0;
width: 25%;
height: auto;
min-height: 100%;
padding: 0.625em;
}
/* NAVIGATION */
#imagelightbox-nav {
background-color: #444;
background-color: rgba(0, 0, 0, .5);
border-radius: 20px;
position: fixed;
z-index: 10001;
left: 50%;
bottom: 3.75em;
/* 60 */
padding: 0.313em;
/* 5 */
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
#imagelightbox-nav button {
width: 1em;
/* 20 */
height: 1em;
/* 20 */
background-color: transparent;
border: 1px solid #fff;
border-radius: 50%;
display: inline-block;
margin: 0 0.313em;
/* 5 */
}
#imagelightbox-nav button.active {
background-color: #fff;
}
/* ARROWS */
.imagelightbox-arrow {
width: 3.75em;
/* 60 */
height: 7.5em;
/* 120 */
background-color: #444;
background-color: rgba(0, 0, 0, .5);
vertical-align: middle;
display: none;
position: fixed;
z-index: 10001;
top: 50%;
margin-top: -3.75em;
/* 60 */
}
.imagelightbox-arrow:hover,
.imagelightbox-arrow:focus {
background-color: #666;
background-color: rgba(0, 0, 0, .75);
}
.imagelightbox-arrow:active {
background-color: #111;
}
.imagelightbox-arrow-left {
left: 2.5em;
/* 40 */
}
.imagelightbox-arrow-right {
right: 2.5em;
/* 40 */
}
.imagelightbox-arrow:before {
width: 0;
height: 0;
border: 1em solid transparent;
content: '';
display: inline-block;
margin-bottom: -0.125em;
/* 2 */
}
.imagelightbox-arrow-left:before {
border-left: none;
border-right-color: #fff;
margin-left: -0.313em;
/* 5 */
}
.imagelightbox-arrow-right:before {
border-right: none;
border-left-color: #fff;
margin-right: -0.313em;
/* 5 */
}
#imagelightbox-loading,
#imagelightbox-overlay,
#imagelightbox-close,
#imagelightbox-caption,
#imagelightbox-nav,
.imagelightbox-arrow {
-webkit-animation: fade-in .25s linear;
animation: fade-in .25s linear;
}
#-webkit-keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#media only screen and (max-width: 41.250em)
/* 660 */
{
#container {
width: 100%;
}
#imagelightbox-close {
top: 1.25em;
/* 20 */
right: 1.25em;
/* 20 */
}
#imagelightbox-nav {
bottom: 1.25em;
/* 20 */
}
.imagelightbox-arrow {
width: 2.5em;
/* 40 */
height: 3.75em;
/* 60 */
margin-top: -2.75em;
/* 30 */
}
.imagelightbox-arrow-left {
left: 1.25em;
/* 20 */
}
.imagelightbox-arrow-right {
right: 1.25em;
/* 20 */
}
}
#media only screen and (max-width: 20em)
/* 320 */
{
.imagelightbox-arrow-left {
left: 0;
}
.imagelightbox-arrow-right {
right: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
<a href="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/full/7.jpg" data-imagelightbox="d">
<img src="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/thumb/7.jpg" alt="The end of the railway" />
</a>
</li>
<li>
<a href="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/full/8.jpg" data-imagelightbox="d">
<img src="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/thumb/8.jpg" alt="Railway in Klaipeda" />
</a>
</li>
<li>
<a href="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/full/9.jpg" data-imagelightbox="d">
<img src="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/thumb/9.jpg" alt="Herkaus Manto street in Klaipeda" />
</a>
</li>
</ul>
<script src="http://osvaldas.info/examples/image-lightbox-responsive-touch-friendly/imagelightbox.min.js"></script>
Thanks
Replace this line:
var description = $( 'a[href="' + $( '#imagelightbox' ).attr( 'src' ) + '"] img' ).attr( 'alt' );
...with this one:
var description = $( 'a[href="' + $( '#imagelightbox' ).attr( 'src' ) + '"] ' ).find( '#caption' ).html();

Categories

Resources