I have built a gallery viewer with a preload function.
The preload function is as follows:
$.preloadFullImages = function() {
// Create array of images
var set = [];
$('.slide-item img').each(function() {
var img = $(this).data('src');
var id = $(this).parent().attr('id');
$(this).remove();
set.push([img,id]);
});
// Set current image
var current = 0;
var iterate = function() {
var current_src = set[current][0];
var current_id = set[current][1];
var temp = '<img src="'+current_src+'" />';
var target = '#'+current_id;
var targetImg = '#'+current_id+' img';
// Load 'temp' image
$(temp).bind('load', function() {
// Show image
$(target).append(temp);
$(targetImg).show();
$(this).remove();
});
if ( ++current < set.length ) iterate();
};
iterate();
};
On load of the page, images are loaded sequentially.
The problem is until all the images are loaded, the animation between images (prev and next arrows) is stunted and doesn't work correctly. I want the gallery viewer to transition smoothly between slides (images) even if not all images are loaded.
You can see a live demo here: http://www.davidclapp.net/portfolio
The issue is especially apparent on the iPhone (safari).
Is there a way to ensure the animation is smooth even whilst images are still loading?
Edit: I am using this plugin for CSS3 transitions - http://ricostacruz.com/jquery.transit/
$.preloadFullImages = function(callback) {
...
if ( ++current < set.length ) iterate();
else if(callback) callback(); //check if callback exists, then call it.
};
iterate();
};
These two lines being the important part.
$.preloadFullImages = function(callback) {
if ( ++current < set.length ) iterate();
else callback();
make a function to call the beginning of your animation, pass it to "preloadFullImages"
Related
I have a ul which contains images which are hidden and then loaded into a carousel using absolute positioning.
The height of these images is constrained in desktop view so I can control the height of the parent element as there is a small toggle menu below the ul.
When I switch to mobile I am using media queries to set the width of the image to 100% and reset the height. This means that the position of my toggle menu has to be calculated each time the next or previous slide is swiped as the image heights vary.
I currently have a function which is returning the height of the current slide and using that to set the height of the element, however I need this function to calculate the height of the next image if the user swipes right, or the previous for left.
This is my code:
// check height of slider
var chSliderHeight = function(){
var slider = $('.slider');
var sliderImg = slider.find('li:visible img');
var sliderImgNext = sliderImg.parent().next().find('img').height();
var sliderImgPrev = sliderImg.parent().prev().find('img').height();
var sliderH = sliderImg.get(0).height;
slider.css('height',sliderH + 40);
console.log(sliderH, sliderImgNext, sliderImgPrev);
};
$(window).on('load resize orientationchange',function(){
chSliderHeight();
});
The variables sliderImgNext and sliderImgPrev look like they are returning the values of the previous or next slides, but I don't know how to trigger the css height rule inside the swipe function.
And before this I have my swipe functions:
images.wipetouch({
wipeLeft: function(result) {
target = $('ul.triggers li.selected').index();
if ( target === lastElem ) { target = 0; }
else { target = target+1; }
sliderResponseMobile(target);
chSliderHeight();
},
wipeRight: function() {
target = $('ul.triggers li.selected').index();
lastElem = triggers.length-1;
if ( target === 0 ) { target = lastElem; }
else { target = target-1; }
sliderResponseMobile(target);
chSliderHeight();
}
});
I need some condition to run a slightly different function or parameter if swiping left or right. Maybe this should run inside a success function, I am not 100% sure. Maybe hoisting?
I am finding it difficult to get around the issue of writing a function inside chSliderHeight which is available to wipeLeft and wipeRight functions.
I have a full fiddle with a single dependency (and all other code loaded) HERE
This also has all the other code and vars contained.
OK managed to get this working.
One issue I was having, because the slider uses a fadeIn/fadeOut function, calling slider.find('li:visible img'); is returning a length of 2 as there are two slides visible at the time of calling the function.
So I changed my selector to this:
slider.find('li[class="active"] img');
And the length is now 1.
I then wrote a callback function like this:
var callback = function(){
var slider = $('.slider');
var sliderImg = slider.find('li[class="active"] img');
var sliderH = sliderImg.get(0).height;
slider.css('height',sliderH + 40);
};
And passed the callback function into the wipetouch functions, like so:
images.wipetouch({
wipeLeft: function(result) {
target = $('ul.triggers li.selected').index();
if ( target === lastElem ) { target = 0; }
else { target = target+1; }
sliderResponseMobile(target);
callback();
},
wipeRight: function() {
target = $('ul.triggers li.selected').index();
lastElem = triggers.length-1;
if ( target === 0 ) { target = lastElem; }
else { target = target-1; }
sliderResponseMobile(target);
callback();
}
});
sliderResponseMobile(target); now looks like this (so it adds an active class to each slide):
function sliderResponseMobile(target) {
images.removeClass('active').fadeOut(200).eq(target).fadeIn(400).addClass('active');
}
And here is a working FIDDLE
I am a beginner of javascript and jquery and i have 11 image tags in html. I want to
basically change sources of these tags using js and jquery. This code is not working and I am not getting any errors in firebug, can some one please tell me where I am doing wrong?
var imagesArray2=["01.png","02.png","03.png","04.png","05.png","06.png","07.png","08.png","09.png","10.png","11.png"];
var elementArray2 = ["#img1","#img2","#img3","#img4","#img5","#img6","#img7","#img8","#img9","#img10","#img11"];
var imagesArray,elementArray;
var elementInArray;
document ready
$(function(){
setInterval(Myfunction(),1000);});
my function code which has a loop based on elementsInArray variable value and it calls imageFadeAnimations function
function Myfunction(){
if(elementsInArray === 0){
imagesArray = imagesArray2;
elementArray = elementArray2;
elementsInArray = elementArray.length;
var imageChanges = Math.floor(Math.random()*elementsInArray);
imageFadeAnimations(imageChanges);
}
else
{
elementsInArray=elementArray.length;
imageChanges = Math.floor(Math.random()*elementsInArray);
imageFadeAnimations(imageChanges);
}
}
takes an integer as argument
function imageFadeAnimations(imageChanges){
for(var k = 0;k<imageChanges;k++){
var element = Math.floor(Math.random()*elementsinArray);
var image=Math.floor(Math.random()*elementsinArray);
imageChanger(elementArray[element],imageArray[image]);
elementArray.splice(element,1);
imagesArray.splice(image,1);
}
}
function imageChanger(b1,b2){
$(b1).fadeOut(500,function(){
$(b1).attr("src",b2);
$(b1).fadeIn(500);
});
}
You are making heavy weather out of something that jQuery can make very simple.
First wrap your images in an element (typically a div or a span) with id="imageContainer".
Now, if I understand correctly, your code will simplify to :
$(function() {
var imagesArray = ["01.png", "02.png", "03.png", "04.png", "05.png", "06.png", "07.png", "08.png", "09.png", "10.png", "11.png"],
$images = $("img", "#imageContainer");
setInterval(function() {
$images.each(function() {
var $img = $(this),
i = Math.min(imagesArray.length-1, Math.floor(Math.random() * imagesArray.length));
$img.fadeOut().promise().then(function() {
$img.attr("src", imagesArray[i]).fadeIn(500);
});
});
}, 1000);
});
EDIT 1
As #mplungjan points out below ...
If the img nodes were initialised with src attributes, then imagesArray can be composed by grabbing the srcs from the DOM as follows (replacing two lines above) :
var $images = $("img", "#imageContainer"),
imagesArray = $images.map(function() { return this.src; }).get();
I believe this jquery/zepto code is not the smaller, but the easier to understand:
function changeImg(){
$("#img1").attr('src', '01.png');
$("#img2").attr('src', '02.png');
$("#img3").attr('src', '03.png');
$("#img4").attr('src', '04.png');
$("#img5").attr('src', '05.png');
$("#img6").attr('src', '06.png');
};
I'm having trouble finding any good information on how to make a javascript(or jquery) progress bar WITH text that tells you the percentage.
I don't want a plug in, I just want to know how it works so that I can adapt it to what I need. How do you preload images and get a variable for the number of images that are preloaded. Also, how do you change html/css and-or call a function, based on the number of images that are loaded already?
<img> elements have an onload event that fires once the image has fully loaded. Therefore, in js you can keep track of the number of images that have loaded vs the number remaining using this event.
Images also have corresponding onerror and onabort events that fire when the image fails to load or the download have been aborted (by the user pressing the 'x' button). You also need to keep track of them along with the onload event to keep track of image loading properly.
Additional answer:
A simple example in pure js:
var img_to_load = [ '/img/1.jpg', '/img/2.jpg' ];
var loaded_images = 0;
for (var i=0; i<img_to_load.length; i++) {
var img = document.createElement('img');
img.src = img_to_load[i];
img.style.display = 'hidden'; // don't display preloaded images
img.onload = function () {
loaded_images ++;
if (loaded_images == img_to_load.length) {
alert('done loading images');
}
else {
alert((100*loaded_images/img_to_load.length) + '% loaded');
}
}
document.body.appendChild(img);
}
The example above doesn't handle onerror or onabort for clarity but real world code should take care of them as well.
What about using something below:
$('#btnUpload').click(function() {
var bar = document.getElementById('progBar'),
fallback = document.getElementById('downloadProgress'),
loaded = 0;
var load = function() {
loaded += 1;
bar.value = loaded;
/* The below will be visible if the progress tag is not supported */
$(fallback).empty().append("HTML5 progress tag not supported: ");
$('#progUpdate').empty().append(loaded + "% loaded");
if (loaded == 100) {
clearInterval(beginLoad);
$('#progUpdate').empty().append("Upload Complete");
console.log('Load was performed.');
}
};
var beginLoad = setInterval(function() {
load();
}, 50);
});
JSFIDDLE
You might also want to try HTML5 progress element:
<section>
<p>Progress: <progress id="p" max=100><span>0</span>%</progress></p>
<script>
var progressBar = document.getElementById('p');
function updateProgress(newValue) {
progressBar.value = newValue;
progressBar.getElementsByTagName('span')[0].textContent = newValue;
} </script>
</section>
http://www.html5tutorial.info/html5-progress.php
$('.pictures a').click(function () {
var path = "place/of/images";
var pics = ['pic1.JPG',
'pic2.JPG',
'pic3.JPG',
'pic4.JPG'];
var i = 0;
var numberOfPics = pics.length - 1;
var vaheta = setInterval(function () {
$('body').css({ backgroundImage: 'url(' + path + pics[i] + ')' });
if (i == numberOfPics) {
i = 0;
} else {
i++;
}
}, 3000);
return false;
});
This is the code that is currently just changing background images for me. Now I found a topic here where it says you have to load the pictures as etc and there was this fiddle, http://jsfiddle.net/RnqQL/1/, this one, that is exactly what I want to do, but I don't quite know how to combine these two (my code and the fiddle).
The images will actually later be loaded with JSON from the server depending on the id of the link the person clicked to get this slideshow, this is too overwhelming for me...
I created fiddle at http://jsfiddle.net/xMrp3/1/
You can modify and use. I try to explain what i did with comments.
$('.pictures a').click(function () {
var path = "http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/";
$("#wrap").empty(); // clear wrap div content
$.getJSON('/echo/json/', function (pics) { // get json data
var pics = ['s-1.jpg', 's-5.jpg', 's-3.jpg']; // i override json response for demo
$.each(pics, function(i, pic) { // loop through pics array
$('<img/>').attr('src', path + pic).appendTo($("#wrap")); // append all images to #wrap div
});
if (animTimeout == null) // if we didnt started anim yet
anim(); // start animation
});
return false;
});
var animTimeout = null;
function anim() {
$("#wrap img").first().appendTo('#wrap').fadeOut(500);
$("#wrap img").first().fadeIn(500);
animTimeout = setTimeout(anim, 700);
}
I want to fade in multiple images at the same time as the page loads. Just like this website does it: http://www.struckaxiom.com/work. I have the script to do it only on one image, but I want to have more images included.
This is the single photo script. Please help.
document.write("<style type='text/css'>#thephoto {visibility:hidden;}</style>");
function initImage() {
imageId = 'thephoto'
image = document.getElementById(imageId);
setOpacity(image, 0);
image.style.visibility = "visible";
fadeIn(imageId,ImageId2,0);
}
function fadeIn(objId, opacity) {
if (document.getElementById) {
obj = document.getElementById(objId);
if (opacity <= 100) {
setOpacity(obj, opacity);
opacity += 10;
window.setTimeout("fadeIn('"+objId+"',"+opacity+")", 100);
}
}
}
function setOpacity(obj, opacity) {
opacity = (opacity == 100)?99.999:opacity;
// IE/Win
obj.style.filter = "alpha(opacity:"+opacity+")";
// Safari<1.2, Konqueror
obj.style.KHTMLOpacity = opacity/100;
// Older Mozilla and Firefox
obj.style.MozOpacity = opacity/100;
// Safari 1.2, newer Firefox and Mozilla, CSS3
obj.style.opacity = opacity/100;
}
window.onload = function() {initImage()}
// -->
</script>
Thanks!
Simple array and loop are all you need.
First, add such array on top of the code:
var images = [ "thephoto1", "thephoto2", "thephoto3" ];
(With the ID of all desired images)
Next change the function name to initImages to reflect the fact it will initialize more than one image and finally add that loop:
function initImages() {
for (var i = 0; i < images.length; i++) {
imageId = images[i];
image = document.getElementById(imageId);
setOpacity(image, 0);
image.style.visibility = "visible";
fadeIn(imageId, 0);
}
}
That's it, no need to touch the other functions.
Live test case with cute cats: http://jsfiddle.net/yahavbr/e863X/ :-)
You could just wrap all of your images in a single container like this:
<div id="imageContainer">
<img src="img1.jpg">
<img src="img2.jpg">
<img src="img2.jpg">
</div>
Change your CSS to this:
<style type='text/css'>#imageContainer {visibility:hidden;}</style>
Change your first function to this:
function initImage() {
containerId = 'imageContainer'
container = document.getElementById(containerId);
setOpacity(container, 0);
container.style.visibility = "visible";
fadeIn(containerId,0);
}
By running the fading effect on the container you can then add as much content to the container and it will all fade in together and you never have to update your code.
The way they are doing is using jQuery (an excellent implementation). All of the images are in the same container and are selected using the jQuery class selector. Then they fade in all elements that fit within the viewable area. Their js file is not minimized so you could reverse engineer most of that functionality. The important thing to note is not that it is showing each row at a time but every element that fits in the viewing area. Their key function looks like this:
var elTop = $(el).offset().top - $(window).scrollTop();
var elHeight = $(el).height();
// if between top of footer and top of window
if (elTop + elHeight > 40 && elTop < $(window).height()) {
if ($.inArray($(el).attr("data-unique-id"), elementsInView) < 0) {
addToView(el);
}
} else {
if ($.inArray($(el).attr("data-unique-id"), elementsInView) >= 0) {
removeFromView(el);
}
}
addToView and removeFromView add and remove the element from an array, then fade is executed on the array.