0

I thought I fixed it but looks like not. Heres whats happening:

The canvas.mousemove event is handled by viewport.onMouseMove.bind(viewport) function (viewport is an instance of a class).

At the end of the onMouseMove function it calls this.Draw() (referring to viewport.Draw() function).

viewport.Draw() loops through all the items and calls Items[i].Draw(ctx) on each of them where ctx is a back buffer canvas context.

Now if If the item that is being drawn goes ahead and uses the ctx to draw something right there and then (in its Draw function), using this to refer to itself, everything works fine. For example

this.Draw = function(ctx) {
    ctx.beginPath();
    ctx.moveTo(this.x1, this.y1);
    ctx.lineTo(this.x2, this.y2);
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#000000";
    ctx.stroke();
};

However, if the object is a container that has items in itself and tries to loop and draw them like this

this.Draw = function(ctx) {
    for (j = 0; j < this.Items.length; j++) {
        this.Items[j].Draw(ctx);
    }
};

When it gets into the Items[j].Draw, "this" loses all meaning. alert(this) produces "object object" and I cant figure out what its referring to (it's not the viewport nor the container nor the item it needs to be). Also another weird thing - I had to change the container object loop to use j instead of i because otherwise it would create a perpetual loop (like the i's of the viewport.draw and item[i].draw were the same).

soktinpk
  • 3,778
  • 2
  • 22
  • 33
Jake Freelander
  • 1,471
  • 1
  • 19
  • 26
  • 3
    `alert` is a horrible debugging tool. Don't use it. Use `console.log(this)`, then check your browser's console (usually Ctrl+Shift+J). – gen_Eric Jul 14 '14 at 21:49
  • the result is the same in this case – Jake Freelander Jul 14 '14 at 21:49
  • its an array of various object instances that have .Draw function – Jake Freelander Jul 14 '14 at 21:50
  • If you console.log the value of `this` (not in IE) you could see the value is not your object. That is because the value of `this` is the invoking object. It's determined when you call/invoke the function not when you declare it. The fact that you have this.Draw = function would suggest you don't know about prototype and how to capitalize your functions. Constructors are capitalized but callable functions should not. More on prototype and the value of `this` here: http://stackoverflow.com/a/16063711/1641941 – HMR Jul 15 '14 at 03:54

2 Answers2

1

Your question is somewhat unclear. Is this.Items an array of objects with the same prototype as this? ie. nested? Also, is the j counter intended to be shared?

Regardless, function contexts' this values can be changed rather easily to whatever you need them to be with the .apply and .call functions:

this.Draw = function(ctx) {
    for (var j = 0; j < this.Items.length; j++) {
        // These two are the same as what you have in the question
        this.Draw.call(this.Items[j], ctx);
        this.Draw.apply(this.Items[j], [ctx]);
        // This is what you had in the question if Draw is different for Items:
        this.Items[j].Draw(ctx);
        this.Items[j].Draw.call(this.Items[j], ctx);
        // Will preserve the this reference within the nested call
        this.Items[j].Draw.call(this, ctx);
    }
};
blgt
  • 8,135
  • 1
  • 25
  • 28
  • the prototype can be same but in my test case its not. The objects in Items array have various prototypes, only really common thing they have is the .Draw function. And no i is not intended to be shared. – Jake Freelander Jul 14 '14 at 22:16
  • Well in that case referring to `this` within the body of `this.Items[j].Draw` will refer to the `Items[j]` object. Wasn't that what you intended? (as for `j`, just put the `var` declaration like above) – blgt Jul 14 '14 at 22:25
0

Not sure what the problem is but as my comment suggest this is the invoking object:

//this in someFunction is window
setTimeout(myObject.someFunction, 200);
//this in someFunction is button
button.onClick=myObject.someFunction;

Not sure what you would like this to be when it's called but if it has to be Items[j] then your code is fine and maybe something else is causing you problems. I suggest console.log objects in Chrome or Firefox with firebug, use F12 to open the console and inspect the logged objects.

Here is sample code of items that can be Square or Circle;

var Shape = function Shape(args){
  //args.x1 or y1 can be 0, defaults to 2
  this.x1 = (args.x1 === undefined)? 2:args.x1;
  this.y1 = (args.y1 === undefined)? 2:args.y1;
  this.name = args.name||"unnamed";
}
//in this example Square and Cirle draw does the same
// so they can inherit it from Shape
Shape.prototype.draw=function(){
  console.log("this x1:",this.x1,"this y1:",this.y1,"name",this.name);
  //you can log complex values as well and click on them in the console
  // to inspect the details of the complex values (objects)
  // the above can be done in the following log
  console.log("in draw, this is:",this);
}
var Square = function Square(args){
  //re use parent constructor (parent is Shape)
  Shape.call(this,args);
}
//set prototype part of inheritance and repair constructor
Square.prototype=Object.create(Shape.prototype);
Square.prototype.constructor=Square;

var Circle = function Circle(args){
  //re use parent constructor (parent is Shape)
  Shape.call(this,args);
}
//set prototype part of inheritance
Circle.prototype=Object.create(Shape.prototype);
Circle.prototype.constructor=Circle;
//there is only one app so will define it as object literal
var app = {
  items:[],
  init:function(){
    var i = -1;
    while(++i<10){
      this.items.push(new Circle({x1:i,y1:i,name:"circle"+i}));
    }
    while(++i<20){
      this.items.push(new Square({x1:i,y1:i,name:"square"+i}));
    }
  },
  draw:function(){
    var i = -1;len=this.items.length;
    while(++i<len){
      this.items[i].draw();
    }
  }
}
app.init();
app.draw();//causes console.logs
HMR
  • 37,593
  • 24
  • 91
  • 160