How to exit a function embedded in an $.each() block? - javascript

Sorry but, I've had a look at similar posts on Stack Overflow and could not find my exact situation.
I'm iterating on a bunch of images and I want to exit as soon as I find the one meeting my specifications. Trouble is, I need to use an 'onload' event to test that.
I don't know how to break out of my innermost function: the each() loop always iterates on all items, even though the second image fits the bill. Here's the jsfiddle: you will see 3 alerts, one for each iteration. http://jsfiddle.net/q07awnbr/10/
If anyone could guide me, that would be awesome! Thx.
// A bunch of images
var arrImages = ["http://i.imgur.com/cKUVXuQ.jpg","http://i.imgur.com/Ei598tR.jpg","http://i.imgur.com/W92PhqU.jpg"];
// Iterate until I find the first one meeting my specs
$.each(arrImages, function(i,item)
{
extension = item.slice(-(3)).toLowerCase();
if (extension == "jpg")
{
// Test image size
newImg = new Image();
newImg.onload = function()
{
if (this.width > 600 && this.height > 900)
{
// All right! That's the one. Set it as src on my web page
$("#MyImgBg").attr("src",this.src);
return false; // trying to break out - not working
}
};
newImg.src = item;
}
// I expected this alert to popup only twice
alert(i);
});

The following loads one image at a time and checks if it is the correct size, if not it loads the next one. It stops once the correct image has been loaded.
// A bunch of images
var arrImages = ["http://i.imgur.com/cKUVXuQ.jpg","http://i.imgur.com/Ei598tR.jpg","http://i.imgur.com/W92PhqU.jpg"];
// Loads image with index i
var loadImage = function(i){
extension = arrImages[i].slice(-(3)).toLowerCase();
if (extension == "jpg"){
// Test image size
var newImg = new Image();
newImg.src = arrImages[i];
newImg.onload = function(){
if (this.width > 600 && this.height > 900){
// All right! That's the one. Set it as src on my web page
$("#MyImgBg").attr("src",this.src);
}else{
if(i < arrImages.length){
// This is not the one, load next one.
loadImage(i+1);
}
}
}
}else{
if(i < arrImages.length){
// Wrong file extension, try next one.
loadImage(i+1);
}
}
alert(i);
}
loadImage(0); // Start with first image

The onload handler is asynchronous so it runs AFTER the .each() loop has finished. Thus, you can't stop the .each() from inside the onload handler.
If you want to load the images one at a time and only load the next one if the previous one doesn't meet your criteria, then you will need a totally different structure to the code. You will not be able to use $.each() the way you are. Instead, you will have to start loading of the next image from within the onload handler of the previous one (thus serializing the asynchronous image loads).

Related

Checking if the image is loaded within specific timespan

I'm trying to load image with JS and give it a certain time to load. For example 1 second. If the image wasn't loaded within 1 second - use default image. Here's what I have so far:
function displayUserImage() {
setTimeout(function(){
var imageMe = new Image();
imageMe.onload = function(){
$('#user-img-me').css('background-image', 'url(' + imageMe.src + ')');
};
imageMe.onerror = function() {
imageMe.src = "images/defaultImage.png";
}
if(!isEmpty(myObject.getPic()) && !isBlank(myObject.getPic())) {
imageMe.src = myObject.getPic();
}
else {
imageMe.src = "images/defaultImage.png";
}
}, 0);
}
I'm setting timeOut of 0 only to make the image loading asynchronous and not to interfere with execution of rest of the code. myObject.getPic() returns a string with image path. The image may be located on a remote domain/server. The connection might be slow, the image might be heavy, the server may not respond... So I want to give this image only a second to load, and if it didn't succeed - use default image. In both cases I need to set external variable imageMeLoaded to true once either image is loaded. Can it be done?

How to monitor an image source for fully loaded status

