0

I tried to create an array of Image to be displayed on a canvas, after each image is loaded. No errors, no draw...

    var x=...
var y=...
var canvas = document.getElementById(sCanvasName);
var context = canvas.getContext('2d');

var imageCardObj = [];

//vCards contains the images file names
for (var k=0;k<vCards.length;k++){
    imageCardObj[k] = new Image();

    var func = function(){
            var c = arguments[3];
            try{                
                c.drawImage(arguments[0], arguments[1], arguments[2]);
            }catch(e){
                alert(e.message)
            }
        }

        imageCardObj[k].onload = func(imageCardObj[k], x, y, context);

        imageCardObj[k].src = "res/img/"+vCards[k].trim()+".png";   

        x+=40;
    }
4
  • 1
    Are this code inside a window.onload-function? The document.getElementById() are probably not returning the canvas element. Commented Mar 7, 2014 at 9:50
  • No, the code is inside a function called by a link. The canvas is ok - I tried to draw a single img outside the loop and it worked Commented Mar 7, 2014 at 10:03
  • Okay. I see that you have created a function named func, but I don't see that you ever call it. Commented Mar 7, 2014 at 10:17
  • Here: imageCardObj[k].onload = func(imageCardObj[k], x, y, context); Commented Mar 7, 2014 at 10:37

2 Answers 2

1

You are calling the func() handler and gives the result to it to the image's onload handler. That won't work so well.. and you cannot pass arguments that way to a handler function.

Try this:

var func = function(){

    // "this" will be the current image in here

    var c = arguments[3];
    try{                
        c.drawImage(this, x, y); // you need to reference x and y
    }catch(e){
        alert(e.message)
    }
}

imageCardObj[k].onload = func;  // only a reference here

If you need different x and y's then you need to maintain those on the side, either in an additional array or use objects to embed the image, its intended x and y and use the url to identify the image in question inside the func() callback.

Also note that load order may vary as the last image loaded could finish before the first one so when you draw the image they may not appear in the same order.

You may want to do this instead:

var files = [url1, url2, url, ...],
    images = [],
    numOfFiles = files.length,
    count = numOfFiles;

// function to load all images in one go
function loadImages() {

    // go through array of file names
    for(var i = 0; i < numOfFiles; i++) {

        // create an image element
        var img = document.createElement('img');

        // use common loader as we need to count files
        img.onload = imageLoaded;
        //img.onerror = ... handle errors too ...
        //img.onabort = ... handle errors too ...

        img.src = files[i];

        // push image onto array in the same order as file names
        images.push(img);
    }
}
function imageLoaded(e) {

    // for each successful load we count down
    count--;
    if (count === 0) draw(); //start when all images are loaded
}

Then you can start the drawing after the images has loaded - the images are now in the same order as the original array:

function draw() {
    for(var i = 0, img; img = images[i++];)
        ctx.drawImage(img, x, y); // or get x and y from an array
}

Hope this helps!

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Ken, great solution and explanation! I don't care the load order of the images - they are very small and probably they will load in the same time. Just one question: X and Y inside the func() are global variables?
@Vincent no problem! X and y are global or at least in parent scope (just meant for example). They can come from an array or object instead (object with image, url etc. so you can use f.ex. the url to identify the image).
I had some problem with the increment of X and Y for each img, considering them as global vars. I solved by assigning X to the img obj : imageCardObj[k].xxx=x; and use xxx inside func context.drawImage(this, this.xxx, yStreet);
0

This is the final (working) version

var x=...
var y=...
var canvas = document.getElementById(sCanvasName);
var context = canvas.getContext('2d');
var imageCardObj = [];

    for (var k=0;k<vCards.length;k++){

        imageCardObj[k] = new Image();
         imageCardObj[k].xxx=x;

        var func = function(){              

            try{                
                context.drawImage(this, this.xxx, yStreet);                 
            }catch(e){
                alert(e.message)
            }
        }

        imageCardObj[k].onload = func;      
        imageCardObj[k].src = 'res/img/'+vCards[k].trim()+".png";   
        x +=40;         

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.