I'm a beginner with OOP coding in javascript.
I'm trying to set a size of a class. But i got an error in my code.
(function($) {
Block = function() {
var self = this;
this.el = $('<div></div>');
}
Block.prototype.appendTo = function(parent) {
this.el.appendTo(parent);
}
Block.prototype.setSize = function(width, height) {
var self = this;
this.width = width;
this.height = height;
}
})(jQuery);
This is how i call the class:
var block1 = new Block();
block1.appendTo('body').setSize(100,100);
In the console i get:
Uncaught TypeError: Cannot call method 'setSize' of undefined
You are calling setSize on the return value of appendTo. However, appendTo returns nothing (undefined) and as such it throws an Error when you try and call setSize on it.
The solution to this is to return the Block object from your appendTo function, like so:
(function($) {
Block = function(width, height) {
this.el = $('<div></div>');
if (width !== undefined && height !== undefined) {
this.width = width;
this.height = height;
}
}
Block.prototype.appendTo = function(parent) {
this.el.appendTo(parent);
return this;
}
Block.prototype.setSize = function(width, height) {
this.width = width;
this.height = height;
}
})(jQuery);
Related
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);
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
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 want to call to method setupCanvas.Draw(); to draw rectangle.
And for some reason I can not call a function Draw(); from out the scop game.setupCanvas();
Demo jsfiddle
window.game = window.game|| {};
game.main = function() {};
game.setupCanvas = function(){
var w = $(window).outerWidth();
var h = $(window).outerHeight();
myCanvas = document.createElement('canvas');
document.body.appendChild(myCanvas);
myCanvas.id = "playground";
myCanvas.width = w * 0.8;
myCanvas.height = h * 0.8;
myCanvas.style.left= (w - myCanvas.width )/2 + 'px' ;
myCanvas.style.top= (h - myCanvas.height )/2 + 'px' ;
myCanvas.style.zIndex = 10;
myCanvas.style.position = "absolute";
myCanvas.style.border = "1px solid green ";
this.ctx= $('#playground').get(0).getContext('2d');
this.Draw = function(){
ctx.fillStyle="#0000FF";
ctx.fillRect(150,75,150,75);
ctx.fillStyle="#F0F0FF";
ctx.fillRect(0,0,150,75);
};
}();
game.setupCanvas.Draw();
Many thanks
You need to create a new instance:
var x = new game.setupCanvas();
x.Draw();
Also, this part is wrong:
};
}(); // <--
game.setupCanvas.Draw();
You're immediately-invoking the function, which you shouldn't be doing. It returns undefined to game.setupCanvas. Take it away and your code should work.
Moreover, when you reference a thectx property in your Draw method, you need to use this.ctx.
jsFiddle Demo
Your assignment of game.setupCanvas is invalid since the self invoking function doesn't return anything so game.setupCanvas will be undefined. Make sure to return an object with your public methods like this.
return {
Draw: function(){
ctx.fillStyle="#0000FF";
ctx.fillRect(150,75,150,75);
ctx.fillStyle="#F0F0FF";
ctx.fillRect(0,0,150,75);
},
DrawSomethingElse: function(){
ctx.fillStyle="#0000FF";
ctx.fillRect(150,75,150,75);
ctx.fillStyle="#F0F0FF";
ctx.fillRect(0,0,150,75);
}
};
Here is an update to your fiddle http://jsfiddle.net/dAvtS/11/
When I try to draw an image to a Canvas element I get this exeption:
Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1
textureLoadedstaticsprite.js:14
StaticSpritestaticsprite.js:21
(anonymous function)
All both the CanvasRenderingContent and the HTMLImageElement exist.
I just don't get it :S
Here is teh code I'm using:
/**
* Class for drawing static sprites, like trees and blocks
*/
function StaticSprite(args) {
// Private Fields
var texture = new Image();
// Events
function textureLoaded(context) {
console.log(context);
console.log(texture);
context.drawImage(texture, 0, 0, 32, 32);
}
// Constructor
// Add event listeners
texture.addEventListener("load", textureLoaded(this.graphics), false);
// Load texture
texture.src = "img/assets/wall1.png";
if(args != undefined) {
// Set local fields
this.x = args.x || this.x;
this.y = args.y || this.y;
this.z = args.z || this.z;
this.width = args.width || this.width;
this.height = args.height || this.height;
}
this.width = 32;
this.height = 32;
}
// Inherit from GraphicsEntity
StaticSprite.prototype = new GraphicsEntity();
And here is the GraphicsEntity base class, in case you need it :P
/**
* Class for presentation of graphical objects.
*/
function GraphicsEntity(args) {
// Private Fields
var x = 0; // The X-position of the GraphicsEntity relative to it's parent container
var y = 0; // The Y-position of the GraphicsEntity relative to it's parent container
var z = 0; // The Z-position of the GraphicsEntity relative to it's parent container
var width = 0; // The width of the GraphicsEntity
var height = 0; // The height of the GraphicsEntity
// Public Fields
this.DOMElement = null; // Reference to the corresponding HTML Element
this.graphics = null; // The 2D context for rendering 2D onto the element.
this.name = ""; // The name of the GraphicsEntity
// Properties
// The Alpha or transparency value of the GraphicsEntity, 1 is completely opaque, 0 is completely transparent.
Object.defineProperty(this, "alpha", {
get: function() { return parseFloat(this.DOMElement.style.opacity); },
set: function(value) { this.DOMElement.style.opacity = value; }
});
// The height of the GraphicsEntity
Object.defineProperty(this, "height", {
get: function() { return height; },
set: function(value) {
height = value; // Set internal width
this.DOMElement.setAttribute("height", height); // Set DOMElement width
}
});
// The width of the GraphicsEntity
Object.defineProperty(this, "width", {
get: function() { return width; },
set: function(value) {
width = value; // Set internal width
this.DOMElement.setAttribute("width", width); // Set DOMElement width
}
});
// The X-position of the GraphicsEntity relative to it's parent container
Object.defineProperty(this, "x", {
get: function() { return x; },
set: function(value) {
x = value; // Set internal X-axis
this.DOMElement.style.left = Math.ceil(x) + "px"; // Set DOMElement X-axis
}
});
// The Y-position of the GraphicsEntity relative to it's parent container
Object.defineProperty(this, "y", {
get: function() { return y; },
set: function(value) {
y = value; // Set internal Y-axis
this.DOMElement.style.top = Math.ceil(y) + "px"; // Set DOMElement Y-axis
}
});
// The Z-position of the GraphicsEntity relative to it's parent container
Object.defineProperty(this, "z", {
get: function() { return z; },
set: function(value) { this.DOMElement.style.zIndex = parseInt(value); }
});
// Constructor
// Get constructor values of use default
if(args) {
x = args.x || x;
y = args.y || y;
z = args.z || z;
width = args.width || width;
height = args.height || height;
}
// Create a new canvas element
this.DOMElement = document.createElement('canvas');
// Set postion
this.DOMElement.style.position = "absolute"; // Positioning style
this.DOMElement.style.left = x + "px"; // X-axis
this.DOMElement.style.top = y + "px"; // Y-axis
this.DOMElement.style.zIndex = z; // Z-Axis
this.DOMElement.width = width;
this.DOMElement.height = height;
// Set opacity/alpha
this.DOMElement.style.opacity = 1;
// Get 2d canvas context
this.graphics = this.DOMElement.getContext('2d');
}
texture.addEventListener("load", textureLoaded(this.graphics), false);
This line tries to add the function returned by textureLoaded(this.graphics) as the event listener. The function returns undefined, so it doesn't quite work out.
Try changing that line to
texture.addEventListener("load", textureLoaded, false);
and replacing the line
function textureLoaded(context) {
With the lines
var context = this.graphics;
function textureLoaded() {