I am trying to make an image carousel. I am using the jQuery .each() method to iterate over all the images in the div with class="slideshow".
HTML code
<div class="slideshow">
<img src="images/page-1-hero-image.jpg" alt="school's image" class="img-responsive page-one-pic mySlides">
<img src="images/Capture2.PNG" alt="school pic" class="img-responsive mySlides">
<img src="images/Capture.PNG" alt="school pic" class="img-responsive mySlides">
<img src="images/Capture3.PNG" alt="school pic" class="img-responsive mySlides">
</div>
CSS code
.mySlides {
display: none;
position: fixed;
left: 0;
top: 0;
z-index: 1;
/* to make pic responsive */
min-height: 100%;
min-width: 1024px;
width: 100%;
height: auto;
}
Javascript:
function carousel() {
$(".slideshow > img").each(function(index, element) {
$(element).fadeIn(1000).delay(2000);
setTimeout(carousel, 1000);
});
}
The function only fades in the first image and then stops. The other images are not displayed.
here is the link to the hosted project:
https://rimildeyjsr.github.io/St.Anthony-Website/
This code:
function carousel() {
$(".slideshow > img").each(function(index,element){
$(element).fadeIn(1000).delay(2000);
setTimeout(carousel,1000);
});
}
Says: "For each img element, spend a second fading in, then delay by two seconds before doing nothing, and reschedule this entire process (not per element, for all of them) to run again a second from now."
That doesn't make much sense, you'll be calling carousel several times again roughly at the time the first image finishes fading out.
Given the term "slideshow" I'd guess what you're trying to do is show each image for two seconds before spending a second having the next one fade in, looping when you get to the end. If so, you want to call carousel once, two seconds after the last image has finished fading in. You can do that by delaying the fades and the next call.
function carousel() {
var imgs = $(".slideshow > img");
imgs.each(function(index,element){
// Don't make the first one (index = 0) wait at all;
// make the second (index = 1) wait 3 seconds, the third
// (index = 2) wait 6 seconds, etc. And then fade in
$(element).delay(index * 3000).fadeIn(1000);
});
// Start the entire process again two seconds after the last image fades in
setTimeout(carousel, imgs.length * 3000);
}
Just an improvement to the previous answer, you can do it in the form of a callback(which ensures you that the function is called only after the fadeIn has occurred or happened, so you wont need a setTimeout) as follows
function carousel() {
var imgs = $(".slideshow > img");
imgs.each(function(index, element) {
$(element).delay(index * 2000).fadeIn(1000, function() {
if (index + 1 >= imgs.length) {
carousel(); // call the function only after all images are fadeIn completed
}
});
});
}
See if that helps and if not drop a comment below
Edit:
After .fadeIn() does it's job, it sets the display value to block what you have to do here is, hide the elements before continuing the slideshow animation, for simplicity we'll set all the img elements display to hidden by using .hide(0). This sets the elements display to none
function carousel() {
var imgs = $(".slideshow > img");
imgs.stop().hide(0); // hide all the images whenever the carousel() is called
imgs.each(function(index, element) {
$(element).delay(index * 2000).fadeIn(1000, function() {
if (index + 1 >= imgs.length) {
carousel(); // call the function only after all images are fadeIn completed
}
});
});
}
Let me know if you need anything else
Related
I'm trying to learn jQuery and I have this case, I have 3 slides, each slide has some boxes and I want to display them one by one by adding the class .show.
The thing should work like this:
show boxes on the first slide one by one
after all are showed, i want to wait 1 second and do the same for the second
repeat, but after show I want to show first slide again.
$('.slide').each(function() {
var $childrens = $(this).children();
$childrens.each(function() {
$this.addClass('show');
});
});
Can someone explain me how to do this?
Here is what I tried.
http://jsbin.com/jigoku/22/edit?html,css,js,output
I used recursion in a few places here to facilitate the delay in showing the slides. Your code is solid but it runs near-instantly so I don't think you get the effect you are going for.
showSlideItems is responsible for adding the show to each child of the slides. It waits 200ms and displays the next child.
slideDelay takes all slides and goes through them, adding a 1 second wait after all children of one slide is shown.
showSlides is responsible for grabbing all our slides and resetting their children so we can loop after both of the above functions complete.
jsFiddle example
javascript
function showSlides(){
var slides = $('.slide');
$('.slide i').removeClass('show');
slideDelay(slides.toArray());
}
function slideDelay(slides) {
var slide = slides.shift();
showSlideItems($(slide).children().toArray(), function(){
setTimeout(function(){
if(slides.length > 0){
slideDelay(slides);
}else{
showSlides();
}
}, 1000);
});
}
function showSlideItems(slideItems, callback) {
if(slideItems.length === 0) {
callback();
return;
}
var slideItem = slideItems.shift();
$(slideItem).addClass('show');
setTimeout(function(){ showSlideItems(slideItems, callback) }, 200);
}
showSlides();
html
<div class="slide">
<i>one</i>
<i>two</i>
<i>three</i>
</div>
<div class="slide slide-2">
<i>four</i>
<i>five</i>
<i>six</i>
<i>seven</i>
</div>
<div class="slide slide-3">
<i>eight</i>
<i>nine</i>
<i>ten</i>
</div>
css
.slide{
margin-top: 20px;
}
.show {
display: block !important;
}
.slide i {
display: none;
}
I've got a tricky little problem. I'm just starting out the design for a website with a cycling background image. At the minute it's working fine, although you can see the alternate background images loading with the first image which looks a little messy. I could pretty easily hide these images, but I feel a better solution would be to allow the first image to load before the others to speed up the page load. Unfortunately I cant work out how to incorporate this into my existing JS.
The beginnings of the site are here (it might be broken at some point, I'm still experimenting).
My current JS:
function cycleImages(){
var $active = $('#background-cycler .active');
var $next = ($('#background-cycler .active').next().length > 0) ? $('#background-cycler .active').next() : $('#background-cycler img:first');
$next.css('z-index',2);//move the next image up the pile
$active.fadeOut(1500,function(){//fade out the top image
$active.css('z-index',1).show().removeClass('active');//reset the z-index and unhide the image
$next.css('z-index',3).addClass('active');//make the next image the top one
});
}
$(window).load(function(){
$('#background-cycler').fadeIn(1500);//fade the background back in once all the images are loaded
// run every 7s
setInterval('cycleImages()', 7000);
})
HTML:
<div id="background-cycler" >
<script type="text/javascript">
$('#background_cycler').hide();//hide the background while the images load, ready to fade in later
</script>
<img class="active" src="images/bg1.jpg" alt=""/>
<img src="images/bg2.jpg" alt=""/>
<img src="images/bg3.jpg" alt=""/>
<img src="images/bg4.jpg" alt=""/>
<img src="images/bg5.jpg" alt=""/>
</div>
Any help you could give would be greatly appreciated!! :)
EDIT: The other problem I have is I need this on every page, but I'd rather not reload the images each time. Am I right in thinking the images will still be cached?
Here's my take at it:
http://jsfiddle.net/bortao/9TxED/
You hide the image element and only fade it in when the onload event is triggered.
And yes, all images will be cached by the browser throughout your site.
HTML
<div id="background-cycler" class="background-cycler">
<img id="imgPrev" />
<img id="imgNext" />
</div>
CSS
.background-cycler {
width: 1000px;
height: 600px;
}
.background-cycler img {
position: absolute;
left: 0px;
top: 0px;
}
JS
var imgs = [
'http://ravenstudio.co.uk/izzy/images/bg1.jpg',
'http://ravenstudio.co.uk/izzy/images/bg2.jpg',
'http://ravenstudio.co.uk/izzy/images/bg3.jpg',
'http://ravenstudio.co.uk/izzy/images/bg4.jpg',
'http://ravenstudio.co.uk/izzy/images/bg5.jpg']
var imgNext = document.getElementById("imgNext");
var imgPrev = document.getElementById("imgPrev");
var currentImg = -1;
var MAX_IMAGES = 5;
var CYCLE_DELAY = 2000;
var FADE_DELAY = 1500;
imgNext.onload = function () {
// When finished loading:
$(this).fadeIn(FADE_DELAY, function() {
// When fadeIn ends:
imgPrev.src = imgs[currentImg]; // Send current image to back
}); // Fade in loaded image
window.setTimeout('cycleImages()', CYCLE_DELAY + FADE_DELAY); // Set next cycle
};
cycleImages = function () {
currentImg++;
if (currentImg == MAX_IMAGES) currentImg = 0;
imgNext.style.display = "none"; // Hide before loading
imgNext.src = imgs[currentImg]; // Load new image.
// After imgNext finish loading, onload above will be called
}
cycleImages(); // Call the first cycle
So I seem to have run into a bit of a dead end. I'm making a page which has an image slider. The slider has three images, one centered on the screen, the other two overflow on the left and right. When you click on the button to advance the slides it runs this code....
$('#slideRight').click(function() {
if ($('.container').is(':animated')) {return false;}
var next=parseInt($('.container img:last-of-type').attr('id')) + 1;
if (next == 12) {
next = 0;
}
var diff = galsize() - 700;
if ($('.thumbs').css("left") == "0px") {
var plus = 78;
} else {
var plus = 0;
}
var app='<img id="' + next + '" src="' + imgs[next].src + '">';
$('.container').width('2800px').append(app);
$('.container').animate({marginLeft: (diff + plus) + "px"}, 300, function() {
$('.container img:first-of-type').remove();
$('.container').width('2100px').css("margin-left", (galsize() + plus) + "px");
});
}); // end right click
This works just fine, not a problem..... I also have an interval set up to run this automatically every 5 seconds to form a slideshow...
var slideShow = setInterval(function() {
$('#slideRight').trigger("click");
}, 5000);
This also works perfectly, not a problem.... However my problem is this.... I have thumbnails, when you click on a thumbnail, it should run this code until the current picture is the same as the thumbnail.... here is the code....
$('img.thumbnail').click(function() {
clearInterval(slideShow);
var src = $(this).attr("src");
while ($('.container img:eq(1)').attr('src') != src) {
$('#slideRight').trigger("click");
}
});
When I click on the thumbnail nothing happens... I've used alert statements to try and debug, what ends up happening is this....
The while loop executes, however nothing happens the first time. The slide is not advanced at all. Starting with the second execution, the is('::animated') is triggered EVERY TIME and the remainder of the slideRight event is not executed...
So my first problem, can anyone shed some light on why it doesn't run the first time?
And my second question, is there any way to wait until the animation is complete before continuing with the loop?
Any help would be appreciated. Thank you!
I'm going to start with the second part of your question, regarding completing the animation before continuing with the loop.
I have done something similar in the past, and what I did was set two global variables to control the animation. One variable is for how long you want the period to be, the other is a counter for how much time since the last loop.
So, for example:
$timeToChange = 5; // in Seconds
$timeSinceReset = 0; // also in Seconds
Set your interval for one second and call a new function (autoAdvance()):
var slideShow = setInterval(function() {
autoAdvance();
}, 1000); // only one second
and then use the counter variable to count each time the interval is called (each second). Something like:
function autoAdvance(){
if($timeSinceReset == $timeToChange){
$timeSinceReset = 0;
$('#slideRight').trigger("click"); // execute click if satisfied
}
else{$timeSinceReset++;}
}
To stop from looping until the animation is done, reset $timeSinceReset back to 0 (zero) when you click on the thumbnail. Something like:
$('#thumbnail').click(function(){
$timeSinceReset = 0;
});
That'll give you a nice 5 second buffer (or whatever you set $timeToChange) before the loop continues.
As for the first part of your question, grab the number of the particular thumbnail, and use that to scroll to the appropriate image. Something like:
$('.thumb').click(function (each) {
$childNumber = $(this).index();
});
which you cansee in this fiddle. Click in one of the grey boxes and it'll tell you which one you clicked in. Use that info to scroll to the appropriate image (1, 2 or 3 if you only have three images).
Hope this helps.
Here is a full solution for one possible way of doing it at this fiddle.
HTML:
The top container holds the images. In this particular example I've included three, using divs instead of images. Whether you use images or divs doesn't change anything.
<div class="holder_container">
<div class="img_container">
<div class="photo type1">ONE</div>
<div class="photo type2">TWO</div>
<div class="photo type3">THREE</div>
</div>
</div>
.img_container holds all the images, and is the same width as the sum of the widths of the images. In this case, each image (.photo) is 150px wide and 50px tall, so .img_container is 450px wide and 50px tall. .holder_container is the same dimensions as a single image. When this runs, the .holder_container is set to hide any overflow while .img_container moves its position left or right.
Included also are two nav buttons (forward and back)
<div class="nav_buttons">
<div class="nav back"><<<</div>
<div class="nav forward">>>></div>
</div>
As well as three thumbnail images - one for each image in the top container
<div class="top">
<div class="thumb"></div>
<div class="thumb"></div>
<div class="thumb"></div>
</div>
CSS:
Refer to the JS Fiddle for all CSS rules.
The most important are:
.holder_container {
margin: 0px;
padding: 0px;
height: 50px;
width: 150px;
position: relative;
overflow: hidden;
}
.img_container {
margin: 0px;
padding: 0px;
height: 50px;
width: 450px;
position: relative;
left: 0px;
top: 0px;
}
In the example, .type1, .type2 and .type3 are only used to color the image divs so you can see the animation. They can be left out of your code.
JavaScript:
The javascript contains the following elements…
Variables:
var timeToChange = 3; // period of the image change, in seconds
var timeSinceReset = 0; // how many seconds have passed since last image change
var currentImage = 1; // Which image you are currently viewing
var totalImages = 3; // How many images there are in total
Functions:
autoAdvance - called once every second via setInterval. Counts the number of seconds since the last image change. If the number of seconds that has passed is equal to the period, a function is called that switches the images.
function autoAdvance() {
if (timeSinceReset == timeToChange) {
timeSinceReset = 0;
moveNext();
} else {
timeSinceReset++;
}
}
moveNext() - moves to the next image. If the current image is the last (currentImage == totalImages) then currentImages is set back to 1 and the first image is displayed.
function moveNext(){
if(currentImage == totalImages){
currentImage = 1;
var newPos = 0 + 'px';
$('.img_container').animate({left: newPos}, 300);
}else{
currentImage++;
var newPos = -((currentImage-1) * 150) + 'px'; // child numbers are zero-based
$('.img_container').animate({left: newPos}, 300);
}
}
Rest of code:
If one of the thumbs is clicked, move to the corresponding image.
$('.thumb').click(function (each) {
timeSinceReset = 0;
var childNumber = $(this).index();
currentImage = childNumber + 1; // child numbers are zero-based
var newPos = -(childNumber * 150) + 'px'; // child numbers are zero-based
$('.img_container').animate({left: newPos}, 300);
});
If one of the navigation buttons is clicked, move accordingly. If "back" is clicked, move one image backwards (or to last image if currently on first). If "first" is clicked, move one image forwards (or to first image if currently on last).
$('.nav').click(function(){
timeSinceReset = 0;
if($(this).hasClass('back')){ // Back button
if(currentImage == 1){
currentImage = totalImages;
}else{
currentImage--;
}
}else{ // Forward button
if(currentImage == totalImages){
currentImage = 1;
}else{
currentImage++;
}
}
var newPos = -((currentImage-1) * 150) + 'px';
$('.img_container').animate({left: newPos}, 300);
});
Here is the link to the fiddle example.
I would like to make some changes on a code and add some more options:
1- Rotate the images with the description of each one as well as the link,
2- Add the effect fadeOut while the image is disappearing.
Here is my little code:
var images = new Array ('BMW.png', 'Maybach.png', 'Mercedes-Benz.png', 'Mini.png', 'Jaguar.png', 'Toyota.png');
var descs = new Array ('BMW', 'Maybach', 'Mercedes-Benz', 'Mini', 'Jaguar', 'Toyota');
var links = new Array ('www.url1.com', 'www.url2.com', 'www.url3.com', 'www.url4.com', 'www.url5.com', 'www.url6.com');
var index = 1;
function rotateImage()
{
$('#myImage').fadeOut('fast', function()
{
$(this).attr('src', images[index]);
$(this).fadeIn(2000, function()
{
if (index == images.length-1)
{
index = 0;
}
else
{
index++;
}
});
});
}
$(document).ready(function()
{
setInterval (rotateImage, 7000);
});
</script>
</head>
<body>
<div id="test">
<a href="www.url1.com">
<img class="rotate" id="myImage" src="BMW.png" width="800" height="300" alt="image test" />
</a>
<div class="rotate" id="myDesc" style="margin-top: -30px; margin-left: 30px;"></div>
</div>
uhm... something like this?
(Array is ZERO base so... initial index is 0 [with 1 you start with "Maybach.png" not "BMW.png" ]).
"Add the effect fadeOut while the image is disappearing" - if the image is disappearing is already doing a fade out... you should explain this point...
However...
var images = ['http://placehold.it/150x100', 'http://placehold.it/120x150', 'http://placehold.it/90x120', 'http://placehold.it/100x100', 'http://placehold.it/100x150', 'http://placehold.it/150x100'],
descs = ['BMW', 'Maybach', 'Mercedes-Benz', 'Mini', 'Jaguar', 'Toyota'],
links = ['www.url1.com', 'www.url2.com', 'www.url3.com', 'www.url4.com', 'www.url5.com', 'www.url6.com'],
index = 0; //start from first image
function rotateImage()
{
$('#test').fadeOut('fast', function() //fadeout all block (if display none collapse your graphics use animate and "opacity") to hide without change display
{
$(this).find("a").attr('href', links[index]); //add href to url
$(this).find("img").attr('src', images[index]); //add src to image
$(this).find("#myDesc").text(descs[index]); //add description in desc div
$(this).delay(500).fadeIn(2000, function() //delay (a little bit) to wait image load (for bigger image you need longer delay)
{
if (index == images.length-1)
{
index = 0;
}
else
{
index++;
}
});
});
}
$(document).ready(function()
{
rotateImage(); //fire first time and then use Setinterval for loop
setInterval (rotateImage, 7000);
});
Example HERE jsfiddler
I hope this can help.
Simple image preload:
<img src="path/placeholder.gif" data-src="path/realImage.jpg" style="display:none" />
so the image that be loaded is a gif of trasparent singol pixel. when you need to preload you only need to place data-src in src and than show image... (do this when the prev image of your animation was displayed for prevent the load gap when this image will display)
I'm working on a website for a family friend. On it they wanted to have logos from all their associates on one row, that subtly fade to get replaced with additional logos that didn't fit the first time.
To achieve this i've assigned the <img>'s classes, that represent what cycle they should appear in, depending on how many of those images will fit on the row given its current width. This happens in my assignCycleNumbers function.
Then to actually fade them in and out i have another function called cycleAssociates which recursively fades the appropriate classes in and out. Well in theory, however it doesn't seem to be working properly, which is particularly odd because i tested the function here and it works fine. The only difference between them is that now i'm trying to assign the cycle numbers dynamically.
I'm really stumped and could do with some help!
You can see the website hosted here and if you scroll down to the bottom of the content you'll see the logos at the bottom, not behaving as expected. (First cycle appears okay but then subsequent cycles get muddled, more observable if you resize to a smaller screen width).
You can inspect the code thoroughly through your browser but here's everything you need to know, again i'd really appreciate any insight.
EDIT: The whole javascript file as requested. But all the relevant stuff is below:
JS:
//single global variable to represent how many logo cycles there is
var totalCycles = 0;
...
$(window).load(function() {
...
totalCycles = assignCycleNumbers();
cycleAssociates();
});
// window is resized
$(function(){
$(window).resize(function() {
...
totalCycles = assignCycleNumbers();
});
});
...
function cycleAssociates(){
var cycle = 0;
var recursiveCycling = function(cycle, totalCycles){
var currentAssociate = ".cycle" + cycle;
//fade in all img with the current cyle class over a second,
//wait 3 seconds before fading out over a second.
$(currentAssociate).delay(100).fadeIn(1000).delay(3000).fadeOut(1000,
function(){
cycle++;
if(cycle > totalCycles){
cycle = 0;
}
recursiveCycling(cycle, totalCycles);
});
};
recursiveCycling(cycle, totalCycles);
}
function assignCycleNumbers(){
//first remove any old cycle# classes (resized window case)
$('[class*="cycle"]').removeClass( function(unusedIdx,c){
return c.match(/cycle\d+/g).join(" ");
});
//measure div width
var divSpace = $("#bodies").innerWidth();
//assign a cycle number to a number of logos until no more will fit in that div
var cycleNum = 0;
$(".associate").each(function(){
if( divSpace - $(this).width() > 0){
$(this).addClass("cycle" + cycleNum);
divSpace = divSpace - $(this).width();
}
else{ //next logo won't fit current cycle, create next cycle
cycleNum++
$(this).addClass("cycle" + cycleNum);
divSpace = $("#bodies").innerWidth() - $(this).width();
}
});
return cycleNum;
}
html:
<img class="associate" src="IMG/spare.png" alt=""/>
<img class="associate" src="IMG/bcs_professional.jpg" alt="BCS Professional Member"/>
<img class="associate" src="IMG/climate_savers.jpg" alt="Climate Savers Smart Computing"/>
<img class="associate" src="IMG/code_of_conduct.jpg" alt="Data Centres Code Of Conduct Endorser"/>
<img class="associate" src="IMG/spare.gif" alt=""/>
<img class="associate" src="IMG/enistic.gif" alt="Enistic"/>
<img class="associate" src="IMG/greentrac_authorised.png" alt="Greentrac Authorised Reseller"/>
<img class="associate" src="IMG/very_pc.jpg" alt="Very PC Approved"/>
<img class="associate" src="IMG/spare.jpg" alt=""/>
css:
#bodies img.associate{
float: left;
max-width: 120px;
max-height: 80px;
display:none;
}
The issue is that your fadeOut function's callback is being executed even before all elements in the current cycle are faded out. Here's a modified version of your function that works as expected:
function cycleAssociates(){
var cycle = 0;
var recursiveCycling = function(cycle, totalCycles){
var currentAssociate = ".cycle" + cycle;
var n = $(currentAssociate).length; //How many images in current cycle?
$(currentAssociate).each(function() {
$(this).delay(100).fadeIn(1000).delay(3000).fadeOut(1000, function() {
n --;
if(n <= 0) { //current cycle done?
cycle++;
if(cycle > totalCycles){
cycle = 0;
}
recursiveCycling(cycle, totalCycles);
}
});
});
};
recursiveCycling(cycle, totalCycles);
}
To fix the issues that come up on window resize, try replacing your current $(window).resize handler with this:
$(function(){
$(window).resize(function() {
parallelNavbar();
$(".associate").stop(); //if there are any animations, stop 'em
$(".associate").hide(); //hide all associates
totalCycles = assignCycleNumbers(); //update the assignment
cycleAssociates(); //let's get cyclin' again!
});
});
Although I think you have some issues with scrolling. This should resolve the main cycling problem, though -- so I hope that helped!