2

How can I access ctx in the function loadImage? I have seen snippets that worked exactly like this but It just doesn't work when I try it. It always says 'this' or 'this.ctx' or 'ctx' is undefined.

var MyClass= function(canvasId){
  var canvas = document.getElementById(canvasId);
  var ctx = canvas.getContext("2d");
};
MyClass.prototype.loadImage = function(imageSrc){
    var image = new Image();
    image.src = imageSrc;
    //cannot access this or ctx
    image.onload = function(){
        this.ctx.drawImage(image,0,0);
    };
    //can't even access it here:
    ctx.drawImage(image,0,0);

};
//window.onload = function(){
 var myObject= new MyClass("myCanvas");
 myObject.loadImage('myImage.jpg');
flawr
  • 10,814
  • 3
  • 41
  • 71
  • You can't access `ctx` in `loadImage` unless you were to move the definition for `loadImage` into the function definition of `MyClass`, or declare `ctx` outside of `MyClass`. – crush Oct 22 '14 at 21:14

2 Answers2

2

How can I access ctx in the function loadImage?

You cannot. Unless you create the loadImage function inside the constructor's scope. See Javascript: Do I need to put this.var for every variable in an object? for details.

I have seen snippets that worked exactly like this

Then those snippets didn't work either.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • What other structure of the program would you recommend, if you want to have multiple methods accessing `ctx`? – flawr Oct 22 '14 at 21:20
  • 1
    I would recommend Bergi's structure...using `this.loadImage = function() {}` inside of your function ctor. Your other option is to wrap everything in a closure, and move `ctx` outside of the function ctor, but then `ctx` becomes "shared". – crush Oct 22 '14 at 21:21
  • Thank you very much, that explained a lot! – flawr Oct 22 '14 at 21:24
  • 1
    @crush Also putting `ctx` as prototype property would have the same effect. But having shared `ctx` is probably not ideal at all. As I can see that there can be different canvases, hence different 2d contexts. – dfsq Oct 22 '14 at 21:25
  • I've also seen some libraries use naming convention as a method of restricting visibility, though, it depends on the knowledge and restraint of the developer to enforce. For example, they'd do `this._ctx` where the `_` denotes that `ctx` is meant to be private scope. This kind of programming is generally a code smell in my opinion. I'd highly recommend that you DON'T follow that practice. – crush Oct 22 '14 at 21:27
1

The only way you can access ctx from proptotype methods is to set it as an instance property using this keyword.

var MyClass = function (canvasId) {
    this.canvas = document.getElementById(canvasId);
    this.ctx = this.canvas.getContext("2d");
};

MyClass.prototype.loadImage = function (imageSrc) {
    var image = new Image();
    image.src = imageSrc;

    var self = this;
    image.onload = function () {
        self.ctx.drawImage(image, 0, 0);
    };

    this.ctx.drawImage(image, 0, 0);
};

Note that inside image onload handler you have different context: this no longer points to MyClass instance, but rather to image object instance. You can overcome it for example by saving a reference to proper this in some variable like self.

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • usage* not declaration :P – crush Oct 22 '14 at 21:17
  • @crush: It could (should?) have been `var canvas` still – Bergi Oct 22 '14 at 21:18
  • This answer makes `ctx` public visibility now, by the way. Bergi's is the only real solution besides moving the var into a closure outside of the class "ctor". – crush Oct 22 '14 at 21:18
  • Thanks your answer! You said `this.ctx` makes `ctx` an instance property. Does that mean that `var ctx` will be an static property that is the same for every instance of `MyClass`? – flawr Oct 22 '14 at 21:18
  • No, `var` would make just local scope variable which will not be available outside. – dfsq Oct 22 '14 at 21:19
  • @flawr `var ctx` would be local to the function, whereas `this.ctx` is assigned to the instance. – crush Oct 22 '14 at 21:19
  • Static property would be `MyClass.ctx` which is not what you want, because you probably want to have different canvases and ctx's per MyClass instances. – dfsq Oct 22 '14 at 21:20
  • Ah ok now I understand, thank you very much for answering (so fast!) I didn't expect to get overrun with answers so quickly!!! – flawr Oct 22 '14 at 21:23