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.
Related
I'm modifying a memory game (originally in this repo) which shows a pop up message with the game results once the game is completed:
When the pop up message is introduced, the rest of the screen is assigned a "game-over" css class that darkens the screen (behind the pop up).
//function for what happens when all pairs are found and the game is over
function gameOver() {
stopWatch();
$('.container').addClass('animated rotateIn');
messageWinning();
}
//function for the popup message on winning
function messageWinning() {
$(`<section class="game-over"><div class="message-box" > <h2>Yay! You have found all pairs!</h2><p>Number of attempts: ${attempts}</p><p>Time required: ${showMinutes}:${showSeconds} </p><p>Level: ${stars} </p><p><i class="fas fa-undo"></i></p></section>`).insertAfter($('.game'));
$('.message-box').fadeIn(1);
}
How can I add some js that will let me to close the pop up message AND at the same time remove the "game-over" class, so the user can see their cards once they have completed the game?
What I've done so far but hasn't worked:
I added the following code to the js file to remove the "game-over" class but this never worked. I also tried it without the parent() variation but still no results.
$('.message-box').click(function(){
$(this).parent().removeClass('game-over');
});
Add this <div class="close-popup"> to inside message-box popup.
<div class="close-popup">Close</div>
Add below CSS to place the close top of the right side of the popup.
.message-box {
position: relative;
}
.close-popup {
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
}
On click of close hide .message-box and remove .game-over class from a parent.
$(document).on('click', '.close-popup', function() {
$('.message-box').hide().parent().removeClass('game-over');
createBoard();
});
Check below snippet
$(function() {
//DECLARATION OF VARIABLES
const memoryBoard = $('#memory-game');
//array that holds the values for the memory cards
let cardArray = ['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D', 'E', 'E', 'F', 'F', 'G', 'G', 'H', 'H'];
let comparisonArray = [];
//
let attempts = 0; //counts how many attempts a player has made
let stars = '<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i>'; //stores the stars to display
let clickCount = 0; //counts if this is the first click in an attempt
let pairs = 0; //counts how many pairs have already been discovered
let cardID = ''; //stores the card ID of solved pairs
let seconds = 00;
let tens = 00;
let minutes = 00;
let appendSeconds = $("#seconds");
let appendMinutes = $("#minutes");
let showSeconds = "00";
let showMinutes = "00";
let Interval;
//on page load
createBoard();
//EVENT TRIGGERS
//when clicking the undo icon reload the page
$(document).on('click', '.fa-undo', function() {
location.reload();
});
$('.card').click(function(event) {
//if this is the initial click, start the stopwatch
if (attempts === 0) {
startWatch();
};
//flip the card if it isn't already open or the comparison array full
if ($(this).hasClass("flipped") || $(this).hasClass("solved") || comparisonArray.length >= 2) {
return;
} else {
flipCard($(event.target).parent());
};
//open the card and store the card information in an array
comparisonArray.push($(this).data("card-type"));
//if this is the first card clicked simply count the click and number of attempts
if (clickCount === 0) {
clickCount++;
recordAttempts();
} else {
//if this is the second card clicked compare whether it is the same as the other stored card. If yes, add to the number of pairs and change the css attribute to permanently leave the card open.
if (comparisonArray[0] === comparisonArray[1]) {
$("[data-card-type=" + comparisonArray[0] + "]").removeClass('flipped').addClass('solved');
$("[data-card-type=" + comparisonArray[0] + "]").parent().addClass('animated pulse');
pairs++;
if (pairs === 8) {
gameOver();
}
};
//close all unsuccessfully opened cards and clear the comparison array with a short delay
setTimeout(function() {
flipCard($('.flipped'));
comparisonArray = [];
}, 1000);
//reset the click count
clickCount = 0;
}
});
//FUNCTIONS
//function to flip cards
function flipCard(element) {
$(element).toggleClass('flipped');
}
//function to record the number of attempts of a player and to reduce the number of stars based on performance
function recordAttempts() {
attempts++;
$('#attempts').html(attempts);
if (attempts > 16 && attempts < 24) {
stars = '<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else if (attempts >= 24 && attempts < 32) {
stars = '<i class="fas fa-star"></i><i class="far fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else if (attempts >= 32) {
stars = '<i class="far fa-star"></i><i class="far fa-star"></i><i class="far fa-star"></i>';
$('#stars').html(stars);
} else {
return;
};
}
//function to create the memory board
function createBoard() {
cardArray = shuffle(cardArray);
memoryBoard.html('');
for (i = 1; i <= cardArray.length; i++) {
memoryBoard.append($(`<div class='container'><div class='card' data-card-type='${cardArray[i-1]}'><figure class='front'></figure><figure class='back'></figure></div></div>'`));
}
};
//function for what happens when all pairs are found and the game is over
function gameOver() {
stopWatch();
$('.container').addClass('animated infinite rotateIn');
messageWinning();
}
//function for the popup message on winning
function messageWinning() {
$(`<section class="game-over"><div class="message-box"><div class="close-popup">Close</div><h2>Yay! You have found all pairs!</h2><p>Number of attempts: ${attempts}</p><p>Time required: ${showMinutes}:${showSeconds} </p><p>Level: ${stars} </p><p><i class="fas fa-undo"></i></p></div></section>`).insertAfter($('.game'));
$('.message-box').fadeIn(1000);
}
// shuffle function from http://stackoverflow.com/a/2450976
function shuffle(array) {
var currentIndex = array.length,
temporaryValue, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//Stopwatch function, based on https://www.cssscript.com/a-minimal-pure-javascript-stopwatch/
function stopWatch() {
clearInterval(Interval);
}
function startWatch() {
clearInterval(Interval);
Interval = setInterval(startTimer, 10);
function startTimer() {
tens++;
if (tens > 99) {
seconds++;
showSeconds = "0" + seconds;
appendSeconds.html(showSeconds);
tens = 0;
}
if (seconds > 9) {
showSeconds = seconds;
appendSeconds.html(showSeconds);
}
if (seconds > 59) {
minutes++;
showMinutes = "0" + minutes;
appendMinutes.html(showMinutes);
seconds = 0;
showSeconds = "0" + 0;
appendSeconds.html(showSeconds);
}
if (minutes > 9) {
showMinutes = minutes;
appendMinutes.html(showMinutes);
}
}
}
$(document).on('click', '.close-popup', function() {
$('.message-box').hide().parent().removeClass('game-over');
createBoard();
});
});
/* ...............................
GLOBAL SETTINGS
.................................*/
/* COLOR PALETTE
credit to http://colorpalettes.net/color-palette-1298/
#a6d5e5
#85c3b4
#fbed60
#96bce9
#ddcfe8
*/
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
body,
html {
background: #fff;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
color: #555;
font-size: 16px;
overflow-x: hidden;
text-align: center;
background: #ffffff;
}
h1 {
font-family: 'Amatic SC', cursive;
font-size: 300%;
padding: 20px;
}
h2 {
margin: 5% 0;
color: #000000;
font-weight: 300;
}
.fa-star {
color: #fbed60;
}
p {
margin: 1%;
}
a {
text-decoration: none;
color: #000;
}
.fa-undo {
padding: 0 20% 20% 20%;
}
.message-box .fa-undo {
padding: 10%;
}
.fa-undo:hover {
cursor: pointer;
}
/* ...............................
GENERAL PAGE LAYOUT
.................................*/
header::before,
footer::after {
display: block;
content: '';
width: 100%;
background: #fbed60;
height: 20px;
}
header {
margin: auto;
background: #ffff92;
-webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
}
footer {
margin: 20px 0 0 0;
background: #f5f5f5;
}
footer div {
font-size: 80%;
padding: 10px;
}
/* ...............................
SPECIFIC SETTINGS
.................................*/
.game {
max-width: 550px;
margin: auto;
}
/* STATISTICS */
.stats {
margin: 30px 0 10px 0;
}
ul.stats {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
}
ul.stats li {
display: inline-block;
padding: 5px;
width: 25%;
}
/* CARDBOARD */
/* card with equal height and width on resizing , credit to http://www.mademyday.de/css-height-equals-width-with-pure-css.html/ */
.container {
display: inline-block;
width: 23%;
margin: 1%;
position: relative;
-webkit-perspective: 800px;
perspective: 800px;
}
.container::before {
content: "";
display: block;
padding-top: 100%;
}
/*card flip effect, credit to https://desandro.github.io/3dtransforms/docs/card-flip.html */
.card {
width: 100%;
height: 100%;
position: absolute;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transition: -webkit-transform 0.3s;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.card figure {
margin: 0;
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
border-radius: 10px 5px;
-webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
}
.card figure:hover {
-webkit-box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.front {
background-color: #85c3b4;
}
.back {
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
}
.card.flipped,
.card.solved {
-webkit-transform: rotateY( 180deg);
transform: rotateY( 180deg);
}
/* Card Backgrounds */
[data-card-type="A"] .back {
background: #f5f5f5 url('https://via.placeholder.com/150.jpg');
}
[data-card-type="B"] .back {
background: #f5f5f5 url('https://via.placeholder.com/151.jpg');
}
[data-card-type="C"] .back {
background: #f5f5f5 url('https://via.placeholder.com/152.jpg');
}
[data-card-type="D"] .back {
background: #f5f5f5 url('https://via.placeholder.com/153.jpg');
}
[data-card-type="E"] .back {
background: #f5f5f5 url('https://via.placeholder.com/154.jpg');
}
[data-card-type="F"] .back {
background: #f5f5f5 url('https://via.placeholder.com/155.jpg');
}
[data-card-type="G"] .back {
background: #f5f5f5 url('https://via.placeholder.com/156.jpg');
}
[data-card-type="H"] .back {
background: #f5f5f5 url('https://via.placeholder.com/157.jpg');
}
/* POPUP MESSAGE ON WINNING */
.game-over {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
z-index: 2;
}
.message-box {
background: rgb(255, 255, 255);
width: 70%;
max-width: 500px;
max-height: 500px;
display: -webkit-box;
display: -ms-flexbox;
display: none;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-flow: column;
flex-flow: column;
padding: 5%;
border: 5px solid #fbed60;
border-radius: 20px;
}
.message-box {
position: relative;
}
.close-popup {
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Memory Card Game</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.9/css/all.css">
<link href="https://fonts.googleapis.com/css?family=Amatic+SC|Open+Sans:300" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css#3.5.2/animate.min.css">
</head>
<body>
<header>
<h1>Memory Card Game</h1>
</header>
<main>
<section class="game">
<ul class="stats">
<li id="stars"><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i></li>
<li>
<p>Attempts</p>
<p id="attempts">0</p>
</li>
<li><i class="fas fa-hourglass-start"></i>
<p><span id="minutes">00</span>:<span id="seconds">00</span></p>
</li>
<li><i class="fas fa-undo"></i></li>
</ul>
<div id="memory-game">
</div>
</section>
</main>
<footer>
<div>Icons made by Smashicons from www.flaticon.com are licensed by <a href="http://creativecommons.org/licenses/by/3.0/"
title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
</footer>
</body>
</html>
How could one implement mobile touch on this code to make the range slider work on mobile?
I found a lot of tutorials on the internet but they all contained jquery ui but I have a range slider without ui and I'm not good at JS.
$("document").ready(function() {
const rangeSliderAmount = document.querySelector('.lc-range-slider-amount');
const rangeSliderMonth = document.querySelector('.lc-range-slider-month');
const rangeValueBarAmount = document.querySelector('#lc-range-value-bar-amount');
const rangeValueBarMonth = document.querySelector('#lc-range-value-bar-month');
const rangeValueAmount = document.querySelector('#lc-range-value-amount');
const rangeValueMonth = document.querySelector('#lc-range-value-month');
const rangeAmount = document.getElementById("lc-amount");
const rangeMonth = document.getElementById("lc-month");
let isDown = false;
function dragHandler() {
isDown = !isDown;
if (!isDown) {
rangeValueAmount.style.setProperty('opacity', '1');
rangeValueMonth.style.setProperty('opacity', '1');
} else {
rangeValueAmount.style.setProperty('opacity', '1');
rangeValueMonth.style.setProperty('opacity', '1');
}
}
function dragOn(e) {
if (!isDown) return;
rangeValueHandler();
}
function rangeValueHandler() {
amountPercentage = `${((rangeSliderAmount.value - 500) * 100) / (6000 - 500)}%`;
monthPercentage = `${((rangeSliderMonth.value - 6) * 100) / (60 - 6)}%`;
rangeValueBarAmount.style.setProperty('width', amountPercentage);
rangeValueBarMonth.style.setProperty('width', monthPercentage);
rangeValueAmount.innerHTML = `${rangeSliderAmount.value}`;
rangeValueMonth.innerHTML = `${rangeSliderMonth.value}`;
rangeAmount.innerHTML = `${rangeSliderAmount.value}`;
rangeMonth.innerHTML = `${rangeSliderMonth.value}`;
vypocetSplatka();
}
rangeValueHandler();
rangeSliderAmount.addEventListener('mousedown', dragHandler);
rangeSliderAmount.addEventListener('mousemove', dragOn);
rangeSliderAmount.addEventListener('mouseup', dragHandler);
rangeSliderAmount.addEventListener('click', rangeValueHandler);
rangeSliderMonth.addEventListener('mousedown', dragHandler);
rangeSliderMonth.addEventListener('mousemove', dragOn);
rangeSliderMonth.addEventListener('mouseup', dragHandler);
rangeSliderMonth.addEventListener('click', rangeValueHandler);
function slideValue(inputElement) {
var sliderElement = inputElement.closest('.lc-slider').find('.slider');
var val = parseInt(inputElement.val().replace(' ', '')) || 0;
var sliderMax = $(sliderElement).slider('option', 'max');
var sliderMin = $(sliderElement).slider('option', 'min');
if (val > sliderMax) {
val = sliderMax;
}
if (val < sliderMin) {
val = sliderMin;
}
$(sliderElement).slider('value', val);
val = formatNumber(val, 0, ',', ' ');
if (inputElement.val() !== val) {
inputElement.val(val);
}
}
$('.slider-value .value').change(function(){
slideValue($(this));
vypocetSplatka();
});
vypocetSplatka();
$('.insurance-box').on('change', 'input[name=poistenie]', function(){
vypocetSplatka();
});
function formatNumber(number, decimals, dec_point, thousands_sep) {
var str = number.toFixed(decimals ? decimals : 0).toString().split('.');
var parts = [];
for (var i = str[0].length; i > 0; i -= 3) {
parts.unshift(str[0].substring(Math.max(0, i - 3), i));
}
str[0] = parts.join(thousands_sep ? thousands_sep : ',');
return str.join(dec_point ? dec_point : '.');
}
function vypocetSplatka() {
var mesiace = parseInt($('[data-value="months"]').html());
var pozicka = parseInt($('[data-value="loan"]').html().replace(' ', ''));
var poplatok = (pozicka / 100) * 2;
$('.hascharge').show();
if(pozicka <= -1){
poplatok = 0;
$('.hascharge').hide();
}
var benefit = 2;
var perc, payment_mpr, payment_mpr_full, insurance, payment_month, payment_month_full, suma, suma_full, rateValue, rpmn;
$('[data-value="charge"]').text(poplatok);
$('[data-value="months-val"]').text(mesiace);
$('span[data-value="loan"]').text(price_format(pozicka));
if (pozicka <= 300) {
perc = 15.18;
} else if (pozicka <= 700) {
perc = 13.9;
} else if (pozicka <= 1499) {
perc = 11.4;
} else {
perc = 8.9;
}
if (pozicka <= 300 && mesiace<=60 && mesiace>=6) {
perc = 15.18;
} else if (pozicka <= 679 && mesiace<=60 && mesiace>=6) {
perc = 13.9;
} else if (pozicka <= 720 && mesiace<=60 && mesiace>=6) {
perc = 10.01;
} else if (pozicka <= 1499 && mesiace<=60 && mesiace>=6) {
perc = 11.4;
} else if (mesiace<=60 && mesiace>=6) {
perc = 8.9;
}
var diff = (Math.round((perc - benefit) * 100) / 100).toFixed(2);
diff = diff.replace('.', ',');
$('[data-value="interest"]').text(diff);
var pmt_ir_full = perc / 1200;
var pmt_ir = (perc - benefit) / 1200;
//pmt_ir = 13.9 / 1200;
var pmt_np = mesiace;
var pmt_pv = -pozicka;
if (pmt_np > 0 && pmt_pv < 0) {
payment_mpr = pmt(pmt_ir, pmt_np, pmt_pv);
payment_mpr_full = pmt(pmt_ir_full, pmt_np, pmt_pv);
$('.insurance-label').text('');
// poistenie
insurance = 0;
if ($('input[name=poistenie]:checked').val() === '1') {
insurance += 0.081 * pozicka / 100;
$('.insurance-label').text('vrátane poistenia');
}
if ($('input[name=poistenie]:checked').val() === '2') {
insurance += 0.148 * pozicka / 100;
$('.insurance-label').text('vrátane poistenia');
}
//payment_mpr += ' €';
payment_month = rd(payment_mpr + insurance);
payment_month_full = rd(payment_mpr_full + insurance);
payment_mpr = rd(payment_mpr);
suma = payment_month * mesiace + poplatok;
suma_full = payment_month_full * mesiace + poplatok;
$('#clientsave').html(price_format(suma_full - suma) + ' €');
} else {
payment_mpr = '';
}
$('[data-value="fee"]').html(price_format(payment_month));
$('[data-value="fee-val"]').text(price_format(payment_mpr));
rateValue = rate(pmt_np, payment_mpr, -pozicka + poplatok);
rpmn = (Math.pow(rateValue + 1, 12) - 1) * 100;
$('[data-value="rpmn-val"]').text(price_format(rpmn));
$('[data-value="sum"]').text(price_format(payment_mpr * mesiace + poplatok));
$('#vyskaF').val(pozicka);
$('#splatnostF').val(mesiace);
if ($('input[name=poistenie]:checked').val() === '0') { $('#poistenieF').val("bez poistenia"); };
if ($('input[name=poistenie]:checked').val() === '1') { $('#poistenieF').val("základné"); };
if ($('input[name=poistenie]:checked').val() === '2') { $('#poistenieF').val("rozšírené"); };
//bez benefitu repre priklad *NEW 16.11:2017 -- START
var diffWo = (Math.round((perc) * 100) / 100).toFixed(2);
diffWo = diffWo.replace('.', ',');
payment_mpr_full = rd(payment_mpr_full);
var rateValue_full, rpmn_full;
rateValue_full = rate(pmt_np, payment_mpr_full, -pozicka + poplatok);
rpmn_full = (Math.pow(rateValue_full + 1, 12) - 1) * 100;
$('[data-value="interest-wo"]').text(diffWo);
$('[data-value="fee-val-wo"]').text(price_format(payment_mpr_full));
$('[data-value="rpmn-val-wo"]').text(price_format(rpmn_full));
$('[data-value="sum-wo"]').text(price_format(payment_mpr_full * mesiace + poplatok));
// *NEW 16.11:2017 -- END
}
function rd(n) {
var r = Math.round(n * 100) / 100;
return r;
}
function price_format(number, decimals, decPoint, thousandsSep) {
decimals = decimals || 2;
number = parseFloat(number);
if (!decPoint || !thousandsSep) {
decPoint = ',';
thousandsSep = ' ';
}
var roundedNumber = Math.round(Math.abs(number) * ('1e' + decimals)) + '';
var numbersString = decimals ? roundedNumber.slice(0, decimals * -1) : roundedNumber;
var decimalsString = decimals ? roundedNumber.slice(decimals * -1) : '';
var formattedNumber = '';
while (numbersString.length > 3) {
formattedNumber += thousandsSep + numbersString.slice(-3);
numbersString = numbersString.slice(0, -3);
}
return (number < 0 ? '-' : '') + numbersString + formattedNumber + (decimalsString ? (decPoint + decimalsString) : '');
}
//function pmt(ir, np, pv, fv = 0, type = 0) { //defaul value nie je vsade podporovane!!! RBR
function pmt(ir, np, pv, fv, type) {
var fv = (typeof fv !== 'undefined') ? fv : 0;
var type = (typeof type !== 'undefined') ? type : 0;
/*
* ir - interest rate per month
* np - number of periods (months)
* pv - present value
* fv - future value
* type - when the payments are due:
* 0: end of the period, e.g. end of month (default)
* 1: beginning of period
*/
if (ir === 0) {
return -(pv + fv) / np;
}
var pvif = Math.pow(1 + ir, np);
var pmt = -ir * pv * (pvif + fv) / (pvif - 1);
if (type === 1) {
pmt /= (1 + ir);
}
return pmt;
}
function rate(paymentsPerYear, paymentAmount, presentValue, futureValue, dueEndOrBeginning, interest) {
//If interest, futureValue, dueEndorBeginning was not set, set now
if (interest == null) {
interest = 0.01;
}
if (futureValue == null) {
futureValue = 0;
}
if (dueEndOrBeginning == null) {
dueEndOrBeginning = 0;
}
var FINANCIAL_MAX_ITERATIONS = 128; //Bet accuracy with 128
var FINANCIAL_PRECISION = 0.0000001; //1.0e-8
var y, y0, y1, x0, x1 = 0,
f = 0,
i = 0;
var rate = interest;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
} else {
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = presentValue + paymentAmount * paymentsPerYear + futureValue;
y1 = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
// find root by Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION) &&
(i < FINANCIAL_MAX_ITERATIONS)) {
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
} else {
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #EFEEEE;
}
.lc-container {
margin-top: 100px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.lc-sliders {
width: 70%;
padding: 0;
background-color: #fff;
border-top: 5px solid #E9EFF4;
border-bottom: 5px solid #E9EFF4;
border-left: 5px solid #E9EFF4;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
.lc-slider {
width: 100%;
margin: 0;
padding: 10px;
background: transparent;
}
.lc-slider:first-child {
border-bottom: 1px solid #E9EFF4;
}
.lc-txtinp {
display: flex;
justify-content: space-between;
align-items: center;
}
.lc-amount {
width: 90px;
height: 90px;
position: relative;
display: block;
padding-top: 13px;
line-height: 30px;
text-align: center;
font-size: 26px;
font-weight: bold;
color: #FC6E50;
font-style: normal;
line-height: normal;
border-radius: 50%;
box-sizing: border-box;
border: 5px solid #EFEEEE;
transform-origin: center center;
background: #fff;
}
.lc-amount::after {
display: block;
content: "EUR";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-month {
width: 90px;
height: 90px;
position: relative;
display: block;
padding-top: 13px;
line-height: 30px;
text-align: center;
font-size: 26px;
font-weight: bold;
color: #FC6E50;
font-style: normal;
line-height: normal;
border-radius: 50%;
box-sizing: border-box;
border: 5px solid #EFEEEE;
transform-origin: center center;
background: #fff;
}
.lc-month::after {
display: block;
content: "Mes.";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-ranger {
width: 100%;
}
.lc-range {
margin: 20px 0;
position: relative;
}
.lc-minmax {
margin-top: 30px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.lc-txtinp span.span,
.lc-minmax span.span {
font-size: 14px;
font-weight: 400;
}
.lc-summarize {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 30%;
height: 421px;
padding: 0;
background: #fff;
border-left: 2px solid #E9EFF4;
border-top: 5px solid #E9EFF4;
border-bottom: 5px solid #E9EFF4;
border-right: 5px solid #E9EFF4;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.lc-summarize-head {
padding: 25px 0;
text-align: center;
}
.lc-summarize-head h2 {
font-size: 20px;
background: none;
color: #4d4d4d;
margin-bottom: 0;
background-repeat: no-repeat;
}
.lc-show-payment {
padding: 5px;
}
.lc-payment-show {
width: 200px;
height: 200px;
position: relative;
display: block;
margin: 0 auto;
padding-top: 60px;
line-height: 30px;
text-align: center;
font-size: 40px;
font-weight: bold;
color: #FC6E50;
font-style: normal;
line-height: normal;
border-radius: 50%;
box-sizing: border-box;
border: 5px solid #EFEEEE;
transform-origin: center center;
background: #fff;
}
.lc-payment-show::after {
display: block;
content: "EUR/MES.";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-accept-loan {
padding: 0;
text-align: center;
border-top: 2px solid #E9EFF4;
}
a.send-loan-details,
button.send-loan-details {
text-decoration: none;
outline: none;
border: none;
display: block;
text-align: center;
width: 100%;
padding: 15px 0;
background: #fff;
font-size: 20px;
color: #4d4d4d;
margin-bottom: 0;
background-repeat: no-repeat;
border-bottom-right-radius: 10px;
cursor: pointer;
}
a.send-loan-details:hover,
a.send-loan-details:focus,
button.send-loan-details:hover,
button.send-loan-details:focus {
background: #FC6E50;
color: #fff;
}
.lc-representative-example {
font-size: 12px;
width: 100%;
position: relative;
margin: 15px 0;
padding: 5px 0;
display: block;
}
.lc-representative-example span.spanbold {
color: #4d4d4d;
font-weight: bold;
}
.lc-range-slider-container {
position: relative;
}
input[type=range] {
-webkit-appearance: none;
margin: 10px 0;
width: 100%;
position: absolute;
top: 0;
margin: 0;
}
#lc-range-value-bar-amount {
width: 100%;
content: "0";
background-color: #FC6E50;
position: absolute;
z-index: 10000;
height: 25px;
top: 0;
margin: 0;
border-radius: 5px;
}
#lc-range-value-bar-month {
width: 100%;
content: "0";
background-color: #FC6E50;
position: absolute;
z-index: 10000;
height: 25px;
top: 0;
margin: 0;
border-radius: 5px;
}
/*
#range-value {
content:"0";
background: rgba(233, 239, 244, 0.1);;
position: absolute;
z-index: 10000;
height: 25px;
top: -65px;
margin: 0;
border-radius: 5px;
left: 50%;
transform0: translateX(-50%);
font-size: 20px;
padding: 12px;
color: #41576B;
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.08);
text-align: center;
opacity: 0;
}*/
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 25px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: #E9EFF4;
border-radius: 5px;
border: 0px solid #000101;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.08);
border: 14px solid #FFF;
height: 53px;
width: 53px;
border-radius: 30px;
background: #FC6E50;
cursor: pointer;
-webkit-appearance: none;
margin-top: -13.5px;
position: relative;
z-index: 1000000000;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 12.8px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: #000;
border-radius: 25px;
border: 0px solid #000101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 20px;
width: 39px;
border-radius: 7px;
background: #000000;
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 12.8px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 39px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #000;
border: 0px solid #000101;
border-radius: 50px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: #000;
border: 0px solid #000101;
border-radius: 50px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 20px;
width: 39px;
border-radius: 7px;
background: #000;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="row">
<div class="col-12">
<div class="lc-container">
<div class="lc-sliders">
<div class="lc-slider">
<div class="lc-txtinp">
<span class="span">Zvoľte si výšku pôžičky</span>
<span id="lc-amount" class="lc-amount">2000</span>
</div>
<div class="lc-range">
<div class="lc-range-slider-container slider-value">
<input id="lc-range-amount" type="range" class="slider lc-range-slider-amount" min="500" max="6000" step="100" value="500">
<span id="lc-range-value-bar-amount"></span>
<span id="lc-range-value-amount" data-value="loan" class="value">0</span>
</div>
</div>
<div class="lc-minmax">
<span class="span">500€</span>
<span class="span">6000€</span>
</div>
</div>
<div class="lc-slider">
<div class="lc-txtinp">
<span class="span">Zvoľte si dobu splatnosti</span>
<span id="lc-month" class="lc-month">6</span>
</div>
<div class="lc-range">
<div class="lc-range-slider-container slider-value">
<input id="lc-range-month" type="range" class="slider lc-range-slider-month" min="6" max="60" step="1" value="6">
<span id="lc-range-value-bar-month"></span>
<span id="lc-range-value-month" data-value="months" class="value ">0</span>
</div>
</div>
<div class="lc-minmax">
<span class="span">6 mesiacov</span>
<span class="span">60 mesiacov</span>
</div>
</div>
</div>
<div class="lc-summarize">
<div class="lc-summarize-head">
<h2>Vaša mesačná splátka</h2>
</div>
<div class="lc-show-payment">
<span id="lc-payment-show" class="lc-payment-show value payment" data-value="fee">
0,00
</span>
</div>
<div class="lc-accept-loan">
<button type="submit" class="send-loan-details">
Chcem pôžičku
</button>
</div>
</div>
</div>
<div class="lc-representative-example">
<span class="spanbold">Reprezentatívny príklad:</span> Mesačná anuitná splátka Pôžičky s odmenou vo výške <span data-value="loan">2 000,00</span> € s úrokovou sadzbou
<span data-value="interest">13,18</span> % p.a. a splatnosťou <span data-value="months-val">60</span> mesiacov predstavuje
<span data-value="fee-val">45,69</span> €. Ročná percentuálna miera nákladov dosahuje
<span data-value="rpmn-val">15,03</span> %, počet splátok <span data-value="months-val">60</span>.
Výška poplatku za poskytnutie pôžičky je <span class="hascharge">2 % z výšky úveru, v tomto prípade</span> <span data-value="charge">40</span> €.
Celková čiastka, ktorú musí klient zaplatiť, predstavuje <span data-value="sum">2 781,40</span> eur. Na schválenie a poskytnutie pôžičky nie je právny nárok. Výška splátky je uvedená bez Poistenia schopnosti splácať úver.
</div>
</div>
</div>
</div>
You need to attach handlers for touch events to make the range sliders work in mobile. If you add the below lines to your code, it will start working in mobile.
rangeSliderAmount.addEventListener('touchstart', dragHandler);
rangeSliderAmount.addEventListener('touchmove', dragOn);
rangeSliderAmount.addEventListener('touchend', dragHandler);
rangeSliderAmount.addEventListener('touchstart', rangeValueHandler);
rangeSliderMonth.addEventListener('touchstart', dragHandler);
rangeSliderMonth.addEventListener('touchmove', dragOn);
rangeSliderMonth.addEventListener('touchend', dragHandler);
rangeSliderMonth.addEventListener('touchstart', rangeValueHandler);
Refer this document to learn about touch events in javascript:
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
Working sample based on your code:
https://plnkr.co/edit/TDLHWvaYFr1V8GQqZ9Zb
I'm converting a player in html into a Vue component.
Half of the component is already created, only the time control slider is missing.
Here is the html player code (Lines with multiple tabs are already implemented in the Vue component):
var audioPlayer = document.querySelector('.green-audio-player');
var playPause = audioPlayer.querySelector('#playPause');
var playpauseBtn = audioPlayer.querySelector('.play-pause-btn');
var loading = audioPlayer.querySelector('.loading');
var progress = audioPlayer.querySelector('.progress');
var sliders = audioPlayer.querySelectorAll('.slider');
var player = audioPlayer.querySelector('audio');
var currentTime = audioPlayer.querySelector('.current-time');
var totalTime = audioPlayer.querySelector('.total-time');
var speaker = audioPlayer.querySelector('#speaker');
var draggableClasses = ['pin'];
var currentlyDragged = null;
window.addEventListener('mousedown', function(event) {
if(!isDraggable(event.target)) return false;
currentlyDragged = event.target;
let handleMethod = currentlyDragged.dataset.method;
this.addEventListener('mousemove', window[handleMethod], false);
window.addEventListener('mouseup', () => {
currentlyDragged = false;
window.removeEventListener('mousemove', window[handleMethod], false);
}, false);
});
playpauseBtn.addEventListener('click', togglePlay);
player.addEventListener('timeupdate', updateProgress);
player.addEventListener('loadedmetadata', () => {
totalTime.textContent = formatTime(player.duration);
});
player.addEventListener('canplay', makePlay);
player.addEventListener('ended', function(){
playPause.attributes.d.value = "M18 12L0 24V0";
player.currentTime = 0;
});
sliders.forEach(slider => {
let pin = slider.querySelector('.pin');
slider.addEventListener('click', window[pin.dataset.method]);
});
function isDraggable(el) {
let canDrag = false;
let classes = Array.from(el.classList);
draggableClasses.forEach(draggable => {
if(classes.indexOf(draggable) !== -1)
canDrag = true;
})
return canDrag;
}
function inRange(event) {
let rangeBox = getRangeBox(event);
let rect = rangeBox.getBoundingClientRect();
let direction = rangeBox.dataset.direction;
if(direction == 'horizontal') {
var min = rangeBox.offsetLeft;
var max = min + rangeBox.offsetWidth;
if(event.clientX < min || event.clientX > max) return false;
} else {
var min = rect.top;
var max = min + rangeBox.offsetHeight;
if(event.clientY < min || event.clientY > max) return false;
}
return true;
}
function updateProgress() {
var current = player.currentTime;
var percent = (current / player.duration) * 100;
progress.style.width = percent + '%';
currentTime.textContent = formatTime(current);
}
function getRangeBox(event) {
let rangeBox = event.target;
let el = currentlyDragged;
if(event.type == 'click' && isDraggable(event.target)) {
rangeBox = event.target.parentElement.parentElement;
}
if(event.type == 'mousemove') {
rangeBox = el.parentElement.parentElement;
}
return rangeBox;
}
function getCoefficient(event) {
let slider = getRangeBox(event);
let rect = slider.getBoundingClientRect();
let K = 0;
if(slider.dataset.direction == 'horizontal') {
let offsetX = event.clientX - slider.offsetLeft;
let width = slider.clientWidth;
K = offsetX / width;
} else if(slider.dataset.direction == 'vertical') {
let height = slider.clientHeight;
var offsetY = event.clientY - rect.top;
K = 1 - offsetY / height;
}
return K;
}
function rewind(event) {
if(inRange(event)) {
player.currentTime = player.duration * getCoefficient(event);
}
}
function formatTime(time) {
var min = Math.floor(time / 60);
var sec = Math.floor(time % 60);
return min + ':' + ((sec<10) ? ('0' + sec) : sec);
}
function togglePlay() {
if(player.paused) {
playPause.attributes.d.value = "M0 0h6v24H0zM12 0h6v24h-6z";
player.play();
} else {
playPause.attributes.d.value = "M18 12L0 24V0";
player.pause();
}
}
function makePlay() {
playpauseBtn.style.display = 'block';
loading.style.display = 'none';
}
.audio.green-audio-player {
width: 400px;
min-width: 300px;
height: 56px;
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.07);
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 24px;
padding-right: 24px;
border-radius: 4px;
user-select: none;
-webkit-user-select: none;
background-color: #fff;
}
.audio.green-audio-player .play-pause-btn {
display: none;
cursor: pointer;
}
.audio.green-audio-player .spinner {
width: 18px;
height: 18px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/loading.png);
background-size: cover;
background-repeat: no-repeat;
animation: spin 0.4s linear infinite;
}
.audio.green-audio-player .slider {
flex-grow: 1;
background-color: #D8D8D8;
cursor: pointer;
position: relative;
}
.audio.green-audio-player .slider .progress {
background-color: #44BFA3;
border-radius: inherit;
position: absolute;
pointer-events: none;
}
.audio.green-audio-player .slider .progress .pin {
height: 16px;
width: 16px;
border-radius: 8px;
background-color: #44BFA3;
position: absolute;
pointer-events: all;
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.32);
}
.audio.green-audio-player .controls {
font-family: 'Roboto', sans-serif;
font-size: 16px;
line-height: 18px;
color: #55606E;
display: flex;
flex-grow: 1;
justify-content: space-between;
align-items: center;
margin-left: 24px;
}
.audio.green-audio-player .controls .slider {
margin-left: 16px;
margin-right: 16px;
border-radius: 2px;
height: 4px;
}
.audio.green-audio-player .controls .slider .progress {
width: 0;
height: 100%;
}
.audio.green-audio-player .controls .slider .progress .pin {
right: -8px;
top: -6px;
}
.audio.green-audio-player .controls span {
cursor: default;
}
svg, img {
display: block;
}
#keyframes spin {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(1turn);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="audio green-audio-player">
<div class="loading">
<div class="spinner"></div>
</div>
<div class="play-pause-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="24" viewBox="0 0 18 24">
<path fill="#566574" fill-rule="evenodd" d="M18 12L0 24V0" class="play-pause-icon" id="playPause"/>
</svg>
</div>
<div class="controls">
<span class="current-time">0:00</span>
<div class="slider" data-direction="horizontal">
<div class="progress">
<div class="pin" id="progress-pin" data-method="rewind"></div>
</div>
</div>
<span class="total-time">0:00</span>
</div>
<audio>
<source src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/Swing_Jazz_Drum.mp3" type="audio/mpeg">
</audio>
</div>
Html Codepen: https://codepen.io/caiokawasaki/pen/JwVwry
Here is the Vue component:
Vue.component('audio-player', {
props: ['message'],
data: () => ({
audio: undefined,
loaded: false,
playing: false,
currentTime: '00:00',
totalTime: '00:00',
percent: '0%',
draggableClasses: ['pin'],
currentlyDragged: null
}),
computed: {},
methods: {
formatTime(time) {
var min = Math.floor(time / 60);
var sec = Math.floor(time % 60);
return min + ':' + ((sec < 10) ? ('0' + sec) : sec);
},
loadedMetaData() {
this.totalTime = this.formatTime(this.audio.duration)
},
canPlay() {
this.loaded = true
},
timeUpdate(){
var current = this.audio.currentTime;
var percent = (current / this.audio.duration) * 100;
this.percent = percent + '%';
this.currentTime = this.formatTime(current);
},
ended(){
this.playing = false
this.audio.currentTime = 0
},
isDraggable(el) {
let canDrag = false;
let classes = Array.from(el.classList);
this.draggableClasses.forEach(draggable => {
if (classes.indexOf(draggable) !== -1)
canDrag = true;
})
return canDrag;
},
inRange(event) {
let rangeBox = getRangeBox(event);
let rect = rangeBox.getBoundingClientRect();
let direction = rangeBox.dataset.direction;
if (direction == 'horizontal') {
var min = rangeBox.offsetLeft;
var max = min + rangeBox.offsetWidth;
if (event.clientX < min || event.clientX > max) return false;
} else {
var min = rect.top;
var max = min + rangeBox.offsetHeight;
if (event.clientY < min || event.clientY > max) return false;
}
return true;
},
togglePlay() {
if (this.audio.paused) {
this.audio.play();
this.playing = true;
} else {
this.audio.pause();
this.playing = false;
}
},
makePlay() {
playpauseBtn.style.display = 'block';
loading.style.display = 'none';
},
getRangeBox(event) {
let rangeBox = event.target;
let el = currentlyDragged;
if (event.type == 'click' && isDraggable(event.target)) {
rangeBox = event.target.parentElement.parentElement;
}
if (event.type == 'mousemove') {
rangeBox = el.parentElement.parentElement;
}
return rangeBox;
},
getCoefficient(event) {
let slider = getRangeBox(event);
let rect = slider.getBoundingClientRect();
let K = 0;
if (slider.dataset.direction == 'horizontal') {
let offsetX = event.clientX - slider.offsetLeft;
let width = slider.clientWidth;
K = offsetX / width;
} else if (slider.dataset.direction == 'vertical') {
let height = slider.clientHeight;
var offsetY = event.clientY - rect.top;
K = 1 - offsetY / height;
}
return K;
},
rewind(event) {
if (this.inRange(event)) {
this.audio.currentTime = this.audio.duration * getCoefficient(event);
}
}
},
mounted() {
this.audio = this.$refs.audio
},
template: `<div class="audio-message-content">
<a v-if="loaded" class="play-pause-btn" href="#" :title="playing ? 'Clique aqui para pausar o audio' : 'Clique aqui ouvir o audio'" #click.prevent="togglePlay">
<svg key="pause" v-if="playing" x="0px" y="0px" viewBox="0 0 18 20" style="width: 18px; height: 20px; margin-top: -10px">
<path d="M17.1,20c0.49,0,0.9-0.43,0.9-0.96V0.96C18,0.43,17.6,0,17.1,0h-5.39c-0.49,0-0.9,0.43-0.9,0.96v18.07c0,0.53,0.4,0.96,0.9,0.96H17.1z M17.1,20"/>
<path d="M6.29,20c0.49,0,0.9-0.43,0.9-0.96V0.96C7.19,0.43,6.78,0,6.29,0H0.9C0.4,0,0,0.43,0,0.96v18.07C0,19.57,0.4,20,0.9,20H6.29z M6.29,20"/>
</svg>
<svg key="play" v-else x="0px" y="0px" viewBox="0 0 18 22" style="width: 18px; height: 22px; margin-top: -11px">
<path d="M17.45,10.01L1.61,0.14c-0.65-0.4-1.46,0.11-1.46,0.91V20.8c0,0.81,0.81,1.32,1.46,0.91l15.84-9.87C18.1,11.43,18.1,10.41,17.45,10.01L17.45,10.01z M17.45,10.01"/>
</svg>
</a>
<div v-else class="loading">
<div class="spinner"></div>
</div>
<div class="controls">
<span class="current-time">{{ currentTime }}</span>
<div class="slider" data-direction="horizontal" #click="">
<div class="progress" :style="{width: percent}">
<div class="pin" id="progress-pin" data-method="rewind"></div>
</div>
</div>
<span class="total-time">{{ totalTime }}</span>
</div>
<audio ref="audio" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/Swing_Jazz_Drum.mp3" #loadedmetadata="loadedMetaData" #canplay="canPlay" #timeupdate="timeUpdate" #ended="ended"></audio>
</div>`
})
var app = new Vue({
el: '#app'
})
.audio-message-content {
width: 400px;
min-width: 300px;
height: 56px;
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.07);
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 24px;
padding-right: 24px;
border-radius: 4px;
user-select: none;
-webkit-user-select: none;
background-color: #fff;
}
.audio-message-content .play-pause-btn {
position: relative;
width: 18px;
height: 22px;
cursor: pointer;
}
.audio-message-content .play-pause-btn svg {
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-left: -9px;
}
.audio-message-content .spinner {
width: 18px;
height: 18px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/loading.png);
background-size: cover;
background-repeat: no-repeat;
animation: spin 0.4s linear infinite;
}
.audio-message-content .slider {
flex-grow: 1;
background-color: #D8D8D8;
cursor: pointer;
position: relative;
}
.audio-message-content .slider .progress {
background-color: #44BFA3;
border-radius: inherit;
position: absolute;
pointer-events: none;
}
.audio-message-content .slider .progress .pin {
height: 16px;
width: 16px;
border-radius: 8px;
background-color: #44BFA3;
position: absolute;
pointer-events: all;
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.32);
}
.audio-message-content .controls {
font-family: 'Roboto', sans-serif;
font-size: 16px;
line-height: 18px;
color: #55606E;
display: flex;
flex-grow: 1;
justify-content: space-between;
align-items: center;
margin-left: 24px;
}
.audio-message-content .controls .slider {
margin-left: 16px;
margin-right: 16px;
border-radius: 2px;
height: 4px;
}
.audio-message-content .controls .slider .progress {
width: 0;
height: 100%;
}
.audio-message-content .controls .slider .progress .pin {
right: -8px;
top: -6px;
}
.audio-message-content .controls span {
cursor: default;
}
svg, img {
display: block;
}
#keyframes spin {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(1turn);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<audio-player></audio-player>
</div>
Vue Component Codepen: https://codepen.io/caiokawasaki/pen/QzRMwz
Functions like the following I could not understand nor find anything on the internet:
window[handleMethod]
window[pin.dataset.method]
Can anyone help me finalize this component?
Edit
I've converted all of the html and javascript into a Vue component but anyway it still is not working properly.
The only thing that is not working properly is the progress bar. It needs to perform two functions:
Clicking it should go to the desired time.
When clicking on the pin and drag it should go to the desired time.
I use Vue Cli, neither of the above two work in the form of .vue files, but in Codepen normally written only function 2 works.
Codepen: https://codepen.io/caiokawasaki/pen/VqOqBQ
The function: window[handleMethod] is executed by deriving the name of the method off of the data- property from the pin element:
<div class="pin" id="progress-pin" data-method="rewind"></div>
So window[handleMethod] is equivalent to window.rewind()
The same is true for window[pin.dataset.method].
So in your case:
this[handleMethod](event)
and:
this[pin.dataset.method](event)
Should be suitable replacements.
I am using ResponsiveSlides for a photo slideshow on a page, and I cannot make the navigation button show up as they do on the website. Currently, the Previous and Next links appear below the slider as simple hypertext links. Here is how this is showing on the website:
website-slideshow. See the Previous/Next buttons below image. Here is how I would like for this to look: navigation-buttons-centered. I've tried so many different things and nothing is working, so any help would be appreciated.
Here is the code that is being used:
HTML:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script src="/wp/wp-content/themes/Avada-Child-Theme/responsiveslides.js"></script>
<script>
$(function() {
$(".rslides").responsiveSlides({
auto: true,
pager: false,
nav: true,
speed: 500,
namespace: "rslides",
});
});
</script>
<link href="/wp/wp-content/themes/Avada-Child-Theme/css/responsiveslides.css" rel="stylesheet" type="text/css" />
<div class="rslides_container">
<ul class="rslides rslides1 centered-btns centered-btns1">
<li><img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''></li>
<li><img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''></li>
<li><img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''></li>
<li><img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''></li>
</ul>
</div>
JS:
(function($, window, i) {
$.fn.responsiveSlides = function(options) {
// Default settings
var settings = $.extend({
"auto": true, // Boolean: Animate automatically, true or false
"speed": 500, // Integer: Speed of the transition, in milliseconds
"timeout": 4000, // Integer: Time between slide transitions, in milliseconds
"pager": true, // Boolean: Show pager, true or false
"nav": true, // Boolean: Show navigation, true or false
"random": false, // Boolean: Randomize the order of the slides, true or false
"pause": false, // Boolean: Pause on hover, true or false
"pauseControls": true, // Boolean: Pause when hovering controls, true or false
"prevText": "Previous", // String: Text for the "previous" button
"nextText": "Next", // String: Text for the "next" button
"maxwidth": "", // Integer: Max-width of the slideshow, in pixels
"navContainer": "", // Selector: Where auto generated controls should be appended to, default is after the <ul>
"manualControls": "", // Selector: Declare custom pager navigation
"namespace": "rslides", // String: change the default namespace used
"before": $.noop, // Function: Before callback
"after": $.noop // Function: After callback
}, options);
return this.each(function() {
// Index for namespacing
i++;
var $this = $(this),
// Local variables
vendor,
selectTab,
startCycle,
restartCycle,
rotate,
$tabs,
// Helpers
index = 0,
$slide = $this.children(),
length = $slide.length,
fadeTime = parseFloat(settings.speed),
waitTime = parseFloat(settings.timeout),
maxw = parseFloat(settings.maxwidth),
// Namespacing
namespace = settings.namespace,
namespaceIdx = namespace + i,
// Classes
navClass = namespace + "_nav " + namespaceIdx + "_nav",
activeClass = namespace + "_here",
visibleClass = namespaceIdx + "_on",
slideClassPrefix = namespaceIdx + "_s",
// Pager
$pager = $("<ul class='" + namespace + "_tabs " + namespaceIdx + "_tabs' />"),
// Styles for visible and hidden slides
visible = {
"float": "left",
"position": "relative",
"opacity": 1,
"zIndex": 2
},
hidden = {
"float": "none",
"position": "absolute",
"opacity": 0,
"zIndex": 1
},
// Detect transition support
supportsTransitions = (function() {
var docBody = document.body || document.documentElement;
var styles = docBody.style;
var prop = "transition";
if (typeof styles[prop] === "string") {
return true;
}
// Tests for vendor specific prop
vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
prop = prop.charAt(0).toUpperCase() + prop.substr(1);
var i;
for (i = 0; i < vendor.length; i++) {
if (typeof styles[vendor[i] + prop] === "string") {
return true;
}
}
return false;
})(),
// Fading animation
slideTo = function(idx) {
settings.before(idx);
// If CSS3 transitions are supported
if (supportsTransitions) {
$slide
.removeClass(visibleClass)
.css(hidden)
.eq(idx)
.addClass(visibleClass)
.css(visible);
index = idx;
setTimeout(function() {
settings.after(idx);
}, fadeTime);
// If not, use jQuery fallback
} else {
$slide
.stop()
.fadeOut(fadeTime, function() {
$(this)
.removeClass(visibleClass)
.css(hidden)
.css("opacity", 1);
})
.eq(idx)
.fadeIn(fadeTime, function() {
$(this)
.addClass(visibleClass)
.css(visible);
settings.after(idx);
index = idx;
});
}
};
// Random order
if (settings.random) {
$slide.sort(function() {
return (Math.round(Math.random()) - 0.5);
});
$this
.empty()
.append($slide);
}
// Add ID's to each slide
$slide.each(function(i) {
this.id = slideClassPrefix + i;
});
// Add max-width and classes
$this.addClass(namespace + " " + namespaceIdx);
if (options && options.maxwidth) {
$this.css("max-width", maxw);
}
// Hide all slides, then show first one
$slide
.hide()
.css(hidden)
.eq(0)
.addClass(visibleClass)
.css(visible)
.show();
// CSS transitions
if (supportsTransitions) {
$slide
.show()
.css({
// -ms prefix isn't needed as IE10 uses prefix free version
"-webkit-transition": "opacity " + fadeTime + "ms ease-in-out",
"-moz-transition": "opacity " + fadeTime + "ms ease-in-out",
"-o-transition": "opacity " + fadeTime + "ms ease-in-out",
"transition": "opacity " + fadeTime + "ms ease-in-out"
});
}
// Only run if there's more than one slide
if ($slide.length > 1) {
// Make sure the timeout is at least 100ms longer than the fade
if (waitTime < fadeTime + 100) {
return;
}
// Pager
if (settings.pager && !settings.manualControls) {
var tabMarkup = [];
$slide.each(function(i) {
var n = i + 1;
tabMarkup +=
"<li>" +
"<a href='#' class='" + slideClassPrefix + n + "'>" + n + "</a>" +
"</li>";
});
$pager.append(tabMarkup);
// Inject pager
if (options.navContainer) {
$(settings.navContainer).append($pager);
} else {
$this.after($pager);
}
}
// Manual pager controls
if (settings.manualControls) {
$pager = $(settings.manualControls);
$pager.addClass(namespace + "_tabs " + namespaceIdx + "_tabs");
}
// Add pager slide class prefixes
if (settings.pager || settings.manualControls) {
$pager.find('li').each(function(i) {
$(this).addClass(slideClassPrefix + (i + 1));
});
}
// If we have a pager, we need to set up the selectTab function
if (settings.pager || settings.manualControls) {
$tabs = $pager.find('a');
// Select pager item
selectTab = function(idx) {
$tabs
.closest("li")
.removeClass(activeClass)
.eq(idx)
.addClass(activeClass);
};
}
// Auto cycle
if (settings.auto) {
startCycle = function() {
rotate = setInterval(function() {
// Clear the event queue
$slide.stop(true, true);
var idx = index + 1 < length ? index + 1 : 0;
// Remove active state and set new if pager is set
if (settings.pager || settings.manualControls) {
selectTab(idx);
}
slideTo(idx);
}, waitTime);
};
// Init cycle
startCycle();
}
// Restarting cycle
restartCycle = function() {
if (settings.auto) {
// Stop
clearInterval(rotate);
// Restart
startCycle();
}
};
// Pause on hover
if (settings.pause) {
$this.hover(function() {
clearInterval(rotate);
}, function() {
restartCycle();
});
}
// Pager click event handler
if (settings.pager || settings.manualControls) {
$tabs.bind("click", function(e) {
e.preventDefault();
if (!settings.pauseControls) {
restartCycle();
}
// Get index of clicked tab
var idx = $tabs.index(this);
// Break if element is already active or currently animated
if (index === idx || $("." + visibleClass).queue('fx').length) {
return;
}
// Remove active state from old tab and set new one
selectTab(idx);
// Do the animation
slideTo(idx);
})
.eq(0)
.closest("li")
.addClass(activeClass);
// Pause when hovering pager
if (settings.pauseControls) {
$tabs.hover(function() {
clearInterval(rotate);
}, function() {
restartCycle();
});
}
}
// Navigation
if (settings.nav) {
var navMarkup =
"<a href='#' class='" + navClass + " prev'>" + settings.prevText + "</a>" +
"<a href='#' class='" + navClass + " next'>" + settings.nextText + "</a>";
// Inject navigation
if (options.navContainer) {
$(settings.navContainer).append(navMarkup);
} else {
$this.after(navMarkup);
}
var $trigger = $("." + namespaceIdx + "_nav"),
$prev = $trigger.filter(".prev");
// Click event handler
$trigger.bind("click", function(e) {
e.preventDefault();
var $visibleClass = $("." + visibleClass);
// Prevent clicking if currently animated
if ($visibleClass.queue('fx').length) {
return;
}
// Adds active class during slide animation
// $(this)
// .addClass(namespace + "_active")
// .delay(fadeTime)
// .queue(function (next) {
// $(this).removeClass(namespace + "_active");
// next();
// });
// Determine where to slide
var idx = $slide.index($visibleClass),
prevIdx = idx - 1,
nextIdx = idx + 1 < length ? index + 1 : 0;
// Go to slide
slideTo($(this)[0] === $prev[0] ? prevIdx : nextIdx);
if (settings.pager || settings.manualControls) {
selectTab($(this)[0] === $prev[0] ? prevIdx : nextIdx);
}
if (!settings.pauseControls) {
restartCycle();
}
});
// Pause when hovering navigation
if (settings.pauseControls) {
$trigger.hover(function() {
clearInterval(rotate);
}, function() {
restartCycle();
});
}
}
}
// Max-width fallback
if (typeof document.body.style.maxWidth === "undefined" && options.maxwidth) {
var widthSupport = function() {
$this.css("width", "100%");
if ($this.width() > maxw) {
$this.css("width", maxw);
}
};
// Init fallback
widthSupport();
$(window).bind("resize", function() {
widthSupport();
});
}
});
};
})(jQuery, this, 0);
CSS:
.rslides {
position: relative;
list-style: none;
overflow: hidden;
width: 100%;
padding: 0;
margin: 0;
}
.rslides li {
-webkit-backface-visibility: hidden;
position: absolute;
display: none;
width: 100%;
left: 0;
top: 0;
}
.rslides li:first-child {
position: relative;
display: block;
float: left;
}
.rslides img {
display: block;
height: auto;
float: left;
width: 100%;
border: 0;
}
.rslides1_nav {
position: absolute;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
top: 50%;
left: 0;
z-index: 99;
opacity: 0.7;
text-indent: -9999px;
overflow: hidden;
text-decoration: none;
height: 61px;
width: 38px;
background: transparent url("themes.gif") no-repeat left top;
margin-top: -45px;
}
.rslides1_nav:active {
opacity: 1.0;
}
.rslides1_nav.next {
left: auto;
background-position: right top;
right: 0;
}
.rslides1_nav:focus {
outline: none;
}
.centered-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
top: 50%;
left: 0;
opacity: 0.7;
text-indent: -9999px;
overflow: hidden;
text-decoration: none;
height: 61px;
width: 38px;
background: transparent url("themes.gif") no-repeat left top;
margin-top: -45px;
}
.centered-btns_nav:active {
opacity: 1.0;
}
.centered-btns_nav.next {
left: auto;
background-position: right top;
right: 0;
}
a {
color: #fff;
}
.rslides {
margin: 0 auto;
}
.rslides_container {
margin-bottom: 50px;
position: relative;
float: left;
width: 100%;
}
.centered-btns_nav {
z-index: 10;
position: absolute;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
top: 50%;
left: 0;
opacity: 0.7;
text-indent: -9999px;
overflow: hidden;
text-decoration: none;
height: 61px;
width: 38px;
background: transparent url("themes.gif") no-repeat left top;
margin-top: -45px;
}
.centered-btns_nav:active {
opacity: 1.0;
}
.centered-btns_nav.next {
left: auto;
background-position: right top;
right: 0;
}
.transparent-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
top: 0;
left: 0;
display: block;
background: #fff;
/* Fix for IE6-9 */
opacity: 0;
filter: alpha(opacity=1);
width: 48%;
text-indent: -9999px;
overflow: hidden;
height: 91%;
}
.transparent-btns_nav.next {
left: auto;
right: 0;
}
.large-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
opacity: 0.6;
text-indent: -9999px;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
background: #000 url("themes.gif") no-repeat left 50%;
width: 38px;
}
.large-btns_nav:active {
opacity: 1.0;
}
.large-btns_nav.next {
left: auto;
background-position: right 50%;
right: 0;
}
.centered-btns_nav:focus,
.transparent-btns_nav:focus,
.large-btns_nav:focus {
outline: none;
}
.centered-btns_tabs,
.transparent-btns_tabs,
.large-btns_tabs {
margin-top: 10px;
text-align: center;
}
.centered-btns_tabs li,
.transparent-btns_tabs li,
.large-btns_tabs li {
display: inline;
float: none;
_float: left;
*float: left;
margin-right: 5px;
}
.centered-btns_tabs a,
.transparent-btns_tabs a,
.large-btns_tabs a {
text-indent: -9999px;
overflow: hidden;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
background: #ccc;
background: rgba(0, 0, 0, .2);
display: inline-block;
_display: block;
*display: block;
-webkit-box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3);
-moz-box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3);
box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, .3);
width: 9px;
height: 9px;
}
.centered-btns_here a,
.transparent-btns_here a,
.large-btns_here a {
background: #222;
background: rgba(0, 0, 0, .8);
}
I believe your problem is in this line under .rslides1_nav:
background: transparent url("themes.gif") no-repeat left top;
Try:
background: transparent url("http://responsiveslides.com/with-captions/themes.gif") no-repeat left top;
Or copy that image to your local and use whatever link would be appropriate. I've been messing around with a fiddle, but it doesn't look quire right yet. Hopefully, this can at least get you started
You need to add the responsiveslides.css and theme.css. After that you can download the image with the arrows from here. Or you can just change the background images path of .centered-btns_nav with the path from this link.
You can get the responsiveslides.css file from here.
You can get the theme.css file from here.
You also have to change the namespace property value from the plugin initialization to be:
namespace: "centered-btns"
See the working snippet below:
$(function() {
$(".rslides").responsiveSlides({
auto: true,
pager: false,
nav: true,
speed: 500,
namespace: "centered-btns"
});
});
http://responsiveslides.com/themes/themes.gif
/*! http://responsiveslides.com v1.54 by #viljamis */
.rslides {
position: relative;
list-style: none;
overflow: hidden;
width: 100%;
padding: 0;
margin: 0;
}
.rslides li {
-webkit-backface-visibility: hidden;
position: absolute;
display: none;
width: 100%;
left: 0;
top: 0;
}
.rslides li:first-child {
position: relative;
display: block;
float: left;
}
.rslides img {
display: block;
height: auto;
float: left;
width: 100%;
border: 0;
}
* {
margin: 0;
padding: 0;
}
html {
background: #fff;
}
body {
color: #333;
font: 14px/24px sans-serif;
margin: 0 auto;
max-width: 700px;
_width: 700px;
padding: 0 30px;
text-align: center;
-webkit-font-smoothing: antialiased;
}
#wrapper {
float: left;
width: 100%;
margin-bottom: 50px;
}
h1 {
font: 600 28px/36px sans-serif;
margin: 50px 0;
}
h3 {
font: 600 18px/24px sans-serif;
color: #999;
margin: 0 0 20px;
}
a {
color: #222;
}
.rslides {
margin: 0 auto;
}
.rslides_container {
margin-bottom: 50px;
position: relative;
float: left;
width: 100%;
}
.centered-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0,0,0,0);
top: 50%;
left: 0;
opacity: 0.7;
text-indent: -9999px;
overflow: hidden;
text-decoration: none;
height: 61px;
width: 38px;
background: transparent url("http://responsiveslides.com/themes/themes.gif") no-repeat left top;
margin-top: -45px;
}
.centered-btns_nav:active {
opacity: 1.0;
}
.centered-btns_nav.next {
left: auto;
background-position: right top;
right: 0;
}
.transparent-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0,0,0,0);
top: 0;
left: 0;
display: block;
background: #fff; /* Fix for IE6-9 */
opacity: 0;
filter: alpha(opacity=1);
width: 48%;
text-indent: -9999px;
overflow: hidden;
height: 91%;
}
.transparent-btns_nav.next {
left: auto;
right: 0;
}
.large-btns_nav {
z-index: 3;
position: absolute;
-webkit-tap-highlight-color: rgba(0,0,0,0);
opacity: 0.6;
text-indent: -9999px;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
background: #000 url("http://responsiveslides.com/themes/themes.gif") no-repeat left 50%;
width: 38px;
}
.large-btns_nav:active {
opacity: 1.0;
}
.large-btns_nav.next {
left: auto;
background-position: right 50%;
right: 0;
}
.centered-btns_nav:focus,
.transparent-btns_nav:focus,
.large-btns_nav:focus {
outline: none;
}
.centered-btns_tabs,
.transparent-btns_tabs,
.large-btns_tabs {
margin-top: 10px;
text-align: center;
}
.centered-btns_tabs li,
.transparent-btns_tabs li,
.large-btns_tabs li {
display: inline;
float: none;
_float: left;
*float: left;
margin-right: 5px;
}
.centered-btns_tabs a,
.transparent-btns_tabs a,
.large-btns_tabs a {
text-indent: -9999px;
overflow: hidden;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
background: #ccc;
background: rgba(0,0,0, .2);
display: inline-block;
_display: block;
*display: block;
-webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,.3);
-moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,.3);
box-shadow: inset 0 0 2px 0 rgba(0,0,0,.3);
width: 9px;
height: 9px;
}
.centered-btns_here a,
.transparent-btns_here a,
.large-btns_here a {
background: #222;
background: rgba(0,0,0, .8);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/ResponsiveSlides.js/1.53/responsiveslides.min.css" rel="stylesheet" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ResponsiveSlides.js/1.53/responsiveslides.min.js"></script>
<div class="rslides_container">
<ul class="rslides rslides1 centered-btns centered-btns1">
<li>
<img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''>
</li>
<li>
<img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''>
</li>
<li>
<img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''>
</li>
<li>
<img src="http://cdnparap110.paragonrels.com/ParagonImages/Property/P11/VALLEYMLS/480490/0/0/0/f479a2d775fa69c1118b25a3c2c8ecab/2/52ab9841b1e470e3517c5cdc93691ff5/480490.JPG" alt=''>
</li>
</ul>
</div>
I'm trying to embed videos in my website with custom video players and when I embed more than one video when I press the play button on any of the videos it plays all of the videos at once instead of just the one I click play on. The code items are down below:
goto the jsfiddle below and run the code then press play on a video and you'll see it plays both videos at once instead of the one you click.
HTML
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.scss">
</head>
<body>
<!--Video 1-->
<section id="wrapper">
<div class="videoContainer">
<video id="myVideo" controls preload="auto" poster="http://s.cdpn.io/6035/vp_poster.jpg" width="380" >
<source src="http://html-testing.github.io/2/videos/mikethefrog.mp4" type="video/mp4" />
<p>Your browser does not support the video tag.</p>
</video>
<div class="caption">Video1</div>
<div class="control">
<div class="btmControl">
<div class="btnPlay btn" title="Play/Pause video"><span class="icon-play"></span></div>
<div class="progress-bar">
<div class="progress">
<span class="bufferBar"></span>
<span class="timeBar"></span>
</div>
</div>
<!--<div class="volume" title="Set volume">
<span class="volumeBar"></span>
</div>-->
<div class="sound sound2 btn" title="Mute/Unmute sound"><span class="icon-sound"></span></div>
<div class="btnFS btn" title="Switch to full screen"><span class="icon-fullscreen"></span></div>
</div>
</div>
</div>
</section>
<!--Video 2-->
<section id="wrapper">
<div class="videoContainer">
<video id="myVideo" controls preload="auto" poster="http://s.cdpn.io/6035/vp_poster.jpg" width="380" >
<source src="http://html-testing.github.io/2/videos/mikethefrog.mp4" type="video/mp4" />
<p>Your browser does not support the video tag.</p>
</video>
<div class="caption">Video2</div>
<div class="control">
<div class="btmControl">
<div class="btnPlay btn" title="Play/Pause video"><span class="icon-play"></span></div>
<div class="progress-bar">
<div class="progress">
<span class="bufferBar"></span>
<span class="timeBar"></span>
</div>
</div>
<!--<div class="volume" title="Set volume">
<span class="volumeBar"></span>
</div>-->
<div class="sound sound2 btn" title="Mute/Unmute sound"><span class="icon-sound"></span></div>
<div class="btnFS btn" title="Switch to full screen"><span class="icon-fullscreen"></span></div>
</div>
</div>
</div>
</section>
</body>
</html>
CSS
#import url(http://fonts.googleapis.com/css?family=Oswald:300);
* {
box-sizing: border-box;
}
html {
width: 100%;
height: 100%;
background: #1f323e;
background: radial-gradient(ellipse cover at 80% 0%, #426168 0%, rgba(49, 67, 74, 0.1) 100%), radial-gradient(ellipse cover at 20% 100%, #080d11 0%, #243a43 100%);
}
body {
font-family: 'Oswald', sans-serif;
}
video {
border-radius: 6px;
}
/* video container */
.videoContainer {
width: 380px;
height: 200px;
position: relative;
overflow: hidden;
background: #000;
color: #ccc;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.8);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
margin: 50px auto 0;
}
.videoContainer:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.3);
z-index: 6;
border-radius: 6px;
pointer-events: none;
}
/* video caption css */
.caption {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 5px 10px;
color: #ddd;
font-size: 14px;
font-weight: 300;
text-align: center;
background: rgba(0, 0, 0, 0.4);
text-transform: uppercase;
border-radius: 6px 6px 0 0;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
}
/*** VIDEO CONTROLS CSS ***/
/* control holder */
.control {
color: #ccc;
position: absolute;
bottom: 10px;
left: 10px;
width: 360px;
z-index: 5;
display: none;
}
/* control bottom part */
.btmControl {
clear: both;
}
.control .btnPlay {
float: left;
width: 34px;
height: 30px;
padding: 5px;
background: rgba(0, 0, 0, 0.5);
cursor: pointer;
border-radius: 6px 0 0 6px;
border: 1px solid rgba(0, 0, 0, 0.7);
box-shadow: inset 0 0 1px rgba(255, 255, 255, 0.5);
}
.control .icon-play {
background: url(http://s.cdpn.io/6035/vp_sprite.png) no-repeat -11px 0;
width: 6px;
height: 9px;
display: block;
margin: 4px 0 0 8px;
}
.control .icon-pause {
background: url(http://s.cdpn.io/6035/vp_sprite.png) no-repeat -34px -1px;
width: 8px;
height: 9px;
display: block;
margin: 4px 0 0 8px;
}
.control .selected {
font-size: 15px;
color: #ccc;
}
.control .sound {
width: 30px;
height: 30px;
float: left;
background: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(0, 0, 0, 0.7);
border-left: none;
box-shadow: inset 0 0 1px rgba(255, 255, 255, 0.5);
cursor: pointer;
}
.control .icon-sound {
background: url(http://s.cdpn.io/6035/vp_sprite.png) no-repeat -19px 0;
width: 13px;
height: 10px;
display: block;
margin: 8px 0 0 8px;
}
.control .muted .icon-sound {
width: 7px !important;
}
.control .btnFS {
width: 30px;
height: 30px;
border-radius: 0 6px 6px 0;
float: left;
background: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(0, 0, 0, 0.7);
border-left: none;
box-shadow: inset 0 0 1px rgba(255, 255, 255, 0.5);
}
.control .icon-fullscreen {
background: url(http://s.cdpn.io/6035/vp_sprite.png) no-repeat 0 0;
width: 10px;
height: 10px;
display: block;
margin: 8px 0 0 9px;
}
/* PROGRESS BAR CSS */
/* Progress bar */
.progress-bar {
height: 30px;
padding: 10px;
background: rgba(0, 0, 0, 0.6);
border: 1px solid rgba(0, 0, 0, 0.7);
border-left: none;
box-shadow: inset 0 0 1px rgba(255, 255, 255, 0.5);
float: left;
}
.progress {
width: 240px;
height: 7px;
position: relative;
cursor: pointer;
background: rgba(0, 0, 0, 0.4);
/* fallback */
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 1px 1px black;
border-radius: 10px;
}
.progress span {
height: 100%;
position: absolute;
top: 0;
left: 0;
display: block;
border-radius: 10px;
}
.timeBar {
z-index: 10;
width: 0;
background: -webkit-linear-gradient(top, #6bcce2 0%, #1da3d0 100%);
box-shadow: 0 0 7px rgba(107, 204, 226, 0.5);
}
.bufferBar {
z-index: 5;
width: 0;
background: rgba(255, 255, 255, 0.2);
}
/* VOLUME BAR CSS */
/* volume bar */
.volume {
position: relative;
cursor: pointer;
width: 70px;
height: 10px;
float: right;
margin-top: 10px;
margin-right: 10px;
}
.volumeBar {
display: block;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #eee;
z-index: 10;
}
JavaScript
/*
JS Modified from a tutorial found here:
http://www.inwebson.com/html5/custom-html5...ls-with-jquery/
I really wanted to learn how to skin html5 video.
*/
$(document).ready(function(){
//INITIALIZE
var video = $('#myVideo');
//remove default control when JS loaded
video[0].removeAttribute("controls");
$('.control').fadeIn(500);
$('.caption').fadeIn(500);
//before everything get started
video.on('loadedmetadata', function() {
//set video properties
$('.current').text(timeFormat(0));
$('.duration').text(timeFormat(video[0].duration));
updateVolume(0, 0.7);
//start to get video buffering data
setTimeout(startBuffer, 150);
//bind video events
$('.videoContainer')
.hover(function() {
$('.control').stop().fadeIn();
$('.caption').stop().fadeIn();
}, function() {
if(!volumeDrag && !timeDrag){
$('.control').stop().fadeOut();
$('.caption').stop().fadeOut();
}
})
.on('click', function() {
$('.btnPlay').find('.icon-play').addClass('icon-pause').removeClass('icon-play');
$(this).unbind('click');
video[0].play();
});
});
//display video buffering bar
var startBuffer = function() {
var currentBuffer = video[0].buffered.end(0);
var maxduration = video[0].duration;
var perc = 100 * currentBuffer / maxduration;
$('.bufferBar').css('width',perc+'%');
if(currentBuffer < maxduration) {
setTimeout(startBuffer, 500);
}
};
//display current video play time
video.on('timeupdate', function() {
var currentPos = video[0].currentTime;
var maxduration = video[0].duration;
var perc = 100 * currentPos / maxduration;
$('.timeBar').css('width',perc+'%');
$('.current').text(timeFormat(currentPos));
});
//CONTROLS EVENTS
//video screen and play button clicked
video.on('click', function() { playpause(); } );
$('.btnPlay').on('click', function() { playpause(); } );
var playpause = function() {
if(video[0].paused || video[0].ended) {
$('.btnPlay').addClass('paused');
$('.btnPlay').find('.icon-play').addClass('icon-pause').removeClass('icon-play');
video[0].play();
} else {
$('.btnPlay').removeClass('paused');
$('.btnPlay').find('.icon-pause').removeClass('icon-pause').addClass('icon-play');
video[0].pause();
}
};
//fullscreen button clicked
$('.btnFS').on('click', function() {
if($.isFunction(video[0].webkitEnterFullscreen)) {
video[0].webkitEnterFullscreen();
}
else if ($.isFunction(video[0].mozRequestFullScreen)) {
video[0].mozRequestFullScreen();
} else {
alert('Your browsers doesn\'t support fullscreen');
}
});
//sound button clicked
$('.sound').click(function() {
video[0].muted = !video[0].muted;
$(this).toggleClass('muted');
if(video[0].muted) {
$('.volumeBar').css('width',0);
} else {
$('.volumeBar').css('width', video[0].volume*100+'%');
}
});
//VIDEO EVENTS
//video canplay event
video.on('canplay', function() {
$('.loading').fadeOut(100);
});
//video canplaythrough event
//solve Chrome cache issue
var completeloaded = false;
video.on('canplaythrough', function() {
completeloaded = true;
});
//video ended event
video.on('ended', function() {
$('.btnPlay').removeClass('paused');
video[0].pause();
});
//video seeking event
video.on('seeking', function() {
//if video fully loaded, ignore loading screen
if(!completeloaded) {
$('.loading').fadeIn(200);
}
});
//video seeked event
video.on('seeked', function() { });
//video waiting for more data event
video.on('waiting', function() {
$('.loading').fadeIn(200);
});
//VIDEO PROGRESS BAR
//when video timebar clicked
var timeDrag = false; /* check for drag event */
$('.progress').on('mousedown', function(e) {
timeDrag = true;
updatebar(e.pageX);
});
$(document).on('mouseup', function(e) {
if(timeDrag) {
timeDrag = false;
updatebar(e.pageX);
}
});
$(document).on('mousemove', function(e) {
if(timeDrag) {
updatebar(e.pageX);
}
});
var updatebar = function(x) {
var progress = $('.progress');
//calculate drag position
//and update video currenttime
//as well as progress bar
var maxduration = video[0].duration;
var position = x - progress.offset().left;
var percentage = 100 * position / progress.width();
if(percentage > 100) {
percentage = 100;
}
if(percentage < 0) {
percentage = 0;
}
$('.timeBar').css('width',percentage+'%');
video[0].currentTime = maxduration * percentage / 100;
};
//VOLUME BAR
//volume bar event
var volumeDrag = false;
$('.volume').on('mousedown', function(e) {
volumeDrag = true;
video[0].muted = false;
$('.sound').removeClass('muted');
updateVolume(e.pageX);
});
$(document).on('mouseup', function(e) {
if(volumeDrag) {
volumeDrag = false;
updateVolume(e.pageX);
}
});
$(document).on('mousemove', function(e) {
if(volumeDrag) {
updateVolume(e.pageX);
}
});
var updateVolume = function(x, vol) {
var volume = $('.volume');
var percentage;
//if only volume have specificed
//then direct update volume
if(vol) {
percentage = vol * 100;
} else {
var position = x - volume.offset().left;
percentage = 100 * position / volume.width();
}
if(percentage > 100) {
percentage = 100;
}
if(percentage < 0) {
percentage = 0;
}
//update volume bar and video volume
$('.volumeBar').css('width',percentage+'%');
video[0].volume = percentage / 100;
//change sound icon based on volume
if(video[0].volume === 0){
$('.sound').removeClass('sound2').addClass('muted');
}
else if(video[0].volume > 0.5){
$('.sound').removeClass('muted').addClass('sound2');
} else {
$('.sound').removeClass('muted').removeClass('sound2');
}
};
//Time format converter - 00:00
var timeFormat = function(seconds){
var m = Math.floor(seconds/60)<10 ? "0"+Math.floor(seconds/60) : Math.floor(seconds/60);
var s = Math.floor(seconds-(m*60))<10 ? "0"+Math.floor(seconds-(m*60)) : Math.floor(seconds-(m*60));
return m+":"+s;
};
});
Click Here for JS Fiddle.
You cannot have multiple ID's on one page. Change the video id's to classes. That is probably why you aren't getting the results you want.
After that, on click you can do:
$('.myVideo').each(function(){
this.play();
});
or
$('video').each(function(){
this.play();
});
EDIT
So upon re-reading the question I finally understand what you need to do. Your event selectors and everything should still be good.
1- change:
var video = $('#myVideo');
to
var video = $('.myVideo');
2- Pass the $(this).parents(.videoContainer) variable to your playpause() function. This will enable you to access the video container that is being clicked.
You can also consolidate your event function calls to one line:
$(document).on('click', 'video, .btnPlay', function(){
playPause($(this).parents('.videoContainer'));
});
var playPause = function($that){
var $playBtn = $that.find('.btnPlay');
var video = $that.find('video').get(0);
//video.pause() and video.play() is what you will you use to play/pause
//put your conditional statements and stuff here
}