I am loading a large number of images into a dynamic DIV and I am using a preloader to get the images.
imageObj = new Image();
imageObj.src = imgpath + imgname;
Each of these events creates a GET that I can see and monitor in Firebug.
If I know the name and path of an image, can I watch the relevant XMLHttpRequest to see if the GET has completed?
I do not want to rely on (or use) .onload events for this process.
The pseudo would look something like this...
if (imageObj.GET = 'complete')
Has anyone had any experience of this?
EDIT 1
Thanks to the help from Bart (see below) I have changed my image preloader to store an array of the image objects...
function imagePreLoader(imgname) {
images[imgnum] = new Image();
images[imgnum].src = imgpath + imgname;// load the image
imgnum ++;
}
And then, after all my other functions have run to build the content DIVs, I used the image.complete attribute in the following...
var interval = setInterval(function () {
imgcount = imgnum - 1; // because the imgnum counter ++ after src is called.
ok = 1;
for (i=0; i<imgcount; i++) {
if (images[i].complete == false){
ok = 0;
}
}
if (ok == 1) {
clearInterval(interval);
showIndexOnLoad();
}
}, 1000);
This waits until all the images are complete and only triggers the showIndexOnLoad() function when I get the 'ok' from the interval function.
All images now appear as I wanted, all at once with no additional waits for the GETs to catch up.
Well done Bart for putting me on to the image.complete attribute.
You can watch the complete property of the image to see if the image is fully loaded or not.
Here's an example.
http://jsfiddle.net/t3esV/1/
function load (source) {
var img = new Image();
img.src = source;
console.log('Loading ' + source);
var interval = setInterval(function () {
if (img.complete) {
clearInterval(interval);
complete(img);
}
}, 400);
};
function complete(img) {
console.log('Loaded', img.src);
document.body.appendChild(img);
};
Note: This example fails to clear the interval when something goes wrong and complete is never set to true.
Update
I wrote a simple jQuery.preload plugin to take advantage of the image.complete property.
This is a very interesting problem, and I am afraid there is no actual solution to this. The load event for images is when the image is being rendered and the browser knows the width and height of it.
What you would be after would be a tag-applicable readystatechange event. Alas, only IE allows you to bind those to non-document elements, so this is not an option.
There are a bunch of plug-ins that allow you to go around it, as well. One pretty hot one is https://github.com/desandro/imagesloaded , which has the added advantage of dealing with all the browser differences very efficiently. It, however, still relies on the load event (and I am pretty sure this is the only way to start doing what you want to do).

Why is my image gallery lagging when the image changes?

on my live website that I created
there's a big problem I'm having. On the page linked to, which is also the home page of the site, there is an image gallery that performs the following functions:
1) I have a directory in my html file structure called public_html/images/lightbox where all of the images that will be displayed are stored. A php script (dynamically) takes the contents of that directory using the scandir function, and then takes that PHP array returned by this function, implodes it into a PHP string, assigns that PHP string to a javascript string, and then splits that javascript string to a javascript array (which stores the filepaths of the images stored in the public_html/images/lightbox directory.
2) There are two javascript functions called prev() and next(). next() is called automatically every 4.5 seconds, incrementing an indexing variable that moves through the array of images. This goes on in the background regardless of user interaction with the webpage; there is a counter that makes next() execute every 4500 ms using the method setTimeout.
3) The user can trigger the execution of prev() and next() by pressing two buttons, which are absolutely positioned relative to the div that contains the image gallery. Upon the pressing of either button, corresponding to either next() or prev() being called, either function is immediately executed, whereupon the timer for the next execution of next() will restart from 4500 ms.
It all works out fine, but when I first open the site with a web browser, the images lag upon changing. After the images have all been cycled through, they do not lag anymore (is this because they have been cached in the browser), but the first time it is viewed on a web browser, the lagging as the image URL/image is changed spoils the user experience and makes the website come across as poorly designed.
Here's the code: Many thanks.
<?php
$path = "images/lightbox/";
$gallery = scandir($path);
array_shift($gallery); array_shift($gallery);
foreach($gallery as &$image) {
$image = $path . $image;
}
$gallery_string = implode(" ", $gallery);
?>
<script>
$(function() {
$("#prev").on("click", $.prev);
$("#next").on("click", $.next);
});
</script>
<script>
var gallery= new Array();
var gallery_string = "<?php echo $gallery_string; ?>";
gallery = gallery_string.split(" ");
var ImageCnt = 0;
$.prev = function(event) {
if (ImageCnt == 0) { ImageCnt = gallery.length - 1; }
else { ImageCnt -= 1; }
$("#lightbox").css("background", "url(" + gallery[ImageCnt] + ")").css("background-size","670px");
clearTimeout(t);
t = setTimeout($.next, 4500);
event.stopPropagation();
}
$.next = function(event){
if(ImageCnt < gallery.length-1) { ImageCnt++; }
else { ImageCnt = 0; }
$("#lightbox").css("background", "url(" + gallery[ImageCnt] + ")").css("background-size","670px");
if(event != undefined) {
clearTimeout(t);
event.stopPropagation();
}
t = setTimeout($.next, 4500);
}
var t = setTimeout($.next, 4500);
</script>
The lag has nothing to do with the script, it's however mainly due to these reasons
There're many resources being loaded on your site (images, sound).
The background music you have on is ~4.5 MB in size and that seems to be the main cause
This also depends on your hosting platform and speed
I recommend getting rid of the music, as besides causing the lag, it would in my opinion, affect the experience of your site visitor's. Also try using less graphics, use GIF/PNG when possible rather than JPEG, however, if you must use JPEG try compressing them.

