So I am getting a "Uncaught TypeError: Cannot read property '0' of undefined
at update" at line 42, which is this one:
init.ctx.moveTo(this.trail[0].x,this.trail[0].y);
from the following code:
window.onresize = function(){
init.canvas.width = window.innerWidth;
init.canvas.height = window.innerHeight;
//updateComponents();
}
var init = {
canvas: new Object(),
ctx: new Object(),
constructCanvas: function(){
this.canvas = document.getElementById("canvas");
this.ctx = this.canvas.getContext("2d");
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
}
init.constructCanvas();
var background = {
color: "green",
refresh: function(){
init.ctx.fillStyle = this.color;
init.ctx.fillRect(0,0,init.canvas.width,init.canvas.height);
}
}
//background.refresh();
function updateComponents(){
background.refresh();
}
function WalkingLine(arguments){
this.frames = 0;
this.trail = [];
this.walkLength = 5;
this.position = arguments.position;
this.color = "black";
this.trail[0] = this.position;
}
WalkingLine.prototype = {
update: function(){
init.ctx.beginPath();
init.ctx.moveTo(this.trail[0].x,this.trail[0].y);
var i;
for(i=1;i<this.trail.length;i++)
init.ctx.lineTo(this.trail[i].x,this.trail[i].y);
init.ctx.stroke();
this.generateNext();
},
genarateNext: function(){
this.trail[this.trail.length] = {x:this.trail[this.trail.length-1].x+5,y:this.trail[this.trail.length-1].y};
init.ctx.lineTo(this.trail[this.trail.length-1].x,this.trail[this.trail.length-1].y);
inti.ctx.stroke();
}
};
var one = new WalkingLine({position:{x:100,y:100}});
setTimeout(one.update,1000);
So i dont understand why i am apparently trying to access an invalid index in the array because i explicitly set table[0] in the constructor of the WalkingLine class yet despite that it still says it is an uncaught type Error.
You lose context:
setTimeout(one.update,1000);
That way you pass only update without the one, so when its called later it does not know where it belongs to. You either need to call it directly ( inside an arrow function):
setTimeout(()=>one.update(),1000);
or you need to bind the function to one:
setTimeout(one.update.bind(one),1000);
Related
Following is a simple class definition. this.bounds is undefined in the console so i am wondering how can i access and alter bounds inside a callback. The goal is after the image is loaded, the bounds will be set to bounds.width = image.width etc. Thanks!
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = function () {
console.log("image was loaded " + this.bounds);
}
};
}
Can you try doing :
this.image.onload = function () { console.log("image was loaded " + this.bounds); }.bind(this)
"bind" is used to bind the current scope of this to any function.
Whenever you call the function in future, the bound reference of this will be used.
Please refer this link : what is bind in javascript
Inside onload callback this no longer points to Car instance but to image because it's called by image object when image is loaded. To access Car methods inside this callback you can:
use bind method which returns new function inside which this is set the to value passed as argument to bind
this.image.onload = function () {
console.log("image was loaded " + this.bounds);
}.bind(this)
You can read more about bind here
in ES2015 you can use arrow function which also preserves this value:
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = () => {
console.log("image was loaded " + this.bounds);
}
};
}
You can read more about arrow functions here
you can also define a variable that will hold a value of this
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
var self = this;
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = function () {
console.log("image was loaded " + self.bounds);
}
};
}
"this" inside function image.onload() is actually scoped under function setImage(), which definitely don't have this.bounds defined, hence you got it undefined.
One solution could be to assign this to any variable just before the line: this.image.onload = function () {
so it will change to:
var that = this;
this.image.onload = function () {
console.log("image was loaded " + that.bounds);
}
I think you should see this:
var doc, bod, htm, Img, C, E; // for reuse on other loads
addEventListener('load', function(){
doc = document; bod = doc.body; htm = doc.documentElement;
C = function(tag){
return doc.createElement(tag);
}
E = function(id){
return doc.getElementById(id);
}
Img = function(src, complete, context){
this.image = C('img');
var img = this.image;
var cx = context || this;
img.addEventListener('load', function(eventObj){
complete.call(cx, eventObj);
});
img.src = src;
this.imgMethod = fuction(){
this.newProp = 'this in here refers to instance of Img';
}
}
Car = function(){
this.setImg = function(src, complete){
return new Img(src, complete);
}
}
var what = new Car; // no args it's okay to not use () with new
var someImg = what.setImg('yourImgSrc.png', function(){
this.imgMethod(); console.log(this.newProp);
});
someImg.image.addEventListener('click', function(ev){
var bc = this.getBoundingClientRect();
var xy = {x:ev.clientX-bc.left, y:ev.clientY-bc.top};
console.log(xy);
});
});
Note: this is only an example of this binding using call
I'm having a problem while loading pictures in my javascript. Seems that the .onload function is never called and so the picture is not marked as loaded. Can you help?
Here is the code:
//image loader
var img = function (source){
this.loaded = false;
this.image = new Image();
this.image.onload = function () {
this.loaded = true;
};
this.image.src = source;
}
//default component definition
var component = function (x, y){
this.x = x;
this.y = y;
this.draw = function (offsetX, offsetY, img){
if(img.loaded){
ctx.drawImage(img.image,
this.x + offsetX,
this.y + offsetY,
img.image.width, img.image.height);
}
}
}
Thanks
Context #1
this.image.onload = function () {
this.loaded = true;
};
this referes to [object HTMLImageElement], not to the img instance.
Context #2
Now, changing the code to:
this.image.onload = function () {
this.loaded = true;
}.bind(this);
When you do new img("http://serban.ghita.org/imgs/serban.jpg");, this will refer to your [object Object].
Context #3
Now, If you do img("http://serban.ghita.org/imgs/serban.jpg");, without new, this will refer to [object Window].
Solution
It depends on the context of this.
You change it with bind
Or by declaring and external var _this = this; and then use _this.loaded = true; inside onload.
Code: https://jsbin.com/pasumab/edit?js,console
Im trying to make a Hangman game, but im so n00b that i dont get where is the error on my code, im glad if you can help me, (Sorry for my bad english.)
var hombre;
var Ahorcado = function (con) {
this.contexto = con;
this.maximo = 5;
this.intentos = 0;
this.dibujar();
}
Ahorcado.prototype.dibujar = function () {
var dibujo = this.contexto;
dibujo.beginPath();
dibujo.moveTo(150,100);
dibujo.lineTo(150,50);
dibujo.lineTo(400,50);
dibujo.lineTo(400,350);
dibujo.strokeStyle = '#000'
dibujo.stroke();
dibujo.closePath();
}
function iniciar() {
var canvas = document.getElementById('c');
canvas.width = 500;
canvas.height = 400;
var contexto = canvas.getContext('2d');
hombre = new Ahorcado();
}
Thanks.
Your function takes a parametercon in var Ahorcado = function (con) {...}
When you call hombre = new Ahorcado(), you are forgetting to pass in your contexto variable.
Change it to:
function iniciar() {
var canvas = document.getElementById('c');
canvas.width = 500;
canvas.height = 400;
var contexto = canvas.getContext('2d');
hombre = new Ahorcado(contexto);
}
var contexto = canvas.getContext('2d');
hombre = new Ahorcado();
You forgot to pass in the context to the constructor
I am trying to understand objects in javascript. Here is the code:
var fn={};
var canvas;
var ctx;
fn.game=function(width,height,inSide,name){
this.canvas2=document.getElementById(inSide).innerHTML = "<canvas id="+name+" style='width:"+width+";height:"+height+";'>Your browser does not support the Canvas Element.</canvas>";
this.canvas=document.getElementById(name);
this.ctx=this.canvas.getContext("2d");
document.getElementById(inSide).style.width=width;
document.getElementById(inSide).style.height=height;
canvas=document.getElementById(name);
ctx=this.canvas.getContext("2d");
this.width=width;
this.height=height;
canvas.width=width;
canvas.height=height;
this.add={
};
this.add.state=function(name){
this[name]=3;
};
};
var game=new fn.game(640,480,"game","canvas");
game.addState("play");
when I am referencing this["name"] I am trying to refer this to fn.game, but that dous not work because this references the most local object. Any ideas on how to do this?
As you said, it references the most local object, to do what you explained :
...
fn.game=function(width,height,inSide,name){
var that = this;//expose this of fn.game to this scope
...
this.add={
};
this.add.state=function(name){
that[name]=3;//access this of fn.game
};
};
There are a couple of ways to do this, and it depends on the way you're doing it, although I think the biggest issue you've got is that your object has no declared function of addState() so when I tried to run your code it just gave me an error. In the code below I changed it, and it should work how you want it to currently.
var fn = {};
var canvas;
var ctx;
fn.game = function(width, height, inSide, name) {
this.canvas2 = document.getElementById(inSide).innerHTML = "<canvas id=" + name + " style='width:" + width + ";height:" + height + ";'>Your browser does not support the Canvas Element.</canvas>";
this.canvas = document.getElementById(name);
this.ctx = this.canvas.getContext("2d");
document.getElementById(inSide).style.width = width;
document.getElementById(inSide).style.height = height;
canvas = document.getElementById(name);
ctx = this.canvas.getContext("2d");
this.width = width;
this.height = height;
canvas.width = width;
canvas.height = height;
this.add = {
};
this.addState = function(name) {
this[name] = 3;
console.log(this);
};
};
var game = new fn.game(640, 480, "game", "canvas");
game.addState("play");
<div id="game"></div>
HOWEVER
If you'd like to have that same syntax as before, of game.add.state(), then something like either of the below examples should work:
Example 1
Link to Function.Prototype.Bind
//Rest of code
this.add={};
this.add.state = function(name){
this[name]=3;
}.bind(this)
//Rest of code
Example 2
Javascript Variables and Scope
//Rest of code
this.add={};
var self = this;
this.add.state = function(name){
self[name]=3;
}
//Rest of Code
every time you are inside a function() the meaning of this changes to the current function
all you need to do is save the reference to the object you want to access
fn.game=function(width,height,inSide,name){
var self = this;
this.add.state=function(name){
self[name]=3;
};
};
In order for this to mean mean fn.game, you would need to do something more like:
var doc = document, bod = doc.body;
function E(e){
return doc.getElementById(e);
}
function C(t){
return doc.createElement(t);
}
function FnGameAdd(){
this.state = function(popertyName){
this[propertyName] = 3;
}
}
function FnGame(canvasId, width, height, inside){
// style with CSS
inside.innerHTML = "<canvas id='"+canvasId+"'>Your browser does not support the Canvas Element.</canvas>";
var cv = this.canvas = E(canvasId);
cv.height = height; cv.width = width; this.ctx = cv.getContext('2d');
this.add = new FnGameAdd;
};
}
var fn = {};
fn.game = function(canvasId, width, height, inside){
// this.prop = 'belongs to fn';
return new FnGame(canvasId, width, height, inside);
}
new fn.game('canvas', 640, 480, E('game'));
/* keep this for fun of creating new Object literals, not needed here
Object.create = Object.create || function(obj){
function F(){}; F.prototype = obj;
return new F;
}
var newObj = Object.create(fn);*/
I'm new using JS. I want to keep all of the information about an object in one place.
So I've made this function:
function Obiekt(img) {
this.img = img;
this.ready = false;
this.image = new Image();
this.image.src = this.img;
this.image.onload = function() {
ready = true;
};
this.x = 0;
this.y = 0;
this.rotation = 0;
}
Then I've made my object, named hero.
var hero = new Obiekt("images/hero.png");
Problem is, hero.ready is always false and I can't draw this.
if (hero.ready) {
ctx.drawImage(hero.image, 0, 0);
}
Can you help me?
Two problems :
ready can't be found
If your image is cached (depending on the browser), the order you used can't work as the image isn't loaded after you set the callback.
Here's a solution :
var _this = this;
this.image.onload = function() {
_this.ready = true;
};
this.image.src = this.img;
(and I'd add that the naming isn't very good : I'd prefer imgsrc over img)