Source: out/plugins/KineticScrolling/KineticScrolling.js

/**
 * Phaser Kinetic Scrolling Plugin
 * @author       Juan Nicholls <jdnichollsc@hotmail.com>
 * @copyright    2015 Juan Nicholls - http://jdnichollsc.github.io/Phaser-Kinetic-Scrolling-Plugin/
 * @license      {@link http://opensource.org/licenses/MIT}
 * @version 0.1.2
 */

(function (Phaser) {
    'use strict';

    /**
    * Kinetic Scrolling is a Phaser plugin that allows vertical and horizontal scrolling with kinetic motion.
    * It works with the Phaser.Camera
    *
    * @class Phaser.Plugin.KineticScrolling
    * @constructor
    * @param {Object} game - The Game object is the instance of the game, where the magic happens.
    * @param {Any} parent  - The object that owns this plugin, usually Phaser.PluginManager.
    */
    Phaser.Plugin.KineticScrolling = function (game, parent) {
        Phaser.Plugin.call(this, game, parent);


        this.dragging = false;
        this.timestamp = 0;
        this.callbackID = 0;

        this.targetX = 0;
        this.targetY = 0;

        this.autoScrollX = false;
        this.autoScrollY = false;

        this.startX = 0;
        this.startY = 0;

        this.velocityX = 0;
        this.velocityY = 0;

        this.amplitudeX = 0;
        this.amplitudeY = 0;

        this.directionWheel = 0;

        this.velocityWheelX = 0;
        this.velocityWheelY = 0;

        this.settings = {
            kineticMovement: true,
            timeConstantScroll: 325, //really mimic iOS
            horizontalScroll: true,
            verticalScroll: false,
            horizontalWheel: true,
            verticalWheel: false,
            deltaWheel: 40
        };
    };

    Phaser.Plugin.KineticScrolling.prototype = Object.create(Phaser.Plugin.prototype);
    Phaser.Plugin.KineticScrolling.prototype.constructor = Phaser.Plugin.KineticScrolling;

    /**
    * Change Default Settings of the plugin
    *
    * @method Phaser.Plugin.KineticScrolling#configure
    * @param {Object}  [options] - Object that contain properties to change the behavior of the plugin.
    * @param {number}  [options.timeConstantScroll=325] - The rate of deceleration for the scrolling.
    * @param {boolean} [options.kineticMovement=true]   - Enable or Disable the kinematic motion.
    * @param {boolean} [options.horizontalScroll=true]  - Enable or Disable the horizontal scrolling.
    * @param {boolean} [options.verticalScroll=false]   - Enable or Disable the vertical scrolling.
    * @param {boolean} [options.horizontalWheel=true]   - Enable or Disable the horizontal scrolling with mouse wheel.
    * @param {boolean} [options.verticalWheel=false]    - Enable or Disable the vertical scrolling with mouse wheel.
    * @param {number}  [options.deltaWheel=40]          - Delta increment of the mouse wheel.
    */
    Phaser.Plugin.KineticScrolling.prototype.configure = function (options) {

        if (options) {
            for (var property in options) {
                if (this.settings.hasOwnProperty(property)) {
                    this.settings[property] = options[property];
                }
            }
        }

    };

    /**
    * Start the Plugin.
    *
    * @method Phaser.Plugin.KineticScrolling#start
    */
    Phaser.Plugin.KineticScrolling.prototype.start = function () {

        this.game.input.onDown.add(this.beginMove, this);

        this.callbackID = this.game.input.addMoveCallback(this.moveCamera, this);

        this.game.input.onUp.add(this.endMove, this);

        this.game.input.mouse.mouseWheelCallback = this.mouseWheel.bind(this);
    };

    /**
    * Event triggered when a pointer is pressed down, resets the value of variables.
    */
    Phaser.Plugin.KineticScrolling.prototype.beginMove = function () {

        this.startX = this.game.input.x;
        this.startY = this.game.input.y;

        this.dragging = true;

        this.timestamp = Date.now();

        this.velocityY = this.amplitudeY = this.velocityX = this.amplitudeX = 0;

    };

    /**
    * Event triggered when the activePointer receives a DOM move event such as a mousemove or touchmove.
    * The camera moves according to the movement of the pointer, calculating the velocity.
    */
    Phaser.Plugin.KineticScrolling.prototype.moveCamera = function (pointer, x, y) {

        if (!this.dragging) return;

        this.now = Date.now();
        var elapsed = this.now - this.timestamp;
        this.timestamp = this.now;

        if (this.settings.horizontalScroll) {
            var delta = x - this.startX; //Compute move distance
            this.startX = x;
            this.velocityX = 0.8 * (1000 * delta / (1 + elapsed)) + 0.2 * this.velocityX;
            this.game.camera.x -= delta;
        }

        if (this.settings.verticalScroll) {
            var delta = y - this.startY; //Compute move distance
            this.startY = y;
            this.velocityY = 0.8 * (1000 * delta / (1 + elapsed)) + 0.2 * this.velocityY;
            this.game.camera.y -= delta;
        }

    };

    /**
    * Event triggered when a pointer is released, calculates the automatic scrolling.
    */
    Phaser.Plugin.KineticScrolling.prototype.endMove = function () {

        this.dragging = false;
        this.autoScrollX = false;
        this.autoScrollY = false;

        if (!this.settings.kineticMovement) return;

        this.now = Date.now();

        if (this.velocityX > 10 || this.velocityX < -10) {            this.amplitudeX = 0.8 * this.velocityX;
            this.targetX = Math.round(this.game.camera.x - this.amplitudeX);
            this.autoScrollX = true;
        }

        if (this.velocityY > 10 || this.velocityY < -10) {            this.amplitudeY = 0.8 * this.velocityY;
            this.targetY = Math.round(this.game.camera.y - this.amplitudeY);
            this.autoScrollY = true;
        }

    };

    /**
    * Event called after all the core subsystems and the State have updated, but before the render.
    * Create the deceleration effect.
    */
    Phaser.Plugin.KineticScrolling.prototype.update = function () {

        this.elapsed = Date.now() - this.timestamp;

        if (this.autoScrollX && this.amplitudeX != 0) {

            var delta = -this.amplitudeX * Math.exp(-this.elapsed / this.settings.timeConstantScroll);
            if (delta > 0.5 || delta < -0.5) {                this.game.camera.x = this.targetX - delta;
            }
            else {
                this.autoScrollX = false;
                this.game.camera.x = this.targetX;
            }
        }

        if (this.autoScrollY && this.amplitudeY != 0) {

            var delta = -this.amplitudeY * Math.exp(-this.elapsed / this.settings.timeConstantScroll);
            if (delta > 0.5 || delta < -0.5) {                this.game.camera.y = this.targetY - delta;
            }
            else {
                this.autoScrollY = false;
                this.game.camera.y = this.targetY;
            }
        }

        if (this.settings.horizontalWheel && (this.velocityWheelX < -0.1 || this.velocityWheelX > 0.1)) {

            this.game.camera.x -= this.velocityWheelX;
            this.velocityWheelX *= 0.95;
        }

        if (this.settings.verticalWheel && (this.velocityWheelY < -0.1 || this.velocityWheelY > 0.1)) {

            this.game.camera.y -= this.velocityWheelY;
            this.velocityWheelY *= 0.95;
        }
    };

    /**
    * Event called when the mousewheel is used, affect the direction of scrolling.
    */
    Phaser.Plugin.KineticScrolling.prototype.mouseWheel = function (event) {
        if (!this.settings.horizontalWheel && !this.settings.verticalWheel) return;

        event.preventDefault();

        var delta = this.game.input.mouse.wheelDelta * 120 / this.settings.deltaWheel;

        if (this.directionWheel != this.game.input.mouse.wheelDelta) {
            this.velocityWheelX = 0;
            this.velocityWheelY = 0;
            this.directionWheel = this.game.input.mouse.wheelDelta;
        }

        if (this.settings.horizontalWheel) {
            this.autoScrollX = false;

            this.velocityWheelX += delta;
        }

        if (this.settings.verticalWheel) {
            this.autoScrollY = false;

            this.velocityWheelY += delta;
        }

    };

    /**
    * Stop the Plugin.
    *
    * @method Phaser.Plugin.KineticScrolling#stop
    */
    Phaser.Plugin.KineticScrolling.prototype.stop = function () {

        this.game.input.onDown.remove(this.beginMove, this);

        this.game.input.deleteMoveCallback(this.callbackID);

        this.game.input.onUp.remove(this.endMove, this);

        this.game.input.mouse.mouseWheelCallback = null;

    };

} (Phaser));