views:

98

answers:

2

This is driving me crazy.

I need to load an array of images in Javascript, but I want to make sure that all the images are loaded before starting drawing them. So, I busy-wait for every image onLoad event to be called. First I create images and set their source and onload function:

// Load images from names
for (i = 0; i < this.nImages; i++) {
    this.imagesArray[i] = new Image();
    this.imagesArray[i].onload = this.onLoad(i);
    this.imagesArray[i].src = images[i];
}

This is the onLoad function, member of the class I'm developing (the first two steps were in the constructor):

MyClass.prototype.onLoad = function (nimage) {
    console.log ("Image completed? ", nimage, " ", this.imagesArray[nimage].complete);
    this.imagesLoaded++;

}

Then I busy wait for all the onLoad functions to increment the counter (again, in the constructor):

while (this.imagesLoaded < this.nImages) {
    // This is busy wait, and I don't like it.
    continue;
}

So far, so good. But when I try to draw it on an HTMl5 canvas with my drawClass:

MyClass.prototype.refresh = function () {

    // Gets one of the images in the range    
    var imageNum = this.GetImageNum();

    // Test for completeness. This gives FALSE :(
    console.log ("completeness for image number ", imageNum, " is: ", this.imagesArray[imageNum].complete);

    this.drawClass.draw(this.imagesArray[imageNum], this.xOrigin, this.yOrigin);
}

the console.log line gives false and I get the infamous NS_ERROR_NOT_AVAILABLE exception.

Please not that the refresh() function is called after the onLoad() function, according to Firebug.

What am I missing here?

+2  A: 

You need to assign onload before setting the source, otherwise the loading may be completed before the script gets to set the handler. Maybe that already fixes it.

Re the busy waiting, that is indeed never a good thing. It's hard to suggest alternatives, as you are not showing why you need to wait in the first place. But what might be a good idea is extending the onload handler to detect whether the image array is complete, and if it is, to start the following action - that would make the busy waiting unnecessary.

Pekka
Siigh. I did it, and now the onLoad callback says "Image completed? true" for every image. But when I try to draw the image on an html5 canvas, the flag complete is again set to "false" and I get the infamous NS_ERROR_NOT_AVAILABLE exception.
janesconference
@jane does it work for a normal DOM element? Just shooting in the dark, I have zero experience with Canvas.
Pekka
I edited the first post, Canvas does not matter (actually another class takes care of graphics), the problem is that images seem incomplete when I try to draw them (before passing them to the drawing class).
janesconference
@jane are you sure this is not a numbering problem in `refresh()`? Can you confirm that `this.imagesArray[imageNum]` contains the desired `src`?
Pekka
If I log the src in the refresh() function, it's OK. But if I log src in the onLoad(), it is empty. Seems that onLoad() fires before I can set the src in the first snippet of code? WTF?
janesconference
@jane `this.onload(i)` doesn't work because you are calling it immediately. See here: http://stackoverflow.com/questions/3246928/in-javascript-does-it-make-a-difference-if-i-call-a-function-with-parentheses you'd need to put the call into quotes, although then I don't know how to deal with the `this`... Tricky.
Pekka
You are absolutely right. The problem is, I want to stop until all images are loaded (otherwise I cannot refresh the whole thing). But busy waiting kills firefox, at the point it *never* loads the last images (I have a lot).How can I wait until my classes load every image? Damn, I come from C, I'd just need a condition variable :)
janesconference
@jane yeah, JS is a bit tricky in that regard. Is it not an option to start rendering the canvas when all images have loaded? Having the onload handler check whether all images have loaded, and calling `refresh`?
Pekka
Well, no. I have multiple instances of MyClass and I'm trying to make the code as general as possible (it should become a library).But this is not the biggest problem: the handler's this now is the image object, and I can't set properties in the myClass instance that generated it. I guess I could pass myClass' "this" to the onLoad handler, but will I need a closure INYO?
janesconference
Pekka
Ok, I'll try to sort it out and if I'm stuck I'll repost the question. Thanks!
janesconference
(Just tried, the closure works :D:D:D )
janesconference
A: 

you can define onload in body tag