Wait to execute code until after AJAX called image renders

I am trying to run some code that grabs the width and height of a div after it is loaded and filled with an image from an AJAX call.
The div is 0x0 until the image is placed so checking the dimensions before pretty much breaks everything.
I have tried .load() (Doesn't work because this is an AJAX call). I also tried the imagesLoaded js plugin. Here is what I have right now:
alert('outside;')
function startBubbles(){
alert('inside');
var space = new DisplaySpace($('#bubbleWrap').height(), $('#bubbleWrap').width());
var count = 1;
alert(space.getHeight());
var delay = (function(){
var timer = 0;
return function(afterResize, ms){
clearTimeout (timer);
timer = setTimeout(afterResize, ms);
};
})();
var spawnInterval = self.setInterval(function(){
var aBubble = new Bubble(count, space);
count++
aBubble.spawnimate(aBubble);
setTimeout(function() {aBubble.popBubble(aBubble)},Math.floor((Math.random()*30000)+10000));
}, 500);
});
My alerts all fire before the image is visible, then my 'space' object still has height and width of 0.
bubbleWrap is a div inside the loading zone that contains the image in question. I realize I could probably but a manual delay in here to solve the problem MOST of the time - however that doesn't seem optimal. What am I missing?
I'm now implementing the load of this particular state like this:
History.Adapter.bind(window,'popstate',function(){
var state = History.getState();
state = 'target='+state.data.state;
$.get('contents.php', state, function(data){
if(state == 'target=bubbles'){
$('#loading_zone').html(data).waitForImages(startBubbles());
}
else{
$('#loading_zone').html(data);
}
});
});
Unfortunately, on page reload, the height ends up as only 10. Everything seems great when I just navigate away and come back, though. Any thoughts?
I have a plugin that could do this nicely.
Simply call it after you inject the new HTML.
// Assume this function is the callback to the *success*.
function(html) {
$("#target").html(html).waitForImages(function() {
// All descendent images have now loaded, and the
// containing div will have the correct dimensions.
});
};

Loading message

Searching for a js script, which will show some message (something like "Loading, please wait") until the page loads all images.
Important - it mustn't use any js framework (jquery, mootools, etc), must be an ordinary js script.
Message must disappear when the page is loaded.
Yeah an old-school question!
This goes back to those days when we used to preload images...
Anyway, here's some code. The magic is the "complete" property on the document.images collection (Image objects).
// setup a timer, adjust the 200 to some other milliseconds if desired
var _timer = setInterval("imgloaded()",200);
function imgloaded() {
// assume they're all loaded
var loaded = true;
// test all images for "complete" property
for(var i = 0, len = document.images.length; i < len; i++) {
if(!document.images[i].complete) { loaded = false; break; }
}
// if loaded is still true, change the HTML
if(loaded) {
document.getElementById("msg").innerHTML = "Done.";
// clear the timer
clearInterval(_timer);
}
};
Of course, this assumes you have some DIV thrown in somewhere:
<div id="msg">Loading...</div>
Just add a static <div> to the page, informing user that the page is loading. Then add window.onload handler and remove the div.
BTW, what’s the reason of this? Don’t users already have page load indicators in their browsers?
You should do async ajax requests for the images and add a call back when it's finished.
Here's some code to illustrate it:
var R = new XMLHttpRequest();
R.onreadystatechange = function() {
if (R.readyState == 4) {
// Do something with R.responseXML/Text ...
stopWaiting();
}
};
Theoretically you could have an onload event on every image object that runs a function that checks if all images is loaded. This way you don´t need a setTimeOut(). This would however fail if an image didn´t load so you would have to take onerror into account also.

Categories

Resources