Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass parameters into image load event?

Tags:

javascript

When I set the src of an image object, it will trigger an onload function. How can I add parameters to it?

x = 1;
y = 2;
imageObj = new Image();
imageObj.src = ".....";
imageObj.onload = function() {
    context.drawImage(imageObj, x, y);
};
x = 3;
y = 4;

In here, I want to use the x and y values that were set at the time I set the src of the image (i.e. 1 and 2). In the code above, by the time the onload function would finish, x and y could be 3 and 4.

Is there a way I can pass values into the onload function, or will it automatically use 1, and 2?

Thanks

like image 959
omega Avatar asked Jul 10 '13 18:07

omega


2 Answers

All the other answers are some version of "make a closure". OK, that works. I think closures are cool, and languages that support them are cool...

However: there is a much cleaner way to do this, IMO. Simply use the image object to store what you need, and access it in the load handler via "this":

imageObj = new Image();
imageObj.x = 1;
imageObj.y = 2;
imageObj.onload = function() {
    context.drawImage(this, this.x, this.y);
};
imageObj.src = ".....";

This is a very general technique, and I use it all the time in many objects in the DOM. (I especially use it when I have, say, four buttons and I want them to all share an "onclick" handler; I have the handler pull a bit of custom data out of the button to do THAT button's particular action.)

One warning: you have to be careful not to use a property of the object that the object class itself has a special meaning or use. (For example: you can't use imageObj.src for any old custom use; you have to leave it for the source URL.) But, in the general case, how are you to know how a given object uses all its properties? Strictly speaking, you can't. So to make this approach as safe as possible:

  • Wrap up all your custom data in a single object
  • Assign that object to a property that is unusual/unlikely to be used by the object itself.

In that regard, using "x" and "y" are a little risky as some Javascript implementation in some browser may use those properties when dealing with the Image object. But this is probably safe:

imageObj = new Image();
imageObj.myCustomData = {x: 1, y: 2};
imageObj.onload = function() {
    context.drawImage(this, this.myCustomData.x, this.myCustomData.y);
};
imageObj.src = ".....";

Another advantage to this approach: it can save a lot of memory if you are creating a lot of a given object -- because you can now share a single instance of the onload handler. Consider this, using closures:

// closure based solution -- creates 1000 anonymous functions for "onload"
for (var i=0; i<1000; i++) {
   var imageObj = new Image();
   var x = i*20;
   var y = i*10;
   imageObj.onload = function() {
       context.drawImage(imageObj, x, y);
   };
   imageObj.src = ".....";
}

Compare to shared-onload function, with your custom data tucked away in the Image object:

// custom data in the object -- creates A SINGLE "onload" function
function myImageOnload () {
   context.drawImage(this, this.myCustomData.x, this.myCustomData.y);
}
for (var i=0; i<1000; i++) {
   imageObj = new Image();
   imageObj.myCustomData = {x: i*20, y: i*10};
   imageObj.onload = myImageOnload;
   imageObj.src = ".....";
}

Much memory saved and may run a skosh faster since you aren't creating all those anonymous functions. (In this example, the onload function is a one-liner.... but I've had 100-line onload functions, and a 1000 of them would surely be considered spending a lot of memory for no good reason.)

UPDATE: See use of 'data-*' attribute for a standard (and "standards approved") way to do this, in lieu of my ad-hoc suggestion to use myCustomData.

like image 156
Dan H Avatar answered Nov 12 '22 11:11

Dan H


Make a private scope closure that will store x & y values:

imageObj.onload = (function(x,y){
        return function() {
            context.drawImage(imageObj, x, y);
    };
})(x,y);
like image 12
gdoron is supporting Monica Avatar answered Nov 12 '22 10:11

gdoron is supporting Monica