Loading images in js for loop loads nonsequentially - javascript

Currently I have 3 or 4 galleries loaded on one page. It's a photographers site, so each gallery has about 40 images. I originally pre-loaded the images, where I would just load the first two images so the page loads quickly, then use JS in the background to cycle through a loop and load the rest. It worked well, except that it didn't honor the order, and the order is important. I have seen some examples where you hide the images until they load, but since there are about 120 large images being loaded in the page it causes the page to load slowly. Is there a way I can use my code, and sort the images once they're loaded? Or, should I load them through an array, would it still ignore the load order? Here's my jsfiddle: http://jsfiddle.net/drrobotnik/YKPEu/
The piece of js i am looking at mostly is this part:
var stack = [];
for (var i = 3; i <= 59; i++) {
var img = new Image(782,521);
img.src = 'http://anikalondon.com/Images/weddings/weddings-3-' + i + '.jpg';
$(img).bind('load', function() {
stack.push(this);
var len = stack.length+2;
$(".numbers").text(($(".enggal img:visible").index()+1)+"/"+len);
if(i>=58){$(".numbers").css("visibility", "visible");}
});
}
again, in this example it's loading the images out of order (probably whichever ones load first, not sure).

well idk if it helps but here's a sorting algorithm that you could use to order them before inserting them into the DOM
stack.sort(function(a,b){
return a.src.substring(a.src.lastIndexOf("-")+1,a.src.lastIndexOf(".")) - b.src.substring(b.src.lastIndexOf("-")+1,b.src.lastIndexOf("."))
})

What if you replaced you simplify things and use this for loop
for (var i = 3; i <= 59; i++)
{
$(".enggal").append("<img src='http://anikalondon.com/Images/weddings/weddings-3-" + i + ".jpg' />");
}
This inserts all of your images in order. You may want to add in the width/height attributes.

Without knowing the deal with how stack is used, I'm not totally sure this would work, but why don't you just save the index information to a store right away, rather than on the callback when it's done loading?
And you should also set src after you bind load or it might miss.
[totally revised from original answer]
var img,i,stack = [];
var imageLoaded=function(e) {
var len = stack.length+2,
index = parseInt(this.src.split('-')[2])-3
$(".numbers").text(($(".enggal img:visible").index()+1)+"/"+len);
if(index>=58){$(".numbers").css("visibility", "visible");}
}
for (i = 3; i <= 59; i++) {
img = new Image(782,521);
$(img).bind('load', imageLoaded);
stack.push(img);
}
// Just to make sure that the first image doesn't finish loading before the loop isdone
// throwing off the count in the imageLoaded function
for (i = 3; i <= 59; i++) {
stack[i-3].src = 'http://anikalondon.com/Images/weddings/weddings-3-' + i + '.jpg';
}

Related

Restart a for loop after the end of an array

I working in JavaScript and am trying to add some images to a site.
I have a list of blog posts on a page. And I have a bunch of small stand-alone images (think small icon images) that I want to place on either side of the blog post feed. They are kind of just like random background images. As the feed gets longer, more images will automatically be placed.
Here is some example code of what I have so far. Right now I am just appending text to the page to get this working.
I need help figuring out how to restart this loop once the end of the array is reached. For example, after 6url.jpg is printed, I want to print 1url.jpg and so on if my imageCount is more than 6. I played around with continue and while loops but not sure how to implement that.
var blogIcons = ["1url.jpg", "2url.jpg", "3url.jpg", "4url.jpg", "5url.jpg", "6url.jpg"];
var blogFeedHeight = $(".blog-feed").height();
var imageDistance = 400;
// Determining how many images to place based on the blog feed height;
var imageCount = Math.ceil(blogFeedHeight/imageDistance);
// the number of images that should be inserted.
for(var i = 0; i < imageCount; i++){
$('blog-feed').append('<div class="blog-icon">' + blogIcons[i] +'</div>')
}
What you are looking for is called modulo, the rest of the euclidian division of 2 numbers.
var blogIcons = ["1url.jpg", "2url.jpg", "3url.jpg", "4url.jpg", "5url.jpg", "6url.jpg"];
var imageCount = 10;
// the number of images that should be inserted.
for (var i = 0; i < imageCount; i++) {
console.log(blogIcons[i % blogIcons.length])
}
I simplified your problem so it can run on StackOverflow. but you'll get the proper index by using "%"
So your script should look like that:
var blogIcons = ["1url.jpg", "2url.jpg", "3url.jpg", "4url.jpg", "5url.jpg", "6url.jpg"];
var blogFeedHeight = $(".blog-feed").height();
var imageDistance = 400;
// Determining how many images to place based on the blog feed height;
var imageCount = Math.ceil(blogFeedHeight/imageDistance);
// the number of images that should be inserted.
for(var i = 0; i < imageCount; i++){
$('blog-feed').append('<div class="blog-icon">' + blogIcons[i % blogIcons.length] +'</div>')
}
You don't need to restart a loop. Instead you can use modulo division to fetch an item within bounds from the array
var blogIcons = ["1url.jpg", "2url.jpg", "3url.jpg", "4url.jpg", "5url.jpg", "6url.jpg"];
for (var i = 0; i < 14; i++) {
console.log(blogIcons[i % blogIcons.length]);
}
When doing i % blogIcons.length you will get a number between 0 and blogIcons.length

