Reputation: 608
I've been trying to create a small HTML5-based example, but I've ran into some problems. I want to render a rock on a <canvas>
but this Javascript object won't work properly.
function ImageData() {
this.image_names = ["rock1"];
this.images = new Array();
this.loadResources = function () {
for (var i = 0; i < this.image_names.length; i++) {
var img = new Image();
img.onload = (function (a) {
a.images[a.image_names[i]] = img;
console.log(a.images); //log is successful, image is in array
})(this);
img.src = "images/" + this.image_names[i] + ".png";
}
}
}
It's use is to be as follows:
var a = new ImageData();
a.loadResources();
var rock1_image = a.images["rock1"]; //the "rock1.png" image
If you try accessing the object via console, you'll see that there is no image in the image array, after being certain the image loaded. I can't figure out why it's not working. I've looked over it multiple times.
EDIT: Here is my final, working result:
function ImageData() {
this.image_names = ["rock1"];
this.images = new Array();
this.loadResources = function (callback) {
for (var i = 0; i < this.image_names.length; i++) {
var img = new Image();
img.onload = (function (a, i) {
return function() {
a.images[a.image_names[i]] = img;
if (i == (a.image_names.length - 1)) callback();
};
})(this, i);
img.src = "images/" + this.image_names[i] + ".png";
}
}
}
Upvotes: 1
Views: 171
Reputation: 18462
I would venture to say that you are attempting to access it before it is added to your array. I would suggest adding a callback or something to your loadResources
method to make sure that it's there before you attempt to access it.
this.loadResources = function (callback) {
for (var i = 0; i < this.image_names.length; i++) {
var img = new Image();
img.onload = (function (a, i) {
return function() {
a.images[a.image_names[i]] = img;
console.log(a.images); //log is successful, image is in array
callback();
};
})(this, i);
img.src = "images/" + this.image_names[i] + ".png";
}
}
then
var a = new ImageData();
var rock1_image;
a.loadResources(function() {
rock1_image = a.images["rock1"];
// do whatever you need to do with the image in here.
});
Also, what @Igor mentions. I totally missed that. I adjusted the code above so you could keep your this
scope without having to set it elsewhere.
Updated to take care of the i
issue brought up by @RobD.
Upvotes: 2
Reputation: 147343
In the code:
> function ImageData() {
> this.image_names = ["rock1"];
> this.images = new Array();
> this.loadResources = function () {
> for (var i = 0; i < this.image_names.length; i++) {
> var img = new Image();
> img.onload = (function (a) {
This function will be run immediately and does not return a value, so undefined will be assigned. So no point in the assignment, just run the code.
> a.images[a.image_names[i]] = img;
Images is an array that is used as a plain object. Better to use a plain object then.
> console.log(a.images); //log is successful, image is in array
> })(this);
The outer this must be passed in because of the IIFE. Remove the IIFE and there is no requirement to pass this. And if a reference to the instance is stored in the function, it won't matter how the function is called (i.e. you won't have to set this in the call).
> img.src = "images/" + this.image_names[i] + ".png";
> }
> }
> }
You might want something like:
function ImageData() {
this.image_names = ['rock1'];
this.images = {};
imageData = this;
this.loadResources = function (callback) {
for (var i = 0; i < imageData.image_names.length; i++) {
var img = new Image();
imageData.images[a.image_names[i]] = img;
img.src = 'images/' + this.image_names[i] + '.png';
if (callback) {
img.onload = callback;
}
}
}
}
var a = new ImageData();
a.loadResources(function(){console.log('loaded: ' + this.src);}); // loaded: …
window.onload = function() {
document.body.appendChild(a.images.rock1); // image appears in document
}
Upvotes: 1
Reputation: 515
I haven't tested your code yet, but I guess this is the problem: You are trying to access your image before it was loaded. You can use callback event handler after it was load like:
var data = new ImageData();
data.loadResources(function(imgObj){
// imgObj is the newly load image here. Have fun with it now!
})
Upvotes: 0
Reputation: 15893
Remove (this)
after onload
handler definition. You are actually calling this function right away, assigning undefined
(since it returns nothing) as img.onload
value.
Upvotes: 2