Custom jQuery carousel transition bug - javascript

I am working on a custom image carousel, with jQuery and CSS. I am trying to avoid using a multiple-features carousel plugin download from Github, for performance reasons.
My aim is to obtain a vertical transition, like the one on www.pcgarage.ro, but without using the plugin they (might) have used. For this purpose, I have written:
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
for (var i = 0; i < slidesCount; i++) {
var bullets = '' + i + '';
if (i == 0) {
// active bullet
var bullets = '' + i + '';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
}
setZindex();
$('.slider-nav a').on('click', function() {
activeIdx = $(this).text();
$('.slider-nav a').removeClass('activeSlide');
$(this).addClass('activeSlide');
setActiveSlide();
slideUpDown();
});
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
}
var slideUpDown = function() {
// set top property for all the slides
$(slides).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
});
}
body {
margin: 0;
padding: 0;
}
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
position: absolute;
left: 10px;
bottom: 10px;
z-index: 30;
}
.slider .slider-nav a {
display: block;
float: left;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 3px;
text-indent: -9999px;
background: #fff;
}
.slider .slider-nav a.activeSlide {
background: transparent;
border: 2px solid #fff;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-nav"></div>
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=north" alt="">
</a>
</div>
</div>
</div>
The problem with my code is the (obvious) white screen that accompanies every transition, whose cause I do not understand.
Where is my mistake?

I have added some variable and function to fix this issue kindly check the script.
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
for (var i = 0; i < slidesCount; i++) {
var bullets = '' + i + '';
if (i == 0) {
// active bullet
var bullets = '' + i + '';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
// Set (initial) z-index for each slide
var setZindex = function () {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
}
setZindex();
var displayImageBeforeClick = null;
$('.slider-nav a').on('click', function () {
displayImageBeforeClick = $(".slider-container .active");
activeIdx = $(this).text();
if($(slides[activeIdx]).hasClass("active")){ return false; }
$('.slider-nav a').removeClass('activeSlide');
$(this).addClass('activeSlide');
setActiveSlide();
slideUpDown();
});
var setActiveSlide = function () {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
}
var slideUpDown = function () {
// set top property for all the slides
$(slides).not(displayImageBeforeClick).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
});
$(displayImageBeforeClick).animate({
'top': "-100%"
});
}
body {
margin: 0;
padding: 0;
}
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
position: absolute;
left: 10px;
bottom: 10px;
z-index: 30;
}
.slider .slider-nav a {
display: block;
float: left;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 3px;
text-indent: -9999px;
background: #fff;
}
.slider .slider-nav a.activeSlide {
background: transparent;
border: 2px solid #fff;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-nav"></div>
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=north" alt="">
</a>
</div>
</div>
</div>

Add Transition to your ".slider .slider-container a" with a transition-duration and transition-timing-function.... for reference you can see https://www.w3schools.com/css/css3_transitions.asp

Related

Scroll function on hover won't work unless resizing screen

I miss 1% to finish my script, I just don't know how to do it :D
When you hover over the target to the left, you can see the image will scroll. But after clicking on a new image it won't. I then have to resize the window to make it work again. How to fix that? Below is my code but for a working example, here's a CodePen
(function($) {
// virables
var layoutContainer = '.container';
var layoutTarget = '#target';
var layoutTargetIMG = '#target img';
var layoutIMG = '.container .gallery .item img';
var layoutIMGFirst = '.container .gallery .item:first-child img';
// Add first image to target
$(layoutIMGFirst).clone().appendTo(layoutTarget);
// Add image to target when click on gallery image
$(layoutIMG).click(function() {
$(this).closest(layoutContainer).find(layoutTarget).empty();
$(this).clone().appendTo(
$(this).closest(layoutContainer).find(layoutTarget)
);
});
// Image scroll on hover
// This won't work after clicking on an image unless resizing the browser
$(window).resize(function() {
// If i remove this it won't work on the start image.
// Any other solution?
setTimeout(function() {
$('#target img').each(function() {
var itemHeight = $('#target').outerHeight();
var imgHeight = $(this).outerHeight();
// Work out what percentage the image is of the item and remove 100% from that
var topHeight = (imgHeight / itemHeight) * 100 - 100;
//Make the animation speed proptional to that ratio
var animationSpeed = (imgHeight / itemHeight) / 1; //change 2 to tweak the speed
$(this).css({
transition: 'all ease ' + animationSpeed + 's'
});
$(this).mouseleave(function() {
$(this).css({
top: '0'
});
})
// The 'top' property of the image needs
// to be set as as a percentage of the parent
$(this).mouseenter(function(e) {
$(this).css({
top: '-' + topHeight + '%',
});
})
});
}, 200);
});
$(document).ready(function() {
setTimeout(function() { // Add delay after resize so function will load
$(window).triggerHandler('resize');
}, 200);
});
})(jQuery);
.container {
display: flex;
flex-flow: row wrap;
align-items: flex-start;
margin-left: -40px;
max-width: 1000px;
background: lightblue;
padding: 20px;
.column {
flex: 1;
min-width: 30%;
margin-left: 40px;
.target {
height: 400px;
background: pink;
position: relative;
overflow: hidden;
img {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
}
.cta {
display: flex;
a {
background: lightgreen;
width: 50%;
padding: 16px 8px;
;
text-align: center;
justify-content: center;
text-decoration: none;
&:last-child {
background: orange;
}
}
}
.gallery {
display: flex;
flex-flow: row wrap;
margin-left: -4px;
.item {
flex: 1;
margin-left: 4px;
position: relative;
overflow: hidden;
&::before {
content: '';
padding-top: 80%;
display: block;
}
img {
position: absolute;
min-width: 100%;
min-height: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
}
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="column">
<div id="target" class="target"></div>
<div class="cta">
SE DEMO
KØB LAYOUT
</div>
</div>
<div class="column">
<div class="gallery">
<div class="item">
<img src="https://picsum.photos/600/1200" alt="">
</div>
<div class="item">
<img src="https://picsum.photos/500/1600" alt="">
</div>
<div class="item">
<img src="https://picsum.photos/400/2000" alt="">
</div>
</div>
</div>
</div>
Just change this
$(layoutIMG).click(function() {
$(this).closest(layoutContainer).find(layoutTarget).empty();
$(this).clone().appendTo(
$(this).closest(layoutContainer).find(layoutTarget)
);
});
to
$(layoutIMG).click(function() {
$(this).closest(layoutContainer).find(layoutTarget).empty();
$(this).clone().appendTo(
$(this).closest(layoutContainer).find(layoutTarget)
);
$(window).triggerHandler('resize'); // added this line
});

Prevent event overlap in custom jQuery image carousel

UPDATE: the solution I have posted below is not good enough, because it makes all the bullets except the active one non-responsive to clicks, instead of queueing them, so there is room for improvement.
I am working on a custom image carousel, using jQuery and CSS. My aim is to make it really lightweight but with (just) enough features: "bullets", auto-advance, responsiveness.
It works fine, but I have discovered a bug I was unable to fix: when I click 2 bullets in rapid succession - which means clicking the second before the transition triggered by the first is finished - the transitions overlap in a weird manner I can not describe but is visible below:
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 1500,
animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var displayImageBeforeClick = null;
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
/* Prepend the slider navigation to the slider
if there are at least 2 slides */
$elm.prepend('<ul class="slider-nav"></ul>');
// make a bullet for each slide
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li>' + i + '</li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide">' + i + '</li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
};
var slideUpDown = function() {
// set top property for all the slides
$(slides).not(displayImageBeforeClick).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed);
$(displayImageBeforeClick).animate({
'top': "-100%"
}, animationspeed);
};
$('.slider-nav a').on('click', function(event) {
displayImageBeforeClick = $(".slider-container .active");
activeIdx = $(this).text();
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown();
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 3px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 3px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
How could I prevent this phenomenon I would call, for lack of a better term, an event crowding (overlap)?
You can chain your animations using jQuery deferred object and Promise. Here is the class allowing you to do it easily.
var Queue = function() {
var lastPromise = null;
this.add = function(callable) {
var methodDeferred = $.Deferred();
var queueDeferred = this.setup();
// execute next queue method
queueDeferred.done(function() {
// call actual method and wrap output in deferred
callable().then(methodDeferred.resolve)
});
lastPromise = methodDeferred.promise();
};
this.setup = function() {
var queueDeferred = $.Deferred();
// when the previous method returns, resolve this one
$.when(lastPromise).always(function() {
queueDeferred.resolve();
});
return queueDeferred.promise();
}
};
The fiddle is with the animations queued.
PS: I increase the size of the buttons to click more easily
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 1500,
animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
/* Prepend the slider navigation to the slider
if there are at least 2 slides */
$elm.prepend('<ul class="slider-nav"></ul>');
// make a bullet for each slide
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li>' + i + '</li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide">' + i + '</li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
};
var Queue = function() {
var lastPromise = null;
this.add = function(callable) {
var methodDeferred = $.Deferred();
var queueDeferred = this.setup();
// execute next queue method
queueDeferred.done(function() {
// call actual method and wrap output in deferred
callable().then(methodDeferred.resolve)
});
lastPromise = methodDeferred.promise();
};
this.setup = function() {
var queueDeferred = $.Deferred();
// when the previous method returns, resolve this one
$.when(lastPromise).always(function() {
queueDeferred.resolve();
});
return queueDeferred.promise();
}
};
var queue = new Queue();
var slideUpDown = function(previousIdx, activeIdx) {
queue.add(function() {
return new Promise(function(resolve, reject) {
// set top property for all the slides
$(slides).not(slides[previousIdx]).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed);
$(slides[previousIdx]).animate({
'top': "-100%"
}, animationspeed, 'swing', resolve);
})
})
};
var previousIdx = '0' // First slide
$('.slider-nav a').on('click', function(event) {
activeIdx = $(this).text();
// Disable clicling on an active item
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown(previousIdx, activeIdx);
previousIdx = activeIdx
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 6px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 6px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
Here is a possible fix, consisting of waiting for an animation to finish before starting another:
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 1500,
animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var displayImageBeforeClick = null;
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
/* Prepend the slider navigation to the slider
if there are at least 2 slides */
$elm.prepend('<ul class="slider-nav"></ul>');
// make a bullet for each slide
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li>' + i + '</li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide">' + i + '</li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
};
var animationStart = false;
var slideUpDown = function() {
animationStart = true;
// set top property for all the slides
$(slides).not(displayImageBeforeClick).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed, function() {
animationStart = false;
});
$(displayImageBeforeClick).animate({
'top': "-100%"
}, animationspeed, function() {
animationStart = false;
});
};
$('.slider-nav a').on('click', function(event) {
if (animationStart) {
return false;
}
displayImageBeforeClick = $(".slider-container .active");
activeIdx = $(this).text();
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown();
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 3px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 3px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
You could use a queue: every time you click a bullet it add to the queue and execute the queue. Something like this:
{
let
transitionQueue = [],
transitioning = false;
function doTransition() {
displayImageBeforeClick = $(".slider-container .active");
$('.slider-nav a').closest('li').removeClass('activeSlide');
transitionQueue.shift().closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown();
if (transitionQueue.length)
setTimeout(doTransition, animationSpeed)
else
transitioning = false;
}
function callTransition() {
if (!transitioning) {
transitioning = true;
doTransition();
}
}
$('.slider-nav a').click(function () {
transitionQueue.push($(this));
callTransition();
});
}
I haven't tested this, so...
While this not strictly answering your question, one way you could solve your actual problem is by handling your slider differently, consisting of moving the slider instead of the slides :
1) Make the slides container absolute, and it's container relative
.slider-homepage {
position: relative;
}
.slider .slider-container {
position: absolute;
}
.slider .slider-nav {
//position: absolute; Remove this
}
2) Instead of positionning the slides on click, move the slider container to the right position
var slideUpDown = function() {
$('.slider-container').stop().animate(
{top: activeIdx * slideHeight * -1},
{duration: animationspeed}
);
};
This way no image will ever overlap.
Here is the fiddle, the code can certainly be refactored but I didn't have too much time to look into it, will try to post a snippet here asap if you're ok with not leaving your original thing of moving slides instead of the slider.

Reset JavaScript interval instead of clearing it

I am working on a custom image carousel, using jQuery and CSS. My aim is to make it really lightweight but with enough features.
The script has an auto feature that I want to be stopped if the user clicks a bullet. I am using clearInterval for this purpose.
I would like to reset that interval, instead of clearing it. In other words, when the user clicks a bullet, I want that interval between two slides to be a "full" one (of 4 seconds).
Here is the code:
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 300,
animationInterval = 4000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var displayImageBeforeClick = null;
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li>' + i + '</li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide">' + i + '</li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
};
var slideUpDown = function() {
// set top property for all the slides
$(slides).not(displayImageBeforeClick).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed);
$(displayImageBeforeClick).animate({
'top': "-100%"
}, animationspeed);
};
$('.slider-nav a').on('click', function(event) {
event.preventDefault();
displayImageBeforeClick = $(".slider-container .active");
activeIdx = $(this).text();
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Stop autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
}
setActiveSlide();
slideUpDown();
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 3px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 3px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<ul class="slider-nav"></ul>
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
I have not figured out how to do that.
Like #epascarello said in a comment above, just clear & start again:
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
later edit:
If the callback or the interval are not available anymore when restarting, it could help to "save" them in a closure:
function startInterval(func, delay) {
var id = setInterval(func, delay);
return {
stop: function() { clearInterval(id); },
restart: function() { clearInterval(id); id = setInterval(func, delay); }
};
}
var autoAdvance = startInterval(advanceFunc, animationInterval);
//later
autoAdvance.restart();

Making a jQuery carousel automatically slide

So I've created my image slider and it is set to slide when one of the buttons is clicked. But now I'm struggling to make the slide automatically and stop when the mouse hovers over the sider. Could you show me or at least tell me how to do this? Thanks
$(document).ready(function(){
var slide_count = $(".carousel li").length;
var slide_width = $(".carousel li").width();
var slide_height = $(".carousel li").height();
var cont_width = slide_width * slide_count;
$(".cont").css({ height: slide_height, width: slide_width});
$(".carousel").css({ width: cont_width, marginLeft: - slide_width });
$(".carousel li:last-child").prependTo(".carousel");
function next_slide(){
$(".carousel").animate({
left: + slide_width
}, 400, function(){
$(".carousel li:last-child").prependTo(".carousel");
$('.carousel').css('left', 0);
}
);
}
function prev_slide(){
$(".carousel").animate({
left: - slide_width
}, 400, function(){
$(".carousel li:first-child").appendTo(".carousel");
$(".carousel").css("left", 0);
}
);
}
$("#next").click(function(){
next_slide();
});
$("#prev").click(function(){
prev_slide();
});
});
*{
padding: 0;
margin: 0;
}
body{
margin: 0;
padding: 0;
}
.cont{
position: relative;
text-align: center;
font-size: 0;/*removes white space*/
margin: 60px auto 0 auto;
padding: 0;
overflow: hidden;
}
.carousel{
position: relative;
margin: 0;
padding: 0;
list-style-type: none;
height: 100%;
max-height: 600px;
}
.carousel li{
float: left;
width: 750px;
height: 350px;
}
.carousel li img{
width: 100%;
height: auto;
}
#next{
position: absolute;
top: 45%;
right: 0;
width: 40px;
height: 40px;
background-color: blue;
font-size: 0;
z-index: 1;
}
#prev{
position: absolute;
top: 45%;
left: 0;
width: 40px;
height: 40px;
background-color: blue;
z-index: 1;
}
<div class="cont">
<div id="next">
</div>
<div id="prev">
</div>
<ul class="carousel">
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-2.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-6.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-1.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-3.jpg" alt="" />
</li>
</ul>
</div>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
You can achieve that by creating a setInterval() where you call your slider function every x seconds, and put a flag on it to not run if the mouse is over it.
Something like
var SECONDS_INTERVAL = 1000; // 1s
var mouseHoverFlag = false;
setInterval(function() {
if (!mouseHoverFlag) {
next_slide();
}
}, SECONDS_INTERVAL);
And change that mouseHoverFlag to true whenever the user has the mouse over the div that contains it.
$('.carousel').hover(function() {
mouseHoverFlag = true;
}, function () {
mouseHoverFlag = false;
});
You could use setTimeout and kill it every time that the mouse gets in but I think that's too heavy, performance wise.
Here is my edited version. We have to use setInterval function for automatic slide. Next we add hover event listener to carousel. If we are hovering, our variable preventSlide will change to true and if we stop hovering, variable will be changed back to false, which means auto slide.
var preventSlide = false;
$(".carousel").hover(function() {
preventSlide = true;
}, function() {
preventSlide = false;
});
setInterval(function () {
if (!preventSlide)
next_slide();
}, 3500);
$(document).ready(function(){
var slide_count = $(".carousel li").length;
var slide_width = $(".carousel li").width();
var slide_height = $(".carousel li").height();
var cont_width = slide_width * slide_count;
$(".cont").css({ height: slide_height, width: slide_width});
$(".carousel").css({ width: cont_width, marginLeft: - slide_width });
$(".carousel li:last-child").prependTo(".carousel");
function next_slide(){
$(".carousel").animate({
left: + slide_width
}, 400, function(){
$(".carousel li:last-child").prependTo(".carousel");
$('.carousel').css('left', 0);
}
);
}
function prev_slide(){
$(".carousel").animate({
left: - slide_width
}, 400, function(){
$(".carousel li:first-child").appendTo(".carousel");
$(".carousel").css("left", 0);
}
);
}
var preventSlide = false;
$(".carousel").hover(function() {
preventSlide = true;
}, function() {
preventSlide = false;
});
setInterval(function () {
if (!preventSlide)
next_slide();
}, 3500);
/*$("#next").click(function(){
next_slide();
});
$("#prev").click(function(){
prev_slide();
});*/
});
*{
padding: 0;
margin: 0;
}
body{
margin: 0;
padding: 0;
}
.cont{
position: relative;
text-align: center;
font-size: 0;/*removes white space*/
margin: 60px auto 0 auto;
padding: 0;
overflow: hidden;
}
.carousel{
position: relative;
margin: 0;
padding: 0;
list-style-type: none;
height: 100%;
max-height: 600px;
}
.carousel li{
float: left;
width: 750px;
height: 350px;
}
.carousel li img{
width: 100%;
height: auto;
}
#next{
position: absolute;
top: 45%;
right: 0;
width: 40px;
height: 40px;
background-color: blue;
font-size: 0;
z-index: 1;
}
#prev{
position: absolute;
top: 45%;
left: 0;
width: 40px;
height: 40px;
background-color: blue;
z-index: 1;
}
<div class="cont">
<div id="next">
</div>
<div id="prev">
</div>
<ul class="carousel">
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-2.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-6.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-1.jpg" alt="" />
</li>
<li>
<img src="http://lorempixel.com/output/abstract-q-c-1500-700-3.jpg" alt="" />
</li>
</ul>
</div>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
You should add a setInterval and clearInterval for automatic slide. Also it is good to calculate which slide you are in at the current animation. Briefly,
var timer;
var rotator = function(){
nextSlide();
};
timer = setInterval(rotator, 5000); // your desired timer
$('.carousel').hover(function(){ clearInterval(timer), function(){ timer = setInterval(rotator, 5000); });
you can optimize the code far better, but the basic solution is like this.
$(function(){
setInterval(function () {
moveRight();
}, 3000);
});
check here
You can set the time interval as an option in the carousel. You can also set the pause option on hover.
$("#myCarousel").carousel({interval: 500, pause: "hover"});

Implement nav dots to my slider?

I've been messing around with my slider and I got it to slide by itself. The problem is, there is no way you can manually view the slides. I would like to add navigation dots on the bottom so you can skim through the slides without having to view them as the slider goes along. If you could help me with this it would be greatly appreciated.
My slider html:
<div id="slider-container">
<div style="position: relative">
<div class="slide"><img id="slide_1" src="images/slide_1.jpg"/></div>
<div class="slide"><img id="slide_2" src="images/slide_2.jpg"/></div>
<div class="slide"><img id="slide_3" src="images/slide_3.jpg"/></div>
<div class="slide"><img id="slide_4" src="images/slide_4.jpg"/></div>
<div class="slide"><img id="slide_5" src="images/slide_5.jpg"/></div>
<div class="slide"><img id="slide_6" src="images/slide_6.jpg"/></div>
</div>
</div>
My slider css:
.slide-container {
display:block;
}
.slide {
top:0;
width:760px;
height:420px;
display:block;
position:absolute;
transform:scale(0);
transition:all .7s;
}
.slide img {
width:100%;
height:100%;
border-radius:6px;
border:1px solid #95ca1a;
}
My slider javascript:
$(document).ready(function() {
(function (){
var count = $(".slide > img").length;
var current = 1;
var sliderNext = 2;
$("img[id^='slide_']").fadeOut(0);
$("#slide_" + current).fadeIn(300);
var loop = setInterval(function() {
$("#slide_" + current).fadeOut(300);
$("#slide_" + sliderNext).fadeIn(300);
(sliderNext >= count) ? sliderNext = 1 : sliderNext++;
(current >= count) ? current = 1 : current++;
}, 3000)
})()
});
Here's an example of what I mean by nav dots:
CSS Slider - Codepen
First create list of dots, you can do it manually by creating list of "li" tags or can create it via jQuery.
here is code
<ol>
<li></li>
<li></li>
<li></li>
</ol>
number of "li" element should match with number of images
then have following css
#slider-container {
position:relative;
overflow:hidden;
width:100%;
height:380px;
display:inline-block;
}
.slide {
top:0;
width:100%;
display:inline-block;
}
.slide img {
width:100%;
height:100%;
border-radius:6px;
border:1px solid #95ca1a;
}
/******* css of dots ****/
ol{
list-style= none;
width:100%;
}
ol li{
background: #888;
border-radius: 50%;
display: inline-block;
width:20px;
height:20px;
cursor: pointer;
}
then add following jQuery stuff
$('ol li').bind('click', function(){
var index = $(this).index() + 1;
$(".active").fadeOut(300);
$("#slide_" + index).fadeIn(300);
$(".slide").removeClass("active");
$("#slide_" + index).addClass("active");
});
this code will hide active image and shows selected image
here is Fiddle example
hope it will help you
Here is a carousel script I wrote for a project. This allows you to click forward and backward and also on the dots. It's also dynamic so if you have 1 image, there are no dots or scroll bars, if you have 2 images there are the bars to go right and left but no dots, once you have three or more images the dots will be applied.
JsFiddle
HTML
<div class="carousel-container">
<div class="left-arrow"></div>
<div class="right-arrow"></div>
<div class="carousel-image-holder">
<img src="http://digitaljournal.com/img/8/7/8/4/4/i/1/1/7/o/ulingan_kids.jpg" />
<img src="http://freethoughtblogs.com/taslima/files/2012/06/22-funny2.jpg" />
<img src="http://blog.metrotrends.org/wp-content/uploads/2013/09/childPoverty.jpg" />
<img src="http://www.chinadaily.com.cn/china/images/2010WenUN/attachement/jpg/site1/20100921/0013729ece6b0e01d9691a.jpg" />
</div>
</div>
<div class="clear"></div>
<div class="carousel-buttons-container">
<ul></ul>
</div>
CSS
.clear{clear:both;}
.carousel-container{
width: 600px;
height: 360px;
float: left;
margin: 0;
padding: 0;
position: relative;
overflow: hidden;
}
.right-arrow{
width: 60px;
height: 100%;
background-color: rgba(0,0,0,.5);
position: absolute;
right: 0;
margin: 0;
padding: 0;
z-index: 2;
}
.left-arrow{
width: 60px;
height: 100%;
background-color: rgba(0,0,0,.5);
position: absolute;
left: 0;
margin: 0;
padding: 0;
z-index: 2;
}
.carousel-image-holder{
height:360px;
width: 2400px;
margin: 0;
padding: 0;
position: absolute;
z-index: 1;
}
.carousel-image-holder img{
width: 600px;
float: left;
margin: 0;
padding: 0;
display: inline-block;
}
.carousel-buttons-container{
width: 600px;
text-align: center;
margin: 15px 0 0 0;
padding: 0;
}
.carousel-buttons-container ul{
list-style-type: none;
margin: 0;
padding: 0;
}
.carousel-buttons{
background-color: #dddddd;
height: 18px;
width: 18px;
border-radius: 50%;
display: inline-block;
margin: 0 10px 0 0;
padding: 0;
cursor: pointer;
}
.carousel-buttons:last-of-type{
margin: 0;
}
.active{
background-color: #e67e22;
}
JQUERY
$(".left-arrow").hide();
var numImgs = $('div.carousel-image-holder img').length;
var addId = numImgs;
if(numImgs == 2){
var clicked = 0;
imgCount = numImgs-2;
}else if(numImgs <= 1){
$(".right-arrow").hide();
}else{
var clicked = 1;
imgCount = numImgs-1;
}
if(numImgs > 2){
for (var i=0; i<numImgs; i++){
$("ul").prepend('<li class="carousel-buttons" id="carousel'+addId+'"></li>');
var addId = addId - 1;
}
}else{
}
$(".carousel-buttons").click(function(){
var findIdClicked = $(this).attr("id");
var splitString = findIdClicked.split("carousel")
var findTheNumb = splitString[1];
$(".carousel-buttons").removeClass("active");
$(this).addClass("active");
clicked = parseInt(findTheNumb);
var adjustNumberforSlide = findTheNumb-1;
$(".carousel-image-holder").animate({"left": -(600*adjustNumberforSlide)+"px"});
console.log(clicked);
if(findTheNumb == 1){
$(".left-arrow").hide();
$(".right-arrow").show();
}else if (findTheNumb == numImgs){
$(".right-arrow").hide();
$(".left-arrow").show();
}else{
$(".right-arrow").show();
$(".left-arrow").show();
}
});
$(".carousel-buttons-container").find("li").first().addClass("active");
$(".right-arrow").click(function(){
if (clicked < imgCount){
$(".carousel-image-holder").animate({"left": "-=600px"});
console.log(clicked);
}else{
$(".carousel-image-holder").animate({"left": "-=600px"});
$(".right-arrow").hide();
console.log(clicked);
}
clicked = clicked+1;
$(".left-arrow").show();
$(".carousel-buttons").removeClass("active");
$("#carousel"+clicked).addClass("active");
});
$(".left-arrow").click(function(){
if (clicked > 2){
$(".carousel-image-holder").animate({"left": "+=600px"});
console.log(clicked);
}else{
$(".carousel-image-holder").animate({"left": "+=600px"});
$(".left-arrow").hide();
console.log(clicked);
}
$(".right-arrow").show();
clicked = clicked-1;
$(".carousel-buttons").removeClass("active");
$("#carousel"+clicked).addClass("active");
});
I'll clean up the spacing, just wanted to get this posted

Categories

Resources