Appending Different Random Number To URL In Javascript Array On Each Loop

I'm trying (without much success) to create an array which contains slides being loaded into an iframe. One of these frames (/Events.php) uses PHP to query a WordPress database and show 1 post chosen at random. This slide needs to show a different random post every time the array loops through.
My code at them moment is...
<script type="text/javascript">
var frames = Array(
'http://www.example.com/Slide01.php', 5,
'http://www.example.com/Slide02.php', 5,
getRandomUrl(), 5,
'http://www.example.com/Slide04.php', 5
);
var i = 0, len = frames.length;
function getRandomUrl()
{
return "http://www.example.com/Events.php?=" + (new Date().getTime());
}
function ChangeSrc()
{
if (i >= len) { i = 0; } // start over
document.getElementById('myiframe').src = frames[i++];
setTimeout('ChangeSrc()', (frames[i++]*1000));
}
window.onload = ChangeSrc;
</script>
The only trouble is everytime /Events.php is shown it has the same number appended to it so therefore shows the same post in each loop.
I need to append a different number to the /Events.php slide on each loop so it generates different content each time.
I'm starting to think I'm approaching this in totally the wrong way so any help or pointers in the right direction would be appreciated!
Cheers,
Mark.
The issue is you are only calling getRandomUrl() once which is when you defined your array, this means the value will always be the same as its only returned once.
One solution would be to store the function itself in your array like so:
var frames = Array(
'http://www.example.com/Slide01.php', 5,
'http://www.example.com/Slide02.php', 5,
getRandomUrl, 5,
'http://www.example.com/Slide04.php', 5
);
And then call it in ChangeSrc() if its a function
function ChangeSrc()
{
if (i >= len) { i = 0; } // start over
var frame = frames[i++],
isFnc = typeof(frame) == "function";
if(isFnc){
frame = frame();
}
document.getElementById('myiframe').src = frame;
setTimeout(function(){
ChangeSrc()
}, frames[i++]*1000);
}
http://jsfiddle.net/redgg6pq/
A tip would be that you are only calling 'getRandomUrl' once, hence why it's always the same image. You want to call it each time you are in the loop.
I would suggest removing it from the static array, and calling it in the loop - does that make sense? :)
HTH

Fast way to append large list to dom

I am trying to populate an empty list using an array of photo names. I have made this work already, but with a large amount of photos it can become relatively slow. More than 500 photos is not unusual.
I am wondering if someone could find a way to make this code work faster, or tell me what make this code run slow so I can have another look at it myself.
The code I have is as follows. this.photoListElement is a jQuery object referring to the unordered list element. photoNames is an array of photo name strings. Variables are declared at the top of the function which is not shown here. isThumbDownloaded checks a variable in an object. getThumb and getThumbId are functions which add some strings together.
(...)
place = [];
for(i=0; i< photoNames.length; ++i) {
photoName = photoNames[i];
if(coverages.isThumbDownloaded(coverageId, photoName)){ // A function which checks if a photo is downloaded. If it is, the photo should not be hidden, and the right background should be applied.
bg = 'background-image:url(\''+coverages.getThumb(coverageId, photoName) + '?' + new Date().getTime()+'\');';
cls = '';
} else {
bg = '';
cls = 'hidden';
}
place[i] = '<div id="'+ this.getThumbId(photoName) +'" photoName="'+photoName+'" style="'+bg+'" class="phoPhoto '+cls+'" onclick="$.mobile.changePage($(\'#carousel\'), {transition: \'slidefade\'})"></div>';
}
this.photoListElement.html(place.join(''));
(...)
Help is very much appreciated.
After research
The problem is not the loop, although some minor optimizations can be done, but the the dom insertion.
In the loop you are counting the number of photoNames on each iteration:
for(i=0; i< photoNames.length; ++i)
Keep the length in a variable instead and the loop will be faster:
for (var i = 0, ilen = photoNames.length; i < ilen; i += 1)
Also, string concatenation might be faster than array join, check this jsperf .
So:
place = "";
...
place += '<div>.......';
..
this.photoListElement.html(place);
Try using
$('ul').append(ilen);

javascript - download several files

I'm new in javascript and i need to maintain a site.
The actual fonctionnality is to download several card into a file, one card per tab. As users can have plenty of cards, treatment can not always succeed (too many tabs), i wanted create a file evey 20 tabs for instance.
var printTerm = function(grid){
var rows = grid.selected;
if(rows==null) return;
var ids = rows.map(function(val){return grid.getDataByRow(val).num_terme;});
var nbMax = 20;
var nbFic;
var idsPartiel;
var posDebut;
var posFin;
var a;
if(ids.length > nbMax)
{
idsPartiel = ids;
if(ids.length % nbMax == 0) nbFic = ids.length / nbMax;
else nbFic = ((ids.length - (ids.length % nbMax)) / nbMax) + 1;
for (i=0 ; i< nbFic ; i++)
{
posDebut = (nbMax * i);
if(i == nbFic - 1) posFin = idsPartiel.length + 1;
else posFin = posDebut + nbMax;
ids = idsPartiel.slice(posDebut,posFin);
a = new Element('a', 'id':'download','href':'php/utils/export2pdf.php?ids='+ids.join(',')})
.addEvent('click',function(){location.href=this.href;}).inject(document.body);
a.fireEvent('click');
a.dispose();
}
}
else
{
a = new Element('a',{'id':'download','href':'php/utils/export2pdf.php?ids='+ids.join(',')})
.addEvent('click',function(){location.href=this.href;}).inject(document.body);
a.fireEvent('click');
a.dispose();
}
};
When the number of cards is less or equal to nbMax, it works well, bu when there must be several files, not: only the last passage of the loop is creating the file.
When i try to see what happens with firebug, i see my lines of treatment, but only the last is ended.
Thanks for helping me.
If I read your code correctly, you are trying to make the browser download a ton of files into separate tabs. Most browsers won't really appreciate you trying to launch a loop of downloads that way, nor would a user really want that many save as dialogs potentially popping off.
You would be way better off packaging them into a zip file server side and sending ONE file. It would be more efficient and way more user friendly.

Changing a class with z-index

I'm still in the process of learning JavaScript. and I would like to complete the task using only JavaScript and no Jquery.
I have multiple div/images that I’m trying to manipulate using the z-index, and a button that randomize the images to come to the front.
I got the random image array to work but as you could see in image[1]…setting each changeZ index will be laborious. So I’m embarking on changing the class’s (as seen in image[0] so I could add current to the new image and send current to the background on the next go around and then removing the class attribute. I have got the element to work separate but having trouble putting it together in a array.
function changeZIndex(i,id) {
document.getElementById(id).style.zIndex=i;};
function changeClassZIndex(i,tagName){
document.getElementsByTagName("*").style.zIndex=i;};
function getImage(){
var whichImage=Math.floor(Math.random()*3);
var image=new Array()
var currentPhoto = div.current
image[0]=function() {
changeZIndex(5,"scene1");
changeClassZIndex(-5,"current");
currentPhoto.removeClass('current')
document.getElementById("scene1").className += "current"; };
image[1]=function() {
changeZIndex(5,"scene2");
changeZIndex(-5,"scene1");
changeZIndex(-5,"scene3");
changeZIndex(-5,"scene");
};
image[2]=function() {
changeZIndex(5,"scene3");
changeZIndex(-5,"scene");
changeZIndex(-5,"scene2");
changeZIndex(-5,"scene1");
};
image[whichImage].apply(undefined);};
It's because document.getElementsByTagName() returns an array of elements, which you can't do operations like that on. Instead, you need to enumerate through them and do the operations individually.
Here's a working jsfiddle which shows exactly how to do it: jsfiddle
As a side note: if there's one thing a lot of web programming will teach you, its this:
Dont ever, ever, rule out jQuery as an option.
JQuery is your best friend, and the use of it in this situation would cut down your lines of code by well over half.
Firstly, I believe your problem is probably in changeClassZIndex(i,tagName)
which should probably look something like this:
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
function changeClassZIndex(z,className) {
var e = document.getElementsByClassName(className);
for(var i = 0; i < e.length; i++) {
e[i].style.zIndex = z;
}
};
I am defining the getElementsByClassName function if it does not exist because some browsers may not support it.
I may suggest taking a different approach to your problem however:
var images = new Array("scene1", "scene2", "scene3");
var currentPhoto = div.current
var whichImage = Math.floor(Math.random()*images.length);
// change all images to the background
for(var i = 0; i < images.length; i++)
{
changeZIndex(-5, images[i]);
}
// change the one you want to the top
changeZIndex(5, images[whichImage]);
That way you do not have to write functions for each image, and adding images is as easy as adding to the array.

Categories

Resources