0

I'm building a card game with HTML5 canvas, and have run into a problem with drawImage inside a loop. It appears to be an issue with closures, but I'm unsure how closures would apply to my situation.

for (var i = 0; i < length; i++) {  
    var x = start + i * cardWidth
    var y = start
    $(anObject.image).load(function() {
        context.drawImage(anObject.image, x, y);
    });
}

The output from this function is only writing the last image object to the canvas, despite being used in a loop with 30+ iterations. How would I apply a closure to this function and write all of my images?

EDIT

Sorry folks, I should have posted more details about x and y being updated. I've updated the code accordingly. I know the x and y values are being updated properly because I'm also outputting them to a debug DIV beside the canvas.

MechEngineer
  • 1,399
  • 3
  • 16
  • 27
  • it looks like the loop doesnt use i for anything, could you post more code please? – Ryan Jun 15 '12 at 18:57
  • Possible duplicate of http://stackoverflow.com/questions/8741023/javascript-loop-scope-issue-with-image-onload which is itself a possible duplicate of the classic loop-closure question http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – apsillers Jun 15 '12 at 19:14

2 Answers2

0

You need to change x and y where u are drawing canvas every time pls find the below pseudo code for above situation

 charcterIndentifier = {
                 C1: { X: 0, Y: 0, ImgId: "00", adjacentId: ["c2", "c9", "c10"],color:"B" },
                 C2: { X: 1, Y: 0, ImgId: "10", adjacentId: ["c1", "c9", "c10", "c11", "c3"], color: "B" },
                 C3: { X: 2, Y: 0, ImgId: "20", adjacentId: ["c2", "c4", "c10", "c11", "c12"], color: "B" },
                 C4: { X: 3, Y: 0, ImgId: "30", adjacentId: ["c3", "c5", "c13", "c11", "c12"], color: "B" },
                 C5: { X: 4, Y: 0, ImgId: "40", adjacentId: ["c4", "c6", "c13", "c14", "c12"], color: "B" },
                 C6: { X: 5, Y: 0, ImgId: "50", adjacentId: ["c5", "c7", "c13", "c14", "c15"], color: "B" },
                 C7: { X: 6, Y: 0, ImgId: "60", adjacentId: ["c6", "c8", "c16", "c14", "c15"], color: "B" },
                 C8: { X: 7, Y: 0, ImgId: "70", adjacentId: ["c7", "c16", "c15"], color: "B" },
                 C9: { X: 0, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C10: { X: 1, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C11: { X: 2, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C12: { X: 3, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C13: { X: 4, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C14: { X: 5, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C15: { X: 6, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C16: { X: 7, Y: 1, ImgId: "11", adjacentId: "BlackSoldier", color: "B" },
                 C17: { X: 0, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C18: { X: 1, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C19: { X: 2, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C20: { X: 3, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C21: { X: 4, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C22: { X: 5, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C23: { X: 6, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C24: { X: 7, Y: 6, ImgId: "66", adjacentId: "WhiteSoldier", color: "W" },
                 C25: { X: 0, Y: 7, ImgId: "07", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C26: { X: 1, Y: 7, ImgId: "17", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C27: { X: 2, Y: 7, ImgId: "27", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C28: { X: 3, Y: 7, ImgId: "37", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C29: { X: 4, Y: 7, ImgId: "47", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C30: { X: 5, Y: 7, ImgId: "57", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C31: { X: 6, Y: 7, ImgId: "67", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 C32: { X: 7, Y: 7, ImgId: "77", adjacentId: ["c2", "c9", "c10"], color: "W" },
                 id: "one"
             };

 var canvas = document.getElementById(canvasId);
            var ctx = canvas.getContext('2d');
            var width = canvas.offsetWidth;
            var height = canvas.offsetHeight;
            var xwidth = width / 8;
            var yheight = height / 8;
            var xposition, yposition;
 for (var key in charcterIndentifier) {
                if (key.toString() != "id") {
                    xposition = charcterIndentifier[key].X * xwidth;
                    yposition = charcterIndentifier[key].Y * yheight;
                    ctx.save();
                    ctx.translate(xposition, yposition);
                    ctx.drawImage(document.getElementById(charcterIndentifier[key].ImgId), 14, 5);
                    ctx.restore();
                }
            }
Ajay Beniwal
  • 18,857
  • 9
  • 81
  • 99
0

Var <- is function scope in JS.

The x and y used in your closure function would be the last value they received.

To overcome that, you need a function that returns a function.

for (var i = 0; i < length; i++) {  
    var x = start + i * cardWidth
    var y = start
    $(anObject.image).load((function(a, b) {
        return function() {
            context.drawImage(anObject.image, a, b);
        };
    })(x, y));
}
Viele
  • 2,244
  • 2
  • 19
  • 31