Why is this not working?
var img = new Image();
this.dimensions = [ ];
var m = this;
img.onload = function(){
return function(){
m.dimensions = [ this.width, this.height ];
}
};
img.src = 'images/whatever.jpg';
console.log(this.dimensions);
[]
(inside of a JS object, hence the "this")
EDIT: working code
var img = new Image();
this.dimensions = [ ];
var m = this;
img.onload = function(){
m.dimensions.push(this.width, this.height);
console.log(m.dimensions) // had to wait
};
img.src = 'whatever.jpg';
Are you sure console.log(this.dimensions) is being run AFTER the image has loaded? What you've added to img.onload is a callback function to run after the image has finished loading in DOM. Until that img has finished loading, m.dimensions will not be set yet. The image does not load immediately when you add the callback, but loads asynchronously and can finish whenever.
In other words, you are running console.log(this.dimensions) before the dimensions has been set yet (before the onload callback is run). I bet if you wrapped the console.log inside a setTimeout call with say 5 seconds, then it would log what you expected.
That's because this changes meaning inside new function definitions. You solve this by caching this in a local variable. Here, that's already done; your saving it in the variable m. So just use m instead of this.
var img = new Image();
this.dimensions = [ ];
var m = this;
img.onload = function(){
return function(){
m.dimensions = [ m.width, m.height ];
}
};
img.src = 'images/whatever.jpg';
Here's a good tutorial explaining how this changes meaning in different contexts: http://javascriptweblog.wordpress.com/2010/08/30/understanding-javascripts-this/
Consider that this code won't alert:
img.onload = function(){
return function(){
alert("hi")
}
};
Then consider the standard (likely desired) "double-closure":
img.onload = (function(m){
return function(){
alert(m)
}
})(this)
Happy coding.
Related
I am trying to return a value inside a function but the variable is only changed inside a function. outside the function the variable remains the same.
I have tried the following:
//variable file_exist still has the value true in it.
img.onerror = function () {
file_exist = false;
};
//returns function(){ reutnr false;};
file_exist = img.onerror = function () {
return false;
};
I cant seem to get the value outisde of this function. Is there a way to get the value false?
full code:
var i = 1;
var file_exist = true;
while(file_exist){
var img = document.createElement("img");
img.src = "ws-img/"+id+"-"+i+".jpg";
//deleted some code since no need here for the exampled
img.onerror = function () {
file_exist = false;
console.log(file_exist);//shows false
};
console.log(file_exist);//shows true
i++;
}
This is not my preferred method, but it will work in your specific scenario...
var imageCount = 0;
function loadImage(onComplete) {
imageCount++;
var img = document.createElement("img");
img.onerror = function () {
// there was an error, so we're assuming there are no more images
onComplete();
};
img.onload = function() {
// the image has loaded - add it to the DOM?
// call this function again to load the next image
loadImage(onComplete);
};
img.src = "ws-img/" + id + "-" + imageCount +".jpg";
// cached images won't trigger onload
if (img.complete) img.onload();
}}
loadImage(function() {
alert("images have all loaded");
});
It creates the image element, as you were doing, for image #1, then on success it will increment the counter and run itself again. That will try and load image #2, and so on and so on. When it errors it stops and executes the callback function so you know all the images are loaded.
There are issues with this though. If an image doesn't load for any reason, it will stop and load no more images. A much better solution would be to either construct the page with all the images, using server-side code (PHP in your case), or if you do want to perform the image load at client-side create an API call that gives you a list of all the images. Javascript can make 1 call to get that data and then load all the images, safe in the knowledge that they do exist.
I'm trying to execute function after anotherfunction but I'm getting this error in chrome:
TypeError: Cannot read property 'done' of undefined
The functions look like this but I guess it's not so important because they works fine:
function loadImages(){
var img_split = new Image();
img_split.onload = function(){
var this_canvas = img_canvas_split;
this_canvas.width = w;
this_canvas.height = h;
this_canvas.getContext('2d').drawImage(this, 0,0, w, h);
console.log("img 2");
};
img_split.src = path;
var bg = new Image();
bg.onload = function(){
var this_canvas = bg_canvas;
this_canvas.width = panorama_w;
this_canvas.height = panorama_h;
this_canvas.getContext('2d').drawImage(this, panoramaX,panoramaY, panorama_w, panorama_h);
console.log("img 3");
};
bg.src = path_panorama;
}
var drawToMain = function(){
...
main_ctx.drawImage( bg_b, 0, 0, bg_b.width * 0.5, bg_b.height * 0.5, panoramaX, panoramaY, bg_canvas.width, bg_canvas.height );
main_ctx.translate(imageX+img_canvas.width/2, imageY+img_canvas.height/2);
main_ctx.rotate(angle);
main_ctx.translate(-(imageX+img_canvas.width/2),-(imageY+img_canvas.height/2));
main_ctx.drawImage(img_canvas, imageX, imageY);
main_ctx.setTransform(1,0,0,1,0,0);
};
But when I call them like this:
loadImages().done( drawToMain );
It makes error as above.
Don't you have any idea how to solve this issue? I need to load my images first a then execute function.
I think you can use multi callback in your function. drawToMain function can be the call back of bg.onload; and bg.onload can be the callback of img_split.onload.
function loadImages(){
var img_split = new Image();
var bg = new Image();
img_split.onload = function(){
var this_canvas = img_canvas_split;
this_canvas.width = w;
this_canvas.height = h;
this_canvas.getContext('2d').drawImage(this, 0,0, w, h);
console.log("img 2");
img_split.src = path;
// First callcack
bg.onload = function(){
var this_canvas = bg_canvas;
this_canvas.width = panorama_w;
this_canvas.height = panorama_h;
this_canvas.getContext('2d').drawImage(this, panoramaX,panoramaY, panorama_w, panorama_h);
console.log("img 3");
bg.src = path_panorama;
drawToMain(); // callback when all is done
};
};
}
The .done() function is used in context of xHR (ajax) callbacks. it will not work on a regular function without a deferred object. I don't see any specific asynchronous requests on this function. I would suggest a callback, as mentioned above, but you could also 'fake' a deferred using $.when(), ie. $.when(loadImages()).done(drawToMain); although this will execute immediately, so not sure what you would gain there.
The best solution would be to add the following to your loadImages() function:
function loadImages(callback){
// rest of code
// right before close tag:
if (!!callback && typeof callback == 'function') {
callback();
}
}
and then when you call the function:
loadImages(drawToMain());
Note, this makes a lot of assumptions about how/where youre loading these scripts and how functions are organized. If you need to access variables in the first function, you could change callback() to callback(this) or callback(bg)
The easiest approach would be to pass in a callback function:
function abc(callback) {
//do some stuff...
callback();
}
abc(function() { console.log('foo'); });
I have read all the other similar posts but I don't understand why it I have this problem.
I have a canvas (#canvas) and an image (hero.png) on the page, and a JS file loaded at the end of the body. In the JS code...
This works:
var game = {};
game.canvas = document.getElementById('canvas');
game.ctx = game.canvas.getContext("2d");
game.draw = function(){
game.ctx.drawImage(game.hero, 200, 200);
}
game.hero = new Image();
game.hero.src = "hero.png";
game.hero.onload = game.draw;
And this doesn't work:
var game = {};
game.canvas = document.getElementById('canvas');
game.ctx = game.canvas.getContext("2d");
game.hero = new Image();
game.hero.src = "hero.png";
game.hero.onload = game.draw;
game.draw = function(){
game.ctx.drawImage(game.hero, 200, 200);
}
Nothing appears. No error in the console. Why???
Thanks!
You can call functions before define them only with this syntax:
function draw()
{
//COde here
}
By writting
game.draw = function(){};
You define a method to your object, you don't define a JavaScript function: that's why you can't call it before define it :)
In your second hunk of code, you're defining
game.hero.onload = game.draw;
When game.draw is undefined, so your onload is undefined and nothing happens when the image is done loading.
game.draw is not set when you assign it in your second example, you are copying an undefined value into hero.onload.
One workaround is to wrap the function you want to call in an anonymous function and call yours from there:
game.hero.onload = function(){ game.draw(); };
Have in mind that if hero loads before the definition of game.draw is finished, this code will fail.
function LoadResources(){
alert("In load socket");
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var tiles= new Array();
var loadedCount=0;
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload=function(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
};
So when i call the function LoadResources() it does give the alert "in load socket" but does not gives the alert while in imageObj.onload function.
You can use window.onload function i.e "window.onload = function() {..}" and my function in it while use in the body of html document.
Plus i m running it on Google chrome .Is there the problem with chrome's onload or something .
You are trying to increase the loading counter even if the onload function are called only once (at the moment when the images has been loaded completely), so there is no way to trigger the alert many times. For me it's not quite obvious what are you trying to do. Anyway if you want to load multiple images with onload function the best practice is to use a closure, otherwise on each iteration it may happens that at the end of the loop you will get only the last image loaded. I'm not going into detail into what a closure is, but the principle is something like this:
for (var i = 0; i< 4; i++) {
var imgObj = new Image();
imgObj.onload = (function(img) {
return function () {
ctx.drawImage(imgObj, 0, 0);
}
})(i);
imgObj.src = 'image.png';
}
This way by calling a new function you will create a new execution context retaining the value of i on each iteration.
I am just adding a little help for your code.
For assigning functions the way you're doing it , it is cheaper to do it the way below.
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload= imageOnLoad;
}
function imageOnLoad(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
function find_image_dm(imgsrc){
window.imgwidth = "";
var img = new Image();
img.onload = function test() {
var width = this.width;
var height = this.height;
if (height > 300) {
var x = height/300;
window.imgwidth = Math.ceil(width/x);
}
}
img.src = imgsrc;
return(window.imgwidth);
}
I want to return window.imgwidth so i can use it else where but if I try to alert it or anything like that it shows up blank. How do I return its value. window.imgwidth is my attempt to create a global variable. I do not need the width of the window
The problem with your attempt is that the onload callback executes asynchronously. Because of this, you cannot reliably return anything since the onload callback is executed at some future time. Instead of thinking in terms of return values, think about passing a callback function parameter to your find_image_dm function:
function find_image_dm(imgsrc, callback)
{
var img = new Image();
img.onload = function()
{
callback(this.width, this.height);
};
img.src = imgsrc;
}
Which you'd use like this:
function onReturnSize(w, h)
{
console.log('image width is', w);
console.log('image height is', h);
}
find_image_dm('http://placekitten.com/2200/1200', onReturnSize);
Demo: http://jsfiddle.net/mattball/pTKW4/
The problem i think is when you execute find_img_dm, you are trying to return the width value immediately. This won't work because the img.onload most likely won't be fired before the function finishes executing.
What you would need to do is in the onload event handler, put a call to another function, passing in the width value, and have that function do what you need to do when the image is loaded. Then you will know that at that point, the image is loaded and the width value is available.
OK try this. You have to return the value of window.imgwidth within the function test:
function find_image_dm(imgsrc){
window.imgwidth = "";
var img = new Image();
img.onload = function test() {
var width =this.width
var height= this.height;
if(height > 300){
var x = height/300;
console.log(Math.ceil(width/x));
window.imgwidth = Math.ceil(width/x);
console.log(window.imgwidth);
alert (window.imgwidth);
return window.imgwidth;
}
}
img.src = imgsrc;
}
Ok. Another stab at this, #Tom.
There may be two issues here, from what I can see.
There will be no calculation of window.imgwidth if your if statement returns false, as this appears to be the only place you are calculating it.
The window.imgwidth is being calculated in function test() but not returned.
Looking at your code it seems the issue is you aren't technically loading the image before trying to get the height because you are setting the src after the the onload call.
If you are using jQuery you should try and leverage it.
function find_image(imgsrc) {
var imgWidth,
img = $('<img/>').attr('src', imgsrc).load(function() {
var $img = $(this),
height = $img.height(),
width = $img.width();
if (height > 300) {
var x = height/300;
imgWidth = Math.ceil(width/x);
}
});
return imgWidth;
}
Ok... I went through your code and found a problem with your script. You are using image.onload function, so when u load image source, image loads and then only dimension are available and stored on the window.imgwidth.
All goes fine, but problem is, when u call the function, it takes time to load the u image, so if you try to get the window.imgwidth, as the resource is still loading you wont get the window.imgwidth. Return value also will not work as codes do not wait till the image loads so although the image is loading the code block execution will be completed so you wont have any data in window.imgwidth.
If you try to alert window.imgwidth after certain duration when image loading is completed then you can see that window.imgwidth has the value. And also you have the if block which stores the data in window.imgwidth only when the height more than 300 but you dont have else block so you need to implement that too as a fallback :) .
Let me know if i said it hard way :-D