4

I'm trying to loop through an object with JavaScript and add all the subobjects from that object to a HTML5 canvas.

The canvas-bit is working, no problem with that, but for some reason all my images end up being the same size - the size of the last subobject 'background'. I'm assuming that it has to do with the scope of my loop and 'this', but I can't really see what to change;

var stage;
var items = {
    head: {image: null, path: "images/avatar-elements/head01.png", w:200, h:200},
    hair: {image: null, path: "images/avatar-elements/hair01.png", w:200, h:200},
    nose: {image: null, path: "images/avatar-elements/nose01.png", w:200, h:200},
    eyes: {image: null, path: "images/avatar-elements/eyes01.png", w:200, h:200},
    eyebrows: {image: null, path: "images/avatar-elements/eyebrows01.png", w:200, h:200},
    ears: {image: null, path: "images/avatar-elements/ears01.png", w:200, h:200},
    background: {image: null, path: "images/avatar-elements/background01.png", w:500, h:370}
};

function initCanvas() {
    stage = new Kinetic.Stage("canvas", 500, 370);
    makeBasis();
}


function makeBasis() {
    for(i in items) {
        var img = new Image();
        img.onload = function() {
            items[i].image = makeCanvasImage(this, items[i].w, items[i].h);
        }
        img.src = items[i].path;
    }


}

function makeCanvasImage(tar, w, h) {
    var theImage = new Kinetic.Image({
        imageObj: tar,
        x: 250 - (w / 2),
        y: 185 - (h / 2),
        width: w,
        height: h
    });
    stage.add(theImage);
    return theImage;
}

initCanvas();
Rein
  • 1,347
  • 3
  • 17
  • 26
  • 1
    possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Felix Kling Jan 05 '12 at 10:37

1 Answers1

11

Bug is in makeBasis(). After looping on all images i is set to last - classic closure problem. Try to use this:

function makeBasis() {
    for(i in items) {
        var img = new Image();
        img.onload = (function (nr) {
            return function() {
                items[nr].image = makeCanvasImage(this, items[nr].w, items[nr].h);
            }
        }(i));      
        img.src = items[i].path;
    }
}
Mateusz W
  • 1,981
  • 1
  • 14
  • 16
  • Beautiful, that fixed it. Can you tell me what the 'return function' does? Is it being executed after the image is loaded? And what will happen if images don't finish loading in the same order as they were being loaded, won't the wrong images be added to the subobjects in `items`? – Rein Jan 05 '12 at 10:54
  • @Reinoud: `return function(){...}` returns the function defined by `function(){...}`. This is immediately executed because the outer function is executed immediately `(function(){...}())` (note the brackets at the end). – Felix Kling Jan 05 '12 at 10:59
  • Thanks, bookmarked for later reading. I'll see how far I get, never had these problems in AS3 ;) – Rein Jan 05 '12 at 11:58