javascriptcanvasdom-eventsmodule-pattern

How can I call functions from module patterns from an event function


I am experimenting with the Javascript module pattern and the html5 canvas by making a simple html5 based game and have run into my first obstacle. I am listening for a mousemove event over a canvas.

init: function () {
    var gameCanvas = document.getElementById("gameCanvas");
    gameCanvas.addEventListener("mousemove", this.redrawAvatar);
}

What I'm doing is letting my avatar follow the movement of the mousepointer over the canvas.

The problem then is that I have several functions in my module which I wish to call from inside the redrawAvatar function, like so:

redrawAvatar: function (mouseEvent) {
    var gameCanvas = document.getElementById("gameCanvas"),
    avatarCoord = {x: mouseEvent.offsetX, y: mouseEvent.offsetY},
    enemyCoord = {x: 100, y: 100};

    this.clear(gameCanvas);
    this.drawAvatar(avatarCoord);
    this.drawEnemy(enemyCoord);

    if (that.isCollision({coord: avatarCoord, size: 30}, {coord: enemyCoord, size: 30})) {
       alert("Avatar died, collided with enemy");
    }
}

While inside redrawAvatar the this object is not my module anymore but is instead the source of the event (the canvas in this case).

Here is the essence of my module:

var MyGame = (function () {

    var Game = {

        draw: function (image, coord) {},

        drawAvatar: function (coord) {},

        clear: function (canvas) { canvas.width = canvas.width + 1 - 1;},

        drawEnemy: function (xPos, yPos) {},

        isCollision: function (a, b) {},

        redrawAvatar: function (mouseEvent) {
            var gameCanvas = document.getElementById("gameCanvas"),
                avatarCoord = {x: mouseEvent.offsetX, y: mouseEvent.offsetY},
                enemyCoord = {x: 100, y: 100};

            this.clear(gameCanvas);
            this.drawAvatar(avatarCoord);
            this.drawEnemy(enemyCoord);
            if (that.isCollision({coord: avatarCoord, size: 30}, {coord: enemyCoord, size: 30})) {
                alert("Avatar died, collided with enemy");
            }
        },

        init: function () {
            var gameCanvas = document.getElementById("gameCanvas");
            gameCanvas.addEventListener("mousemove", this.redrawAvatar);
        }
    };

    (function () {
        var that = Game;
        that.init();
    }());

}());

How do I get to the functions in my module which I would like to call?


Solution

  • You can use bind to use the current context (in your case the game module) in the function as opposed to the event's context.

    gameCanvas.addEventListener("mousemove", this.redrawAvatar.bind(this));
    

    Here is a basic demo reproducing the binding effect. It uses a click event.

    var MyGame = (function () {
            var Game = {
                scoped: 5,
                redrawAvatar: function (mouseEvent) {
                 alert(this.scoped);
                },
    
                init: function () {
                    var gameCanvas = document.getElementById("d");
                    gameCanvas.addEventListener("click", this.redrawAvatar.bind(this));
                }
            };
            (function () {
                var that = Game;
                that.init();
            }());
        }());
    <div id="d">Basic element for click handler (click for demo)</div>

    Run code snippet or jsFiddle Demo