Source: canvasController.js

/** 
 * Class creates listeners for a range of user events on the canvas.
 * This class is responsible for setting up and implimenting listeners for different sets of actions performed
 * on the canvas area. Including zooming, rotating and moving around the scene.
 * @name CanvasController
 * @class CanvasController
 * @constructor
 */
define(function() {

    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;
    var renderer;
    var camera;
    var targetRotationY = 0;
    var targetRotationOnMouseDownY = 0;
    var targetRotationX = 0;
    var targetRotationOnMouseDownX = 0;
    var mouseX = 0;
    var mouseXOnMouseDown = 0;
    var mouseY = 0;
    var mouseYOnMouseDown = 0;
    var scale = 1;
    var getLatestMoveX = 0;
    var getLatestMoveZ = 0;

    /**
     * Event that calculates the rotation and movement performed by the user starting from the mouse down to 
     * mouse up events. Sets global variables holding these values for use in the get methods used by the 
     * {@link Main} class.
     * @name CanvasController#onDocumentMouseDown
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentMouseDown(event) {
        event.preventDefault();
        renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false);
        renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false);
        renderer.domElement.addEventListener('mouseup', onDocumentMouseUp, false);
        renderer.domElement.addEventListener('mouseout', onDocumentMouseOut, false);
        mouseXOnMouseDown = event.clientX - windowHalfX;
        mouseYOnMouseDown = event.clientY - windowHalfY;
        targetRotationOnMouseDownX = targetRotationX;
        targetRotationOnMouseDownY = targetRotationY;
    }

    /**
     * Multiplies the rotating by 0.02 each time the mouse is moved whilst held down on the canvas.
     * @name CanvasController#onDocumentMouseMove
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentMouseMove(event) {
        mouseX = event.clientX - windowHalfX;
        mouseY = event.clientY - windowHalfY;
        targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.02;
        targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.02;
    }

    /**
     * Removes the listeners for mouse events once a user releases the mouse click button on the canvas.
     * @name CanvasController#onDocumentMouseUp
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentMouseUp(event) {
        renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
        renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
        renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
    }

    /**
     * Removes the listeners for mouse events once a user moves the mouse out of the canvas.
     * @name CanvasController#onDocumentMouseOut
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentMouseOut(event) {
        renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
        renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
        renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
    }

    /**
     * Adds the listener for different mouse actions once a user clicks onto the canvas, holding the mouse down/
     * @name CanvasController#onDocumentTouchStart
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentTouchStart(event) {

        if (event.touches.length == 1) {
            event.preventDefault();
            mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
            targetRotationOnMouseDownX = targetRotationX;
            mouseYOnMouseDown = event.touches[0].pageY - windowHalfY;
            targetRotationOnMouseDownY = targetRotationY;
        }
    }

    /**
     * Alternative event for calculating rotation, for touch devices. Will work on phones and rotate scene 
     * when user drags across the screen.
     * @name CanvasController#onDocumentTouchMove
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onDocumentTouchMove(event) {

        if (event.touches.length == 1) {
            event.preventDefault();
            mouseX = event.touches[0].pageX - windowHalfX;
            targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.05;
            mouseY = event.touches[0].pageX - windowHalfX;
            targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.05;
        }
    }

    /**
     * Resizes the canvas in relation to the window size. Resizes all the objects too, and changes the 
     * camera perspective to view from the correct range.
     * @name CanvasController#onWindowResize
     * @function
     *
     */
    function onWindowResize() {
        windowHalfX = window.innerWidth;
        windowHalfY = window.innerHeight;
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    /**
     * Updates the camera zoom parameter based on the amount scrolled. Has a maximum and minimum value of scroll.
     * @name CanvasController#onMouseScroll
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onMouseScroll(event) {
        var event = window.event || e; // old IE support
        var d = ((typeof event.wheelDelta != "undefined") ? (-event.wheelDelta) : event.detail);
        d = 100 * ((d > 0) ? 1 : -1);
        var cPos = camera.position;
        if (isNaN(cPos.x) || isNaN(cPos.y) || isNaN(cPos.y)) 
            return;
        if (cPos.x > 1 || cPos.x < 0) {
            return;
        }
        mb = d > 0 ? 1.1 : 0.9;
        cPos.x = cPos.x * mb;
        cPos.y = cPos.y * mb;
        cPos.z = cPos.z * mb;
        camera.updateProjectionMatrix();
    }

    /**
     * A listener to run each time the up, down, left and right arrows are pressed. Sets the global variables
     * which are acesses in get methods to navigate the camera about the canvas.
     * @name CanvasController#onKeyDown
     * @function
     *
     * @param {Event} event  Event triggured
     */
    function onKeyDown(event) {
        var step = 5;
        switch (event.keyCode.toString()) {
            case "38":
                // up
                getLatestMoveZ += step;
                break;
            case "40":
                // down
                getLatestMoveZ -= step;
                break;
            case "37":
                // left
                getLatestMoveX += step;
                break;
            case "39":
                // right
                getLatestMoveX -= step;
                break;
        }
    }

    return {

        /**
         * Initial function which is called on startup for creating event listeners in the canvas area. 
         * Including scroll, mouse drag, touch drag and keyboard events. 
         * @name CanvasController#init
         * @function
         *
         * @param {Renderer} r  Renderer object to have listeners added to
         * @param {Camera} c  Camera object to have zoom and aspect ratio modified by events
         */
        init: function(r, c) {
            renderer = r;
            camera = c;
            renderer.domElement.addEventListener('mousedown', onDocumentMouseDown, false);
            renderer.domElement.addEventListener('touchstart', onDocumentTouchStart, false);
            renderer.domElement.addEventListener('touchmove', onDocumentTouchMove, false);
            window.addEventListener('resize', onWindowResize, false);
            renderer.domElement.addEventListener("mousewheel", onMouseScroll, false);
            renderer.domElement.addEventListener("DOMMouseScroll", onMouseScroll, false);
            window.addEventListener("keydown", onKeyDown, false);
        },

        /**
         * Returns the last accumulated rotatoion on X axis
         * @name CanvasController#getLatestTargetRotationX
         * @function
         *
         * @returns {Integer} targetRotationX  Amount of rotation along x axis in degrees.
         */
        getLatestTargetRotationX: function() {
            return targetRotationX;
        },

        /**
         * Returns the last accumulated rotation on Y axis
         * @name CanvasController#getLatestTargetRotationY
         * @function
         *
         * @returns {Integer} targetRotationY  Amount of rotation along y axis in degrees.
         */
        getLatestTargetRotationY: function() {
            return targetRotationY;
        },

        /**
         * Returns the last accumulated movement along X axis
         * @name CanvasController#getLatestMoveX
         * @function
         *
         * @returns {Integer} getLatestMoveX  Amount of movement along x axis in pixels.
         */
        getLatestMoveX: function() {
            return getLatestMoveX;
        },

        /**
         * Returns the last accumulated movement along Z axis
         * @name CanvasController#getLatestMoveZ
         * @function
         *
         * @returns {Integer} getLatestMoveZ  Amount of movement along z axis in pixels.
         */
        getLatestMoveZ: function() {
            return getLatestMoveZ;
        }
    }
});