Source: controls/Pointer.js

import ScenePlugin from '../core/ScenePlugin.js';

/**
 * Unified mouse and touch input.
 *
 * @extends module:core~ScenePlugin
 * @memberof module:controls~
 * @fires module:controls~Pointer#pointerdown
 * @fires module:controls~Pointer#pointermove
 * @fires module:controls~Pointer#pointerup
 */
class Pointer extends ScenePlugin {

    /**
     * Adds the necessary touch and mouse event listeners.
     */
    init()
    {
        let canvas = this.scene.engine.canvas;

        this.mouseDownHandler = this.onMouseDown.bind(this);
        canvas.addEventListener('mousedown', this.mouseDownHandler);

        this.touchStartHandler = this.onTouchStart.bind(this);
        canvas.addEventListener('touchstart', this.touchStartHandler);

        this.mouseMoveHandler = this.onMouseMove.bind(this);
        canvas.addEventListener('mousemove', this.mouseMoveHandler);

        this.touchMoveHandler = this.onTouchMove.bind(this);
        canvas.addEventListener('touchmove', this.touchMoveHandler);

        this.mouseUpHandler = this.onMouseUp.bind(this);
        canvas.addEventListener('mouseup', this.mouseUpHandler);

        this.touchEndHandler = this.onTouchEnd.bind(this);
        canvas.addEventListener('touchend', this.touchEndHandler);

        /**
         * Wether or not the pointer is currently down.
         *
         * @type {boolean}
         */
        this.isDown = false;
    }

    /**
     * Called internally when a the mouse goes down.
     *
     * @param {object} e - The native javascript event object.
     */
    onMouseDown(e)
    {
        this.isDown = true;
        let clientX = e.clientX;
        let clientY = e.clientY;
        let name = 'pointerdown';
        this.emitPointerEvent({name, clientX, clientY});
    }

    /**
     * Called internally when a the finger goes down.
     *
     * @param {object} e - The native javascript event object.
     */
    onTouchStart(e)
    {
        this.isDown = true;
        e.preventDefault();
        let clientX = e.changedTouches[0].clientX;
        let clientY = e.changedTouches[0].clientY;
        let name = 'pointerdown';
        this.emitPointerEvent({name, clientX, clientY});
    }

    /**
     * Called internally when a the mouse moves.
     *
     * @param {object} e - The native javascript event object.
     */
    onMouseMove(e)
    {
        let clientX = e.clientX;
        let clientY = e.clientY;
        let name = 'pointermove';
        this.emitPointerEvent({name, clientX, clientY});
    }

    /**
     * Called internally when a the finger moves.
     *
     * @param {object} e - The native javascript event object.
     */
    onTouchMove(e)
    {
        e.preventDefault();
        let clientX = e.changedTouches[0].clientX;
        let clientY = e.changedTouches[0].clientY;
        let name = 'pointermove';
        this.emitPointerEvent({name, clientX, clientY});
    }

    /**
     * Called internally when the mouse goes up.
     *
     * @param {object} e - The native javascript event object.
     */
    onMouseUp(e)
    {
        this.isDown = false;
        let clientX = e.clientX;
        let clientY = e.clientY;
        this.emitPointerEvent({clientX, clientY});
    }

    /**
     * Called internally when the finger goes up.
     *
     * @param {object} e - The native javascript event object.
     */
    onTouchEnd(e)
    {
        this.isDown = false;
        e.preventDefault();
        let clientX = e.changedTouches[0].clientX;
        let clientY = e.changedTouches[0].clientY;
        this.emitPointerEvent({clientX, clientY});
    }

    /**
     * Calculates the events positions within the game, based on the native mouse or touch position and then emits the event.
     *
     * @param {object} e - An object containing the name of the event to emit and position data of the native event.
     * @param {object} e.name - The name of the event to emit.
     * @param {number} e.clientX - The native events x position relative to the browser window.
     * @param {number} e.clientY - The native events y position relative to the browser window.
     *
     */
    emitPointerEvent({name = 'pointerup', clientX = 0, clientY = 0} = {})
    {
        let rect = this.scene.engine.canvas.getBoundingClientRect();
        let x = (clientX - rect.left);
        let y = (clientY - rect.top);
        let viewportX = x / this.scene.viewport.zoom;
        let viewportY = y / this.scene.viewport.zoom;
        let worldX = viewportX + this.scene.offset.x;
        let worldY = viewportY + this.scene.offset.y;
        /**
         * Pointer down event.
         *
         * @event module:controls~Pointer#pointerdown
         * @type {object}
         * @property {number} viewportX - The x position relative to the top left of the scene's viewport.
         * @property {number} viewportY - The y position relative to the top left of the scene's viewport.
         * @property {number} worldX - The x position relative to the scene's origin.
         * @property {number} worldY - The y position relative to the scene's origin.
         */
        /**
         * Pointer move event. On mobile this event only fires when the pointer is down.
         * This is not the case on desktop. But you can check for the [isDown]{@link module:controls~Pointer#isDown} property
         *
         * @event module:controls~Pointer#pointermove
         * @type {object}
         * @property {number} viewportX - The x position relative to the top left of the scene's viewport.
         * @property {number} viewportY - The y position relative to the top left of the scene's viewport.
         * @property {number} worldX - The x position relative to the scene's origin.
         * @property {number} worldY - The y position relative to the scene's origin.
         */
        /**
         * Pointer up event.
         *
         * @event module:controls~Pointer#pointerup
         * @type {object}
         * @property {number} viewportX - The x position relative to the top left of the scene's viewport.
         * @property {number} viewportY - The y position relative to the top left of the scene's viewport.
         * @property {number} worldX - The x position relative to the scene's origin.
         * @property {number} worldY - The y position relative to the scene's origin.
         */
        this.emit(name, {viewportX, viewportY, worldX, worldY});
    }

    /**
     * Removes all mouse and touch event listeners.
     */
    shutdown()
    {
        super.shutdown();

        let canvas = this.scene.engine.canvas;
        canvas.removeEventListener('mousedown', this.mouseDownHandler);
        canvas.removeEventListener('touchstart', this.touchStartHandler);
        canvas.removeEventListener('mousemove', this.mouseMoveHandler);
        canvas.removeEventListener('touchmove', this.touchMoveHandler);
        canvas.removeEventListener('mouseup', this.mouseUpHandler);
        canvas.removeEventListener('touchend', this.touchEndHandler);

        this.isDown = false;
    }
}
export default Pointer;