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.
Related
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 would like to use the drawImage() function to load an image in a Javascript animation, but the image does not load with my current code. I think I need to specifically ask for the image to be loaded at some point, but I'm not sure when or how. The idea is to make a cloud that goes across the canvas. Thank you for your help.
function draw(x,y){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
x += 2;
if(x>1000){
x=0;
}
var cloud = new image();
cloud.src='small_cloud.png';
ctx.drawImage(cloud,x,0);
var loopTimer = setTimeout('draw('+x+','+y+')',20);
}
Try new Image()rather than new image()
Also move
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
to outside the draw()function, as you only want to set these things up once. Delay this setting up until the browser has had time to parse the document, for example using
window.onload = function(){ ... };
(Though in reality you'd have to make sure not to overwrite any existing window.onload listeners by using proper even handler registration.) Also delay the first invocation to draw()until the image has loaded, for example like so:
cloud.onload = function(){
draw(cloud, 0, 0);
}
I'd also change
var loopTimer = setTimeout('draw('+x+','+y+')',20);
to
setTimeout(function(){ draw(x, y); }, 20);
since you seem not to be using the loopTimer variable, and since passing setTimeout an anonymous function rather than a string is considered better practice.
Finally, it would look like this:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
cloud.onload = function(){
draw(ctx, cloud, 0, 0);
};
};
function draw(ctx, cloud, x,y){
x += 2;
if(x>1000){
x=0;
}
ctx.drawImage(cloud,x,0);
setTimeout(function(){ draw(ctx, cloud, x, y); }, 20);
}
Note that, since ctx is no longer defined inside the draw() function, as it is local to the anonymous window.onload function, you also has to pass ctx to the draw() function.
I have a web page displaying an HTML5 canvas. When the web page loads, the following JavaScript function is called:
window.onload = function(){
var sources = {};
sources[0] = document.getElementById("building").src,
sources[1] = document.getElementById("chair").src,
sources[2] = document.getElementById("drink").src,
sources[3] = document.getElementById("food").src,
sources[4] = document.getElementById("fridge").src,
sources[5] = document.getElementById("land").src,
sources[6] = document.getElementById("money").src,
sources[7] = document.getElementById("oven").src,
sources[8] = document.getElementById("table").src,
sources[9] = document.getElementById("van").src,
sources[10] = document.getElementById("burger").src,
sources[11] = document.getElementById("chips").src,
sources[12] = document.getElementById("drink").src,
sources[13] = document.getElementById("franchiseFee").src,
sources[14] = document.getElementById("wages").src,
sources[15] = document.getElementById("admin").src,
sources[16] = document.getElementById("cleaners").src,
sources[17] = document.getElementById("electricity").src,
sources[18] = document.getElementById("insurance").src,
sources[19] = document.getElementById("manager").src,
sources[20] = document.getElementById("rates").src,
sources[21] = document.getElementById("training").src,
sources[22] = document.getElementById("water").src,
sources[23] = document.getElementById("burger").src,
sources[24] = document.getElementById("chips").src,
sources[25] = document.getElementById("drink").src,
sources[26] = document.getElementById("creditors").src,
sources[27] = document.getElementById("electricity").src,
sources[28] = document.getElementById("food").src,
sources[29] = document.getElementById("hirePurchase").src,
sources[30] = document.getElementById("loan").src,
sources[31] = document.getElementById("overdraft").src,
sources[32] = document.getElementById("payeTax").src,
sources[33] = document.getElementById("tax").src
loadImages(sources, drawImage);
drawGameElements();
drawDescriptionBoxes();
};
This function loads some images from the hidden section of the HTML into the JavaScript, and draws them to the canvas by calling the 'drawImage()' function on each image in the 'sources' array. It then calls the 'drawGameelements();' function, which draws a few more things to the canvas, and finally, I then want to call the 'drawDescriptionBoxes()' function.
This function however, is in a separate JS file to the rest of the code, and when I view the page in a browser, although 'loadImages()' and 'drawGameElements()' are called, and draw what they're supposed to to the canvas, I get an error in the console saying:
ReferenceError: drawDescriptionBoxes is not defined
which I assume means that I haven't referenced the function correctly, since it's not in the same file as where I'm calling it.
What I'm wondering is how do I call this function from the other file? Would it be something like: filename.js.drawDescriptionBoxes ?
There's really two possibilities why the drawDescriptionBoxes function is undefined.
1) It's out of scope
In JavaScript, variables exist in some sort of scope. This maybe global, such as:
<script>
var foo = 123; //foo can be referenced anywhere, it's global!
</script>
Or scoped within another block of code:
function myFunc()
{
var bar = function () //bar can only be accessed within myFunc
{
};
};
//bar() here is undefined
There's a possibility your drawDescriptionBoxes function is not in the global scope.
2) It's not yet defined when your code runs
It's also possible you have some code like this:
File 1
<script>
var result = someFunc(123);
</script>
File 2
<script>
function someFunc(x)
{
return x * 2;
}
</script>
If File 2 gets included after File 1, someFunc doesn't yet exist when file 1 is run. You can get around this by running everything after the document fully loads, using event handlers. If var result = someFunc(123); was run in the onload event, it would work fine regardless of what file someFunc was defined in.
Hope this helps!
if drawDescriptionBoxes is defined as a global function, such as
function drawDescriptionBoxes() {
}
then the fact that it is not found means that the javascript file containing it did not load. Show how you include this file in html and how the function is defined.
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);
}
I'm writing a simple 2D side scroller game using JavaScript + Canvas. I am trying to do this while learning OO JavaScript. I'm encountering an issue where my image will not draw to the canvas, despite being loaded correctly. Here's the code:
//===================================
// class - Canvas
//===================================
var classCanvas = function(id){
canvas = document.getElementById(id);
context = canvas.getContext("2d");
}
//===================================
// abstract class - Image Drawer
//===================================
var classImageDrawer = function(that){
this.draw = function(){
context.drawImage(that.img,
that.spriteCoordsX,
that.spriteCoordsY,
that.width,
that.height,
that.posX,
that.posY,
that.width,
that.height);
}
}
//===================================
// class - Level
//===================================
var classLevel = function(name, src){
this.name = name;
this.img = new Image();
this.img.src = src;
this.img.onload = function(){ };
this.spriteCoordsX = 0;
this.spriteCoordsY = 0;
this.posY = 0;
this.posX = 0;
this.height = 400;
this.width = 600;
this.drawer = new classImageDrawer(this);
}
//==================================
// Begin
//==================================
var game = new classCanvas("playground");
game.LevelOne = new classLevel("LevelOne", "images/foreground-land.png");
game.LevelOne.drawer.draw();
I have checked the code, and I know the image is getting loaded correctly. No errors occur during runtime, the image "foreground-land.png" simply DOESN'T show up on the canvas!
Your image may be loading fine, but as far as I can tell your call to game.LevelOne.drawer.draw() has no guarantee that foreground-land.png has loaded at that point (remember, images are loaded asynchronously without blocking the execution of other code).
Your onload function for the image object in your classLevel class is empty and anonymous. Nothing happens when the image is finished loading. I'm not sure how you want to structure your code given everything else you have going on, but you should only allow the call to game.LevelOne.drawer.draw() to succeed if the resources it depends upon have been fully loaded. The best way to do this would be to hook into the onload callback for all resources you require for that object (in this case, it's just the one image).
Loading images is an async operation, you are (basically) ignoring the loading process, and acting as though it is sync operations.
One thing you could look at is using a 3rd parameter as a callback ("LevelOne", "images/foreground-land.png", function() { this.drawer.draw() }) and doing that as the onload