API Docs for: v0.1.0
Show:

File: src\math\Vector.js

var inherit = require('../utils/inherit');

/**
 * A 2d Vector implementation stolen directly from mrdoob's THREE.js
 * [Vector2d](https://github.com/mrdoob/three.js/blob/master/src/math/Vector2.js)
 *
 * @class Vector
 * @extends Object
 * @constructor
 * @param x {Number} The x component of the vector
 * @param y {Number} The y component of the vector
 */
var Vector = function(x, y) {
    this.x = x || 0;
    this.y = y || 0;
};

inherit(Vector, Object, {
    /**
     * Sets the value of the vector
     *
     * @method set
     * @param x {Number} The x component of the vector
     * @param y {Number} The y component of the vector
     * @return {Vector} Returns itself.
     * @chainable
     */
    set: function(x, y) {
        this.x = x;
        this.y = y;

        return this;
    },
    /**
     * Sets the X value of the vector
     *
     * @method setX
     * @param x {Number} The x component of the vector
     * @return {Vector} Returns itself.
     * @chainable
     */
    setX: function(x) {
        this.x = x;

        return this;
    },
    /**
     * Sets the Y value of the vector
     *
     * @method setY
     * @param y {Number} The y component of the vector
     * @return {Vector} Returns itself.
     * @chainable
     */
    setY: function(y) {
        this.y = y;

        return this;
    },
    /**
     * Sets a component value of the vector
     *
     * @method setComponent
     * @param index {Number} The index of the component to set (0 = x, 1 = y)
     * @param value {Number} The value to set the component to
     * @return {Vector} Returns itself.
     * @chainable
     */
    setComponent: function(index, value) {
        switch(index) {
            case 0:
                this.x = value;
                break;
            case 1:
                this.y = value;
                break;
            default:
                throw new RangeError('index is out of range: ' + index);
        }

        return this;
    },
    /**
     * Gets a component value of the vector
     *
     * @method getComponent
     * @param index {Number} The index of the component to set (0 = x, 1 = y)
     * @return {Number} Returns the component value
     */
    getComponent: function(index) {
        switch(index) {
            case 0:
                return this.x;
            case 1:
                return this.y;
            default:
                throw new RangeError('index is out of range: ' + index);
        }
    },
    /**
     * Copies the passed vector's components to this vector
     *
     * @method copy
     * @param vector {Vector} The vector to copy the values from
     * @return {Vector} Returns itself.
     * @chainable
     */
    copy: function(v) {
        this.x = v.x;
        this.y = v.y;

        return this;
    },
    /**
     * Floors the vector components
     *
     * @method floor
     * @return {Vector} Returns itself.
     * @chainable
     */
    floor: function () {
        this.x = Math.floor(this.x);
        this.y = Math.floor(this.y);

        return this;
    },
    /**
     * Ceils the vector components
     *
     * @method ceil
     * @return {Vector} Returns itself.
     * @chainable
     */
    ceil: function () {
        this.x = Math.ceil(this.x);
        this.y = Math.ceil(this.y);

        return this;
    },
    /**
     * Adds a vector to this one
     *
     * @method add
     * @param vector {Vector} The vector to add to this one
     * @return {Vector} Returns itself.
     * @chainable
     */
    add: function(v) {
        this.x += v.x;
        this.y += v.y;

        return this;
    },
    /**
     * Adds two vectors to each other and stores the result in this vector
     *
     * @method addVectors
     * @param vector1 {Vector}
     * @param vector2 {Vector}
     * @return {Vector} Returns itself.
     * @chainable
     */
    addVectors: function(a, b) {
        this.x = a.x + b.x;
        this.y = a.y + b.y;

        return this;
    },
    /**
     * Adds a scalar value to the x and y components of this vector
     *
     * @method addScalar
     * @param scalar {Number} The scalar value to add
     * @return {Vector} Returns itself.
     * @chainable
     */
    addScalar: function(s) {
        this.x += s;
        this.y += s;

        return this;
    },
    /**
     * Subtracts a vector from this one
     *
     * @method sub
     * @param vector {Vector} The vector to subtract from this one
     * @return {Vector} Returns itself.
     * @chainable
     */
    sub: function(v) {
        this.x -= v.x;
        this.y -= v.y;

        return this;
    },
    /**
     * Subtracts two vectors from each other and stores the result in this vector
     *
     * @method subVectors
     * @param vector1 {Vector}
     * @param vector2 {Vector}
     * @return {Vector} Returns itself.
     * @chainable
     */
    subVectors: function(a, b) {
        this.x = a.x - b.x;
        this.y = a.y - b.y;

        return this;
    },
    /**
     * Multiplies the x and y components of this vector by a scalar value
     *
     * @method multiplyScalar
     * @param scalar {Number} The value to multiply by
     * @return {Vector} Returns itself.
     * @chainable
     */
    multiplyScalar: function(s) {
        this.x *= s;
        this.y *= s;

        return this;
    },
    /**
     * Divides the x and y components of this vector by a scalar value
     *
     * @method divideScalar
     * @param scalar {Number} The value to divide by
     * @return {Vector} Returns itself.
     * @chainable
     */
    divideScalar: function(s) {
        if(s !== 0) {
            this.x /= s;
            this.y /= s;
        } else {
            this.set(0, 0);
        }

        return this;
    },
    /**
     * Sets this vector components to the minimum value when compared to the passed vector's components
     *
     * @method min
     * @param vector {Vector} The vector to compare to
     * @return {Vector} Returns itself.
     * @chainable
     */
    min: function(v) {
        if(this.x > v.x) {
            this.x = v.x;
        }

        if(this.y > v.y) {
            this.y = v.y;
        }

        return this;
    },
    /**
     * Sets this vector components to the maximum value when compared to the passed vector's components
     *
     * @method max
     * @param vector {Vector} The vector to compare to
     * @return {Vector} Returns itself.
     * @chainable
     */
    max: function(v) {
        if(this.x < v.x) {
            this.x = v.x;
        }

        if(this.y < v.y) {
            this.y = v.y;
        }

        return this;
    },
    /**
     * Clamps the vectors components to be between min and max
     *
     * @method max
     * @param min {Vector} The minimum value a component can be
     * @param max {Vector} The maximum value a component can be
     * @return {Vector} Returns itself.
     * @chainable
     */
    clamp: function(min, max) {
        // This function assumes min < max, if this assumption
        //isn't true it will not operate correctly
        if(this.x < min.x) {
            this.x = min.x;
        } else if(this.x > max.x) {
            this.x = max.x;
        }

        if(this.y < min.y) {
            this.y = min.y;
        } else if(this.y > max.y) {
            this.y = max.y;
        }

        return this;
    },
    /**
     * Negates this vector (multiplies by -1)
     *
     * @method negate
     * @return {Vector} Returns itself.
     * @chainable
     */
    negate: function() {
        return this.multiplyScalar(-1);
    },
    /**
     * Project this vector on to another vector.
     *
     * @param v {Vector} The vector to project onto.
     * @return {Vector} Returns itself.
     * @chainable
     */
    project: function(v) {
        var amt = this.dot(v) / v.lengthSq();
        this.x = amt * v.x;
        this.y = amt * v.y;

        return this;
    },
    /**
     * Project this vector onto a vector of unit length.
     *
     * @param v {Vector} The unit vector to project onto.
     * @return {Vector} Returns itself.
     * @chainable
     */
    projectN: function(v) {
        var amt = this.dot(v);
        this.x = amt * v.x;
        this.y = amt * v.y;

        return this;
    },
    /**
     * Reflect this vector on an arbitrary axis.
     *
     * @param axis {Vector} The vector representing the axis.
     * @return {Vector} Returns itself.
     * @chainable
     */
    reflect: function(axis) {
        var x = this.x;
        var y = this.y;
        this.project(axis).multiplyScalar(2);
        this.x -= x;
        this.y -= y;

        return this;
    },
    /**
     * Reflect this vector on an arbitrary axis (represented by a unit vector)
     *
     * @param axis {Vector} The unit vector representing the axis.
     * @return {Vector} Returns itself.
     * @chainable
     */
    reflectN: function(axis) {
        var x = this.x;
        var y = this.y;
        this.projectN(axis).multiplyScalar(2);
        this.x -= x;
        this.y -= y;

        return this;
    },
    /**
     * Performs the dot product between this vector and the passed one and returns the result
     *
     * @method dot
     * @param vector {Vector}
     * @return {Number} Returns the dot product
     */
    dot: function(v) {
        return this.x * v.x + this.y * v.y;
    },
    /**
     * Calculates the square length of the vector
     *
     * @method lengthSq
     * @return {Number} Returns the square length of the vector
     */
    lengthSq: function() {
        return this.dot(this);
    },
    /**
     * Calculates the length of the vector
     *
     * @method length
     * @return {Number} Returns the length of the vector
     */
    length: function() {
        return Math.sqrt(this.lengthSq());
    },
    /**
     * Normalizes this vector (divides by its length)
     *
     * @method normalize
     * @return {Vector} Returns the normalized vector
     */
    normalize: function() {
        return this.divideScalar(this.length());
    },
    /**
     * Calculates the distance to the passed vector
     *
     * @method distanceTo
     * @param vector {Vector} The vector to check distance to
     * @return {Number} The distance
     */
    distanceTo: function(v) {
        return Math.sqrt(this.distanceToSquared(v));
    },
    /**
     * Calculates the square distance to the passed vector
     *
     * @method distanceToSquared
     * @param vector {Vector} The vector to check distance to
     * @return {Number} The square distance
     */
    distanceToSquared: function(v) {
        var dx = this.x - v.x, dy = this.y - v.y;
        return dx * dx + dy * dy;
    },
    /**
     * Sets the length of the vector
     *
     * @method setLength
     * @param length {Number} The length to set this vector to
     * @return {Vector} Returns itself.
     * @chainable
     */
    setLength: function(l) {
        var oldLength = this.length();

        if(oldLength !== 0 && l !== oldLength) {
            this.multiplyScalar(l / oldLength);
        }

        return this;
    },
    /**
     * Performs a linear interpolation between this vector and the passed vector
     *
     * @method lerp
     * @param vector {Vector} The vector to interpolate with
     * @param alpha {Number} The amount to interpolate [0-1] or extrapolate (1-]
     * @return {Vector} Returns itself.
     * @chainable
     */
    lerp: function(v, alpha) {
        this.x += (v.x - this.x) * alpha;
        this.y += (v.y - this.y) * alpha;

        return this;
    },
    /**
     * Rotates the vector by 90 degrees
     *
     * @return {Vector} Returns itself.
     * @chainable
     */
    perp: function() {
        var x = this.x;
        this.x = this.y;
        this.y = -x;

        return this;
    },
    /**
     * Rotates the vector by an arbitrary angle around an arbitrary point in space
     *
     * @method rotate
     * @param angle {Number} The angle in radians to rotate by
     * @param anchor {Vector} The anchor point to rotate around
     * @return {Vector} Returns itself.
     * @chainable
     */
    rotate: function(angle, anchor) {
        var dist = anchor.distanceTo(this);

        return this.set(
            anchor.x + (dist * Math.cos(angle)),
            anchor.y + (dist * Math.sin(angle))
        );
    },
    /**
     * Checks if this vector is equal to another
     *
     * @method equals
     * @param vector {Vector} The vector to compare with
     * @return {Vector} Returns itself.
     * @chainable
     */
    equals: function(v) {
        return ((v.x === this.x) && (v.y === this.y));
    },
    /**
     * Returns an array with the components of this vector as the elements
     *
     * @method toArray
     * @return {Vector} Returns an array of [x,y] form
     */
    toArray: function () {
        return [this.x, this.y];
    },
    /**
     * Creates a new instance of Vector, with the same components as this vector
     *
     * @method clone
     * @return {Vector} Returns a new Vector with the same values
     */
    clone: function () {
        return new Vector(this.x, this.y);
    }
});

/**
 * A vector that is always 0,0
 *
 * @property ZERO
 * @type Vector
 * @readOnly
 * @static
 * @final
 */
Vector.ZERO = new Vector();

module.exports = Vector;