Class Function is not a function - javascript

I am creating a game engine for HTML5 Canvas with javascript for personal use, however I am running into a problem. I have created a entities class with a super constructor and a few functions (like remove and add new entities) as well as a update and init function within the class. However when I run the main init at the end of the code, with entities.init(); it reports an error and says it is not a function, even though I'm sure I made it public. Here is the code
function entities(){
//Entities class holds all objects that: take damage, move,and do things that a static object could not.//
//A list of all current entities in game//
var entitiesList = new Array();
//Allows removal of an entitiy from the game, and the current list of entities//
function removeEntity( id){
//snip!//
}
//entity superclass//
function entity( name, spriteName, HP){
//snip!//
var updateEntity = new function(){
console.log("UPDATING Entities")
//drawSprite(sprite, posX, posY);
if(this.timer > 0){
this.timer = this.timer - 1;
}else{
removeEntity(this.entityID);
delete this;
}
if(this.health == 0){
removeEntity(this.entityID);
delete this;
}
}
}
//Method to create a new entity//
function createNewEntity( entName, sprite, posX, posY, HP){
//snip!//
}
var damageField = new function(radius, power, posX, posY) {
//Damage any entities within a "square" radius of an entity. I plan to add radial version later//
//snip!//
}
this.init = function(){
console.log("INIATING ENTS");
createNewEntity("NUGGET", "chaingun_impact.png", 250, 250);
}
//update function for superclass update function to call//
this.update = function(){
entity.updateEntity();
}
}
The main init function
function init(){
pushToSheetList();
jsonParser();
entities.init();
}
Also I am 99.99% sure that the update function is not called either it is the same code pretty much just update() instead.
I am really not sure what to do, unless I want to make it so every sprite on the screen is hard coded manually, and no one wants that for a reusable engine.

You need to create instance of your entities class.
var oEntity=new entities();
oEntity.init();//call init method.

var en = new entities();
en.init();

Related

Passing $(this) to a new P5 instance is undefined

In the code below, I'm looping through each "player_visualizer" element and attempting to create a new P5 instance for each element.
If I console.log(context) in the loop I will get the context of that particular element, which is exactly what I need.
$('.player_visualizer').each(function (i) {
context = $(this);
playerVisualizersP5[i] = new p5(playerVisualizer, context);
});
However, The trouble I'm having is passing the context of that particular element to the function that will handle all of the P5 animations.
For example, when I try and pass that context variable to the function below and do console.log(p.context), the context variable is always undefined.
let playerVisualizer = function (p, context) {
p.context = context;
}
I've done a fair amount of research on what I could do about this, but I can't seem to tie it back to my particular situation. I've narrowed down my research to a few resources below.
http://hugoware.net/blog/passing-context-with-javascript
How do I pass the this context to a function?
Any help or guidance is greatly appreciated.
Why do you believe that passing something into the p5 constructor will automatically pass that argument into the playerVisualizer function?
From the P5.js documentation:
One final note: when creating a p5 instance, you can specify a second
argument (HTML element id) which acts the parent for all elements
created by the sketch. For example, let's say you have:
<body>
<div id = "p5sketch">
</div>
<p>Some other HTML</p>
</body>
You can now say:
var myp5 = new p5(s,'p5sketch');
And all elements will be created inside that div.
This means the only valid second argument is a string ID, which gets used by P5.js but isn't passed into the sketch function.
To understand better what's going on, let's look at this example:
var s = function( sketch ) {
sketch.setup = function() {
sketch.createCanvas(200, 200);
};
sketch.draw = function() {
sketch.background(128);
};
};
var myp5 = new p5(s);
In this example sketch, there are a few things to understand:
myp5 is an instance of p5, which contains P5.js functions like setup() and draw() and background().
s is a sketch function, which takes an instance of p5.
sketch is an instance of p5, which s can use to access P5.js functions.
In other words, myp5 and sketch are the same object.
This is useful to you, because if you want to pass data into sketch, you can pass that data into myp5, like this:
var s = function( sketch ) {
sketch.setup = function() {
sketch.createCanvas(200, 200);
};
sketch.draw = function() {
sketch.background(128);
sketch.text(sketch.extraThing, 20, 20);
};
};
var myp5 = new p5(s);
myp5.extraThing = "testing";

Assigning callback events from an array of strings (PIXI.js)

all. I have kind of a doozy of a problem, that could be solved really simply, if I just wanted to duplicate the code. I mean, really, it's a small part of a project that I'm doing just to see if I can, more than anything else, but it is bothering me since I've thought it up.
The Project
For fun, I've decided to take someone's ActionScript 3, text-based game engine and convert it to TypeScript and ultimately JavaScript using PixiJS.
The thing is, there are still 20213 errors to be fixed running tsc, so I could just leave this to a later date. But I was working on the Button class, which they defined as a subclass of MovieClip. That's fine; I just responded by reading up on PIXI buttons, and they seem fairly straightforward. Just, in the button's constructor, add something akin to the following lines:
export class Button extends PIXI.Sprite {
private _callback : Function;
private _height : number;
private _width : number;
public get callback() : Function { return this._callback; }
public set callback(fn : Function) {this._callback = fn; }
public get height() : number { return this._height; }
public set height(h : number) {this._height = h; }
public get width() : number {return this._width; }
public set width(w : number) {this._width = w; }
public constructor(width = 180, height = 90, callback: Function = null){
super(new PIXI.Texture(new PIXI.BaseTexture(GLOBAL.BTN_BACK, PIXI.SCALE_MODES.NEAREST)));
this.callback = callback;
this.width = width;
this.height = height;
this.buttonMode = true;
this.interactive = true;
this.anchor.set(0.5);
this.on('mousedown', this.callback)
.on('touchstart', this.callback);
}
}
That's a bit of a simplified version, and the version I did on Codepen uses a Container and a private _sprite field instead (as well as a ColorMatrixFilter that doesn't work too well on the black icons I picked out, but that's not really important for this question), but that's roughly the gist of how it's done.
The Problem
The problem is that, in the codepen, I'd like to do the following:
// assign `this.callback` to each of the following events:
let that = this;
['click','mousedown','touchstart'].map(evt => that.on(evt, that.callback});
with a simple call being passed in their constructors elsewhere:
for (let n = 0; n < 5; ++n){
btnArray.push(new Button(16, 16, () => console.info('You pushed button %d', n)));
}
but I'm not getting anything from them, even in the Chrome Console. I even logged that ColorMatrixFilter I mentioned earlier, to see if it was console.info that was wrong. Nope. So now, I'm confused on that. I was hoping to be able to just make a GLOBAL (a legacy static object from the AS source) key to iterate through for the events, but it looks like that's not happening.
The Questions
Is what I'm trying to do feasible, if odd? Is it blocked by a security feature (for which I'd be grateful)? If not, what am I doing wrong?
Should I even worry about setting all these different event handlers, or is just listening to click enough?
When an arrow function like your event map is executed the this context is not set, so any code that references this is going to get the current value, including any functions your map calls.
Replace your event map with the following:
['click','mousedown','touchstart'].map(function(evt) { that.on(evt, that.callback} } );
A demonstration:
function Named(x) {
this.name = x;
}
var foo = new Named("foo");
var bar = new Named("bar");
var showFunc = function show() {
// this is context dependant
console.log(this.name);
}
var showArrow;
// this is the window
showArrow = () => console.log(this.name);
var fooShowArrow;
(function() {
// this is foo
that = this;
fooShowArrow = () => console.log(that.name);
}).apply(foo);
var example = function(func) {
// For the demo, at this point, this will always be bar
func.apply(this, [ "arbitrary value" ]);
}
// explicitly set the current "this" to bar for the execution of these functions
example.apply(bar, [showFunc]); // works
example.apply(bar, [showArrow]); // fails, this is still the window
example.apply(bar, [fooShowArrow]); // fails, this is still foo

Javascript inheritance - call to child method always invokes method of parent

This is my first time working with inheritance in Javascript. I have a classical parent-child relation between an object "LatchOn" that does one thing, and an object "LatchOnSlider" that has all the functionality of the base class and then some more. stripped down code:
/*creating the instances*/
var latchon = NewLatchOn(); //arguments not important for this
var latchonslider = NewLatchOnSlider();
//factory function
function NewLatchOn(element_id, container_id, screenpos, release)
{
var newLatchOn = new LatchOn(element_id, container_id, screenpos, release);
newLatchOn.startTimer();
}
function LatchOn(element_id, container_id, screenpos, release)
{
//initialise stuff
}
LatchOn.prototype.startTimer = function()
{
var that = this;
setInterval(function(){that.checkPos()}, 10);
}
LatchOn.prototype.checkPos = function()
{
//do stuff
}
LatchOnSlider.prototype.constructor = LatchOnSlider;
//factory function
function NewLatchOnSlider(element_id, container_id, image_class, screenpos)
{
LatchOnSlider.prototype = Object.create(LatchOn.prototype);
var newSlider = new LatchOnSlider(element_id, container_id, image_class, screenpos);
newSlider.startTimer();
return newSlider;
}
function LatchOnSlider(element_id, container_id, image_class, screenpos)
{
LatchOn.call(this, element_id, container_id, screenpos, "CONTAINER");
//initialise own stuff
}
LatchOnSlider.prototype.startTimer = function()
{
var that = this;
setInterval(function(){that.checkPos()}, 10);
}
/*keeps track of when to switch images*/
LatchOnSlider.prototype.checkPos = function()
{
alert("child process called");
}
The objects have to listen to the scrollposition in the browser and act according to that information. So they have a timer running. But as it wouldn't be optimal for two timers running for the inherited object, I figured I could just run one timer that calls the function on the child object, which will invoke the base function and then do its own stuff (invocation of base function not yet in the code. I haven't gotten that far yet...).
In order to not have to start the timer separately for every instance, I made factory functions to initialise the objects and start their timers. And this is where I'm stuck. No matter what I do, if I call startTimer on the LatchOnSlider object, the function of the parent gets called instead. I've looked through at least five different tutorials and tried all their syntax variations, but nothing fixes the problem. I've walked through it in firebug, the process works as expected up to that point. The constructor of LatchOnSlider gets called, the constructor of the base object gets called from there, everything initialises properly, just when LatchOnSlider.startTimer() is called, LatchOn.startTimer() gets executed instead. I'm pretty much out of ideas as to what might be the problem at this point.
This line is the problem:
function NewLatchOnSlider(element_id, container_id, image_class, screenpos) {
LatchOnSlider.prototype = Object.create(LatchOn.prototype);
Here, you are creating a new prototype object every time an instance is created. Those new prototypes do not have the methods you had assigned on the "old" LatchOnSlider.prototype before, and your instances will not inherit them - only the LatchOn.prototype methods indirectly.
You will need to keep the constructor declaration and the prototype initialisiation separate from your factory function:
function NewLatchOnSlider(element_id, container_id, image_class, screenpos) {
var newSlider = new LatchOnSlider(element_id, container_id, image_class, screenpos);
newSlider.startTimer();
return newSlider;
}
function LatchOnSlider(element_id, container_id, image_class, screenpos) {
LatchOn.call(this, element_id, container_id, screenpos, "CONTAINER");
// initialise own stuff
}
LatchOnSlider.prototype = Object.create(LatchOn.prototype);
LatchOnSlider.prototype.constructor = LatchOnSlider;
LatchOnSlider.prototype.startTimer = function() { … }
LatchOnSlider.prototype.…
For assignments, order matters :-)

Best approach to deal with instances of rectangles to draw separately on canvas

First thing, excuse my absolute lack of knowledge in JavaScript. I'm looking for the best approach for this problem, but after 3 days I think it may be wrong.
I need to write some code to draw moving rectangles in different rows in a canvas. In the future I will need to detect when 2 rectangles are in the same X coordinate, so it's important to keep track of the X values. Coming from Java I thought the best would be to create some rectangle "objects" and with each instance a draw method.
What is causing me trouble is that I thought about calling the draw function with setInterval(), but it appears that every time the function draw is called, the values are not the same.
This is my definition of the Rectangle class:
function Rectangle(x,y,width,height) {
var x=x;
var y= y;
var width= width;
var height= height;
this.getX = function(){
return x;
}
this.setX = function (value) {
x = value;
}
this.getY = function(){
return y;
}
this.setY = function (value) {
y = value;
}
this.getWidth = function(){
return width;
}
this.setWidth = function (value) {
width = value;
}
this.getHeight = function(){
return height;
}
this.setHeight = function (value) {
height = value;
}
this.draw = function(){
if(this.getX() <=canvas.width){
clearContext(this.getX() - 30,this.getY(),this.getWidth(),this.getHeight());
var temp= this.getX()+1;
this.setX(temp);
ctx.fillRect(temp,this.getY(),this.getWidth(),this.getHeight());
}else{
clearInterval(this.draw(),speed);
}
}
}
Then I have a function formSubmit where I create the Rectangles instances when the button is pressed and call respectively the function draw with setInterval():
function formSubmit(){
number=parseInt(document.getElementById("nummerT").value);
rate=parseInt(document.getElementById("rate").value);
speed=parseInt(document.getElementById("speed").value);
confirm(speed);
myRectangle= new Rectangle(0,0,30,30);
myRectangle2 = new Rectangle(0,60,30,30);
setInterval(myRectangle.draw(),speed);
}
The problem is that setInterval(myRectangle.draw(),speed); doesn't do what you think it does. You are calling draw one time, and then the interval is calling the result of draw. You'll need something like:
interval = setInterval(function() {
myRectangle.draw();
}, speed);
You'll note, I set the return value of setInterval to a variable because that is how you'll clear the interval later. You just call
clearInterval(interval);
I don't know if that's going to solve all your problems, but it should at least you get to something that will give you some more information.
A Demo: http://jsfiddle.net/m1erickson/SdPPa/
Your instinct of creating rectangle objects to define what is drawn on the canvas is indeed the common standard.
Unlike Java, JavaScript does not have true classes, but you can create a pseudo-class as you have done in your question.
At it's simplest a Rectangle "class" needs these properties:
x, y
width, height
If you want to animate those rectangles on the canvas you might add:
velocityX, directionY
velocityY, direction
These new properties allow you to move the rectangles like this:
this.x += this.directionX * this.velocityX;
this.y += this.directionY * this.velocityY;
Hint: Html5 now has an excellent animation handler: requestAnimationFrame. You might want to use this instead of setInterval or setTimeout because it gives better performance by integrating itself with the refresh cycle of the browser.
Hint: JavaScript is a prototypal language so you can extend your "class" with methods. The best way to add methods to a "class" is to add them to the classes prototype. That way the methods are created once and shared by all instances of the class rather than having every method recreated on every instance.
So a method to allow a rectangle instance to draw itself to the canvas might look like this:
// draw this rect on the canvas
Rectangle.prototype.render=function(){
ctx.fillStyle=this.color;
ctx.fillRect(this.x,this.y,this.width,this.height);
return(this);
}
Hint: JavaScript "class" methods can be chained if you always return(this). A good use of chaining might be calling a move method on an instance and then chaining on the render method.
rectangle1.move().render();
There's lots to learn about javascript "classes".
Here's annotated code to start with:
Good luck with your project!
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// an array to hold all rectangle objects
var rectangles=[];
// a rectangle pseudo-class (javascript does not have actual classes)
function Rectangle(stdProperties) {
addProperties(this,stdProperties);
this.color=randomColor();
};
//
// Add methods that apply to all instance rectangles
// to Rectangle.prototype so those methods are
// created once for all instances instead of
// repeatedly for every instance.
//
// set x,y,width,height of this rectangle
Rectangle.prototype.init=function(x,y,width,height){
this.x=x;
this.y=y;
this.width=width;
this.height=height;
return(this);
};
// move this rectangle by its preset delta-x and delta-y
Rectangle.prototype.move=function(){
var maxRight=canvas.width-this.width;
var maxBottom=canvas.height-this.height;
this.x+=this.directionX*this.velocityX;
if(this.x<0){ this.x=0; this.directionX*=-1}
if(this.x>maxRight){ this.x=maxRight; this.directionX*=-1}
this.y+=this.directionY*this.velocityY;
if(this.y<0){ this.y=0; this.directionY*=-1}
if(this.y>maxBottom){ this.y=maxBottom; this.directionY*=-1}
return(this);
};
// draw this rect on the canvas
Rectangle.prototype.render=function(){
ctx.fillStyle=this.color;
ctx.fillRect(this.x,this.y,this.width,this.height);
return(this);
}
// create a new rectangle object from the Rectangle "class"
function newRect(x,y,width,height){
// define default properties for Rectangle
var DefaultRectangleProperties={
x:0,y:0,width:10,height:10,
velocityX:1,velocityY:1,directionX:1,directionY:1,
color:"black",
}
// new-up a Rectangle
var rect = new Rectangle(DefaultRectangleProperties);
// set the x,y,width,height & draw it on the canvas
rect.init(x,y,width,height).render();
// return(this) to allow chaining
return(rect);
}
// TESTING
// create 5 rectangles with some randomness
for(var i=0;i<5;i++){
var rect=newRect(Math.random()*200,Math.random()*200,40,50);
rect.velocityX=Math.random()*2;
rect.velocityY=Math.random()*3;
rectangles.push(rect);
}
// animate the rectangles using requestAnimationFrame
animate();
// the animation loop
function animate(t){
// request another animation frame
requestAnimationFrame(animate);
// clear the canvas
// move all the rectangles by their preset distance
// redraw all the rectangles
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<rectangles.length;i++){
rectangles[i].move().render();
}
}
///////////////////////////////////
// Utilities
///////////////////////////////////
// create getters/setters on the specified object
// using the supplied properties object
//
function addProperties(object,properties){
for (var i in properties) {
(function(i) {
Object.defineProperty(object, i, {
get: function(){ return properties[i]; },
set: function(val){ properties[i] = val; }
})
})(i);
}
}
// generate a random color
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I have not so much to add to the other answers (+1 to both) but just a note on this part:
function Rectangle(x,y,width,height) {
var x=x;
var y= y;
var width= width;
var height= height;
...
When you do Rectangle(x, y, ...) the compiler/parser will actually do this for you (or rather, the equivalent of):
var x = arguments[0]; // x declared internally, no need to manually declare it
var y = arguments[1]; // y declared too, etc.
...
so you do not need to declare the variables in the function signature as they are already declared - or just leave the signature without any parameters and do the assigning manually (a tad slower but fully legal).
function Rectangle() {
var x = arguments[0]; // legal but not recommended (in most cases)
var y = arguments[1];
...
So, in conclusion - the recommended approach in this case would be:
function Rectangle(x,y,width,height) {
// no x,y, width and height decl. here - they're declared by signature
this.getX = function(){
return x;
}
...
Second issue: setInterval will need a reference to a function. As it is now the function will invoked due to placing the to parenthesis at the end and the result of that function will be handed as a reference instead.
You can call it like:
setInterval(myRectangle.draw, speed); // only a reference, no parenthesis
But in order to enable cancelling of it you need to store the timer ID:
var timerID; // global scope
...
timerID = setInterval(myRectangle.draw, speed);
Then use that request to cancel it later:
clearInterval(timerID);
I would too recommend using requestAnimationFrame as this is optimized for animation and monitor sync.
Contrary to setInterval you'll need to call it per frame inside your animation loop. You can use a flag/condition to not call it again when you want to end the animation.
You have also a clearContext method in there - I assume you have that defined elsewhere in the code, if not, check out context.clearRect().

Javascript, MouseEvents and Classes

With all the buzz of HTML5 I've began by investigating the Canvas's capabilities along with interaction from Javascript. Unfortunately things haven't been going well due to idiosyncrasies of Javascript and its OO model.
For instance, I figured I could create a wrapper class for my canvas object and effectively box all appropriate methods and properties into it making the development side of things much easier. Unfortunately I'm struggling with the way the mouse handlers are working. In my case, I have the 'DrawArea' class that adds three mouse handlers for drawing rectangles and a 'Draw' routine titled 'Invalidate'. When the mouse events are fired (mouseMove and mouseUp methods), they fail claiming that the 'Invalidate' function is invalid - almost like it is out of context of the method it is being called within. Code below.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript">
// Top level variables
var dWrap;
// Point Class
function Point( xPos , yPos ){
this.X = xPos;
this.Y = yPos;
}
// Create wrapper class for the draw area
function DrawArea( da ){
this.SrcArea = da;
// Add mouse handlers
this.SrcArea.addEventListener('mousedown', this.mouseDown, false);
this.SrcArea.addEventListener('mousemove', this.mouseMove, false);
this.SrcArea.addEventListener('mouseup', this.mouseUp, false);
// And draw
// NOTE: this call works!
this.Invalidate();
}
// Properities
DrawArea.prototype.ProposedStartPos = undefined;
DrawArea.prototype.ProposedEndPos = undefined;
DrawArea.prototype.IsDrawing = false;
// Mouse Events
// Handles the mouse down event for new objects
DrawArea.prototype.mouseDown = function(m) {
// Flag as drawing
this.IsDrawing = true;
// Record the start position
this.ProposedStartPos = new Point(m.layerX, m.layerY);
}
// Handles mouse movement when creating a proposed object
DrawArea.prototype.mouseMove = function(m) {
if (this.IsDrawing) {
// Set the current end position
this.ProposedEndPos = new Point(m.layerX, m.layerY);
// NOTE: this call doesn't work!
this.Invalidate();
}
}
// Handles the completion of a proposed object
DrawArea.prototype.mouseUp = function(m) {
if (this.IsDrawing) {
// Set the final end position
if (m.type != 'mouseout') this.ProposedEndPos = new Point(m.layerX, m.layerY);
// NOTE: this call doesn't work!
this.Invalidate();
}
}
// Redraws the source object
DrawArea.prototype.Invalidate = function() {
// Obtain
if (this.SrcArea.getContext) {
var context = this.SrcArea.getContext('2d');
// Clean up
context.clearRect(0, 0, this.SrcArea.width, this.SrcArea.height);
context.save();
// Draw the background
context.strokeStyle = "#000000";
context.fillStyle = "#AAAFFF";
context.beginPath();
context.rect(0, 0, this.SrcArea.width, this.SrcArea.height);
context.closePath();
context.stroke();
context.fill();
// Are we drawing any proposed items
if (this.IsDrawing) {
context.strokeStyle = this.ProposedColorStroke;
context.fillStyle = this.ProposedColorFill;
context.beginPath();
context.rect(this.ProposedStartPos.X, this.ProposedStartPos.Y, this.ProposedEndPos.X - this.ProposedStartPos.X, this.ProposedEndPos.Y - this.ProposedStartPos.Y);
context.closePath();
context.stroke();
context.fill();
}
}
// Flush
context.restore();
}
// Initialise the wrapper class
$(document).ready(function() {
// Obtain the canvas and set
var cWrap = $('#cDrawArea')[0];
dWrap = new DrawArea( cWrap );
});
Html code...
<body>
<div id="DrawContainer">
<canvas id="cDrawArea" width="800" height="600"></canvas>
</div>
</body>
What am I missing here and is this a particular efficient and smart way of handling complex objects that will require a lot of behind the scenes code?
This is a common misunderstanding. JavaScript doesn't have classes, and it doesn't have methods. It has functions. Unlike some other languages (Java, C#, C++), this is determined entirely by how a function is called, not where a function is defined. (This is incredibly powerful, but surprising to someone coming from class-based languages.) So this line of code:
this.SrcArea.addEventListener('mousedown', this.mouseDown, false);
...does hook up the function referenced by the mouseDown property, but does nothing to ensure that when that function is called, this is the value you expect.
If you're really using an ECMAScript5-compliant browser (there are some that have canvas but are not completely ES5-compliant), you can use the new Function#bind feature, but again note that this is only about two years old:
// Create wrapper class for the draw area
function DrawArea( da ){
this.SrcArea = da;
// Add mouse handlers using ECMAScript5's new `Function#bind`
this.SrcArea.addEventListener('mousedown', this.mouseDown.bind(this), false);
this.SrcArea.addEventListener('mousemove', this.mouseMove.bind(this), false);
this.SrcArea.addEventListener('mouseup', this.mouseUp.bind(this), false);
// And draw
// NOTE: this call works!
this.Invalidate();
}
Alternately, you can do pretty much the same thing yourself using closures:
// Create wrapper class for the draw area
function DrawArea( da ){
var self = this; // Set up a variable referencing the instance
this.SrcArea = da;
// Add mouse handlers - these are closures over the context of this
// call to the constructor, and have access to the `self` variable
// above. They just relay the call to the functions on the prototype,
// but in a way that ensures that `this` is what you expect.
this.SrcArea.addEventListener('mousedown', function(event) {
return self.mouseDown(event);
}, false);
this.SrcArea.addEventListener('mousemove', function(event) {
return self.mouseMove(event);
}, false);
this.SrcArea.addEventListener('mouseup', function(event) {
return self.mouseUp(event);
}, false);
// And draw
// NOTE: this call works!
this.Invalidate();
}
More reading:
Mythical methods
You must remember this
Closures are not complicated
Try:
this.SrcArea.addEventListener('mousedown', this.mouseDown.bind(this), false);
this.SrcArea.addEventListener('mousemove', this.mouseMove.bind(this), false);
this.SrcArea.addEventListener('mouseup', this.mouseUp.bind(this), false);
The "bind()" method on the Function prototype (should be in any browser with <canvas> I think) returns a function that will force the this value to be the parameter you pass, in this case your wrapper object instance.
If you don't do something like that, then the handler won't have the this you expect.
The this is not the DrawArea instance in the handler, but the element itself.
You should bind (freeze) the this value with bind. This is the easiest, but is not available in all browsers. There is a shim available, though.
// guarantee the 'this' value inside handler
this.SrcArea.addEventListener('mousedown', this.mouseDown.bind(this), false);
http://jsfiddle.net/KdnZC/

Categories