0

I've got the following class that initializes a canvas element for mouse events. The listeners are initialized in the constructor but when I call findxy when the event is fired, the references to variables like this.flag result in an error because they are undefined which leads me to believe the listener is losing its reference to this when calling findxy. I'm not entirely sure how to fix this. Thanks in advance.

class Signature {
  constructor() {
    this.signed = false;
    this.prevX = 0;
    this.currX = 0;
    this.prevY = 0;
    this.currY = 0;
    this.dot_flag = false;
    this.flag = false;
    this.canvas = document.getElementById('can');

    this.ctx = this.canvas.getContext("2d");
    this.w = this.canvas.width;
    this.h = this.canvas.height;

    this.canvas.addEventListener("touchmove", function(e) {
      mobilexy('move', e)
    }, false);
    
    this.canvas.addEventListener("touchstart", function(e) {
      mobilexy('down', e)
    }, false);
    
    this.canvas.addEventListener("touchleave", function(e) {
      mobilexy('up', e)
    }, false);

    this.canvas.addEventListener("mousemove", function(e) {
      findxy('move', e)
    }, false);
    
    this.canvas.addEventListener("mousedown", function(e) {
      findxy('down', e)
    }, false);
    
    this.canvas.addEventListener("mouseup", function(e) {
      findxy('up', e)
    }, false);
    
    this.canvas.addEventListener("mouseout", function(e) {
      findxy('out', e)
    }, false);

    findxy(res, e) {
      if (res == 'down') {
        this.prevX = this.currX;
        this.prevY = this.currY;
        this.currX = e.pageX - this.canvas.offsetLeft;
        this.currY = e.pageY - this.canvas.offsetTop;

        this.flag = true;
        this.dot_flag = true;
        
        if (this.dot_flag) {
          this.ctx.beginPath();
          this.ctx.fillStyle = x;
          this.ctx.fillRect(currX, currY, 2, 2);
          this.ctx.closePath();
          this.dot_flag = false;
        }
      }
      
      if (res == 'up' || res == "out") {
        this.flag = false;
      }
      
      if (res == 'move') {
        if (this.flag) {
          this.prevX = this.currX;
          this.prevY = this.currY;
          this.currX = e.pageX - canvas.offsetLeft;
          this.currY = e.pageY - canvas.offsetTop;
          draw();
        }
      }
    }
  }

My error:

Uncaught ReferenceError: flag is not defined
at findxy (jobs.self-09776d4c973306a740403ee614a19882dd0d4d402c0c72bba61747ef44c6ab2b.js?body=1:191)
at HTMLCanvasElement. (signature.self-e4f9a6f8d0069a7e6488dd64f3234fbdf4b0c2004f9de362da627d0176111f06.js?body=1:31)
findxy @ jobs.self-09776d4c973306a740403ee614a19882dd0d4d402c0c72bba61747ef44c6ab2b.js?body=1:191
(anonymous) @ signature.self-e4f9a6f8d0069a7e6488dd64f3234fbdf4b0c2004f9de362da627d0176111f06.js?body=1:31 09:37:56.162

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
Cannon Moyer
  • 3,014
  • 3
  • 31
  • 75

1 Answers1

5

Scope does not transfer with calls. You need to either pass the this reference as an argument:

this.canvas.addEventListener("mouseout", function (e) {
  findxy('out', e, this)
}, false); 

findxy(res, e, _this) {
  // call it something more appropriate than '_this' - this is just an example
  _this.prevY = ...;
}

Or use call() to provide a scope:

this.canvas.addEventListener("mouseout", function (e) {
  findxy.call(this, 'out', e)
}, false); 

Or use jQuery's alternative to call(), which is $.proxy():

this.canvas.addEventListener("mouseout", function (e) {
  $.proxy(findxy, this, 'out', e)();
}, false); 
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • I tried all three methods. The first doesn't seem to do anything. I'm not sure why, but I can't even get a `console.log("test");` to print out at the beginning of `findxy`. The other methods produced the same error as indicated in the question. – Cannon Moyer Dec 03 '18 at 16:12
  • If `flag` is causing the error but the other methods aren't (eg. `prevX`, `currX` etc.) then I would suggest you `console.log(this)` in the `findxy()` to determine exactly what's being passed is what you expect it to be. Note that within the event handlers, `this` will be the element which raised the event, not your `Signature` class, if that was your intention – Rory McCrossan Dec 03 '18 at 16:17