Show:
/* Copyright © 2015-2016 David Valdman */

define(function(require, exports, module) {
    var EventHandler = require('../events/EventHandler');
    var SimpleStream = require('../streams/SimpleStream');
    var OptionsManager = require('../core/_OptionsManager');
    var TouchInput = require('./TouchInput');

    /**
     * Generalizes handling of two-finger touch events.
     *  Helper to PinchInput and RotateInput.
     *  This class is meant to be overridden and not used directly.
     *
     * @class TwoFingerInput
     * @extends Streams.SimpleStream
     * @uses Core._OptionsManager
     * @private
     * @constructor
     */
    function TwoFingerInput(options) {
        this.options = OptionsManager.setOptions(this, options);

        this._eventInput = new TouchInput(this.options);
        this._eventOutput = new EventHandler();

        EventHandler.setInputHandler(this, this._eventInput);
        EventHandler.setOutputHandler(this, this._eventOutput);

        this.payload = [];
        this.touchIdA = undefined;
        this.touchIdB = undefined;
        this.posA = null;
        this.posB = null;

        this._eventInput.on('start', handleStart.bind(this));
        this._eventInput.on('update', handleMove.bind(this));
        this._eventInput.on('end', handleEnd.bind(this));
    }

    TwoFingerInput.prototype = Object.create(SimpleStream.prototype);
    TwoFingerInput.prototype.constructor = TwoFingerInput;

    TwoFingerInput.DIRECTION = {
        X : 0,
        Y : 1
    };

    TwoFingerInput.DEFAULT_OPTIONS = {
        direction : undefined,
        rails : false,
        track : 2
    };

    /**
     * Calculates the angle between two touches relative to [0,1].
     *  Direction option must not be set to x- or y- axes, otherwise 0 is returned.
     *
     * @method calculateAngle
     * @static
     * @param value1 {Array}  First touch location (x,y)
     * @param value2 {Array}  Second touch location (x,y)
     * @return {Number}
     */
    TwoFingerInput.calculateAngle = function(value1, value2) {
        if (this.options.direction !== undefined) return 0;
        var diffX = value2[0] - value1[0];
        var diffY = value2[1] - value1[1];
        return Math.atan2(diffY, diffX);
    };

    /**
     * Calculates the distance between two touches.
     *
     * @method calculateDistance
     * @static
     * @param value1 {Number|Array}  First touch location (x,y)
     * @param value2 {Number|Array}  Second touch location (x,y)
     * @return {Number}
     */
    TwoFingerInput.calculateDistance = function(value1, value2) {
        var direction = this.options.direction;
        
        if (direction === undefined){
            var diffX = value2[0] - value1[0];
            var diffY = value2[1] - value1[1];
            return Math.sqrt(diffX * diffX + diffY * diffY);
        }
        else return Math.abs(value2 - value1);
    };

    /**
     * Calculates the midpoint between two touches.
     *
     * @method calculateCenter
     * @static
     * @param value1 {Number|Array}  First touch location
     * @param value2 {Number|Array}  Second touch location
     * @return {Number|Array}
     */
    TwoFingerInput.calculateCenter = function(value1, value2) {
        return (this.options.direction === undefined)
            ? [0.5 * (value1[0] + value2[0]), 0.5 * (value1[1] + value2[1])]
            : (value1 + value2);
    };

    /**
     * Calculates the combined velocity of the two touches.
     *
     * @method calculateCenter
     * @static
     * @param velocity1 {Number|Array}  First velocity
     * @param velocity2 {Number|Array}  Second velocity
     * @return {Number|Array}
     */
    TwoFingerInput.calculateVelocity = function(velocity1, velocity2){
        return (this.options.direction === undefined)
            ? [0.5 * (velocity1[0] + velocity2[0]), 0.5 * (velocity1[1] + velocity2[1])]
            : 0.5 * (velocity1 + velocity2);
    };

    /**
     * Calculates the direction of the touch.
     *
     * @method calculateOrientation
     * @static
     * @param value1 {Number|Array}  First velocity
     * @param value2 {Number|Array}  Second velocity
     * @return {Number|Array}
     */
    TwoFingerInput.calculateOrientation = function(value1, value2){
        return (this.options.direction === undefined)
            ? [(value2[0] - value1[0]), (value2[1] - value1[1])]
            : value2 - value1;
    };

    /**
     * Detects if orientation has changed.
     *
     * @method detectOrientationChange
     * @static
     * @param dir2 {Number|Array}  First direction
     * @param dir1 {Number|Array}  Second direction
     * @return {Boolean}
     */
    TwoFingerInput.detectOrientationChange = function(dir1, dir2){
        return (this.options.direction === undefined)
            ? dir1[0] * dir2[0] + dir1[1] * dir2[1] <= 0
            : dir1 * dir2 <= 0;
    };

    function getPosition(event){
        var direction = this.options.direction;
        var position;
        if (direction === TwoFingerInput.DIRECTION.X)
            position = event.pageX;
        else if (direction === TwoFingerInput.DIRECTION.Y)
            position = event.pageY;
        else
            position = [event.pageX, event.pageY];

        return position;
    }

    function handleStart(data) {
        data.position = getPosition.call(this, data.event);

        if (this.touchIdA === data.touchId){
            this.payload[0] = data;
        }

        if (this.touchIdA === undefined){
            this.touchIdA = data.touchId;
            this.payload[0] = data;
        }
        else if (this.touchIdB === undefined){
            this.touchIdB = data.touchId;
            this.payload[1] = data;
            this.emit('twoFingerStart', this.payload);
        }
    }

    function handleMove(data) {
        if (this.touchIdA === undefined || this.touchIdB === undefined)
            return false;

        data.position = getPosition.call(this, data.event);

        if (data.touchId === this.touchIdA)
            this.payload[0] = data;
        else if (data.touchId === this.touchIdB)
            this.payload[1] = data;

        this.emit('twoFingerUpdate', this.payload);
    }

    function handleEnd(data) {
        if (this.touchIdA === undefined && this.touchIdB === undefined) return false;

        this.emit('twoFingerEnd', this.payload);
        this.touchIdA = undefined;
        this.touchIdB = undefined;
        this.payload = [];
    }

    module.exports = TwoFingerInput;
});