Source: geom/Vector2D.js

//------------------------------------------------------------------------------
// Constructor scope
//------------------------------------------------------------------------------

/**
 * Creates a new instance of the Vector2D class.
 *
 * @constructor
 * @extends rune.geom.Point
 *
 * @param {number} [x=0.0] The x-component of the vector.
 * @param {number} [y=0.0] The y-component of the vector.
 * 
 * @class
 * @classdesc
 * 
 * The Vector2D class represents a generic two-dimensional vector. The class 
 * provides some basic mathematical operations such as vector addition and 
 * subtraction, and scalar multiplicaton. The class basically works as a Point 
 * but with extra features.
 */
rune.geom.Vector2D = function(x, y) {

	//--------------------------------------------------------------------------
	// Super call
	//--------------------------------------------------------------------------
	
	/**
	 * Extend rune.geom.Point
	 */
	rune.geom.Point.call(this, x, y);
};

//------------------------------------------------------------------------------
// Inheritance
//------------------------------------------------------------------------------

rune.geom.Vector2D.prototype = Object.create(rune.geom.Point.prototype);
rune.geom.Vector2D.prototype.constructor = rune.geom.Vector2D;

//------------------------------------------------------------------------------
// Private static properties
//------------------------------------------------------------------------------

/**
 * Lookup table for precision rounding.
 *
 * @type {Array.<number>}
 * @private
 */
rune.geom.Vector2D.PRECISION = [
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    10000000000
];

//------------------------------------------------------------------------------
// Override public prototype methods (API)
//------------------------------------------------------------------------------

/**
 * @inheritDoc
 */
rune.geom.Vector2D.prototype.toString = function() {
	return "[{Vector2D (x=" + this.x + " y=" + this.y + ")}]";
};

//------------------------------------------------------------------------------
// Public prototype methods
//------------------------------------------------------------------------------

/**
 * Set the vector axes values to absolute values.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.abs = function() {
    this['x'] = Math.abs(this['x']);
    this['y'] = Math.abs(this['y']);
    
    return this;
};

/**
 * Adds the argument vector to this vector.
 *
 * @param {rune.geom.Vector2D} vector The second vector.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.add = function(vector) {
	this['x'] += vector['x'];
	this['y'] += vector['y'];

	return this;
};

/**
 * Returns the cross product of this vector by another.
 *
 * @param {rune.geom.Vector2D} vector The second vector.
 *
 * @returns {number}
 */
rune.geom.Vector2D.prototype.cross = function(vector) {
    return this['x'] * vector['y'] - this['y'] * vector['x'];
};

/**
 * Divides this vector by another vector, or by a number specified as a 
 * floating point number.
 *
 * @param {rune.geom.Vector2D|number} value The value to divide by.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.divide = function(value) {
    //@note: This violates object-oriented typing rules but it results in a cleaner interface.
    if (value instanceof rune.geom.Vector2D) {
        this['x'] /= value['x'];
        this['y'] /= value['y'];
    } else {
        this['x'] /= value;
        this['y'] /= value;
    }
    
    return this;
};

/**
 * Returns the dot product of this vector by another.
 *
 * @param {rune.geom.Vector2D} vector The second vector.
 *
 * @returns {number}
 */
rune.geom.Vector2D.prototype.dot = function(vector) {
    return vector['x'] * this['x'] + vector['y'] * this['y'];
};

/**
 * Determine if the specified vector is equal to the current vector.
 *
 * @param {rune.geom.Vector2D} vector The second vector.
 *
 * @returns {boolean}
 */
rune.geom.Vector2D.prototype.equals = function(vector) {
    return vector['x'] === this['x'] && vector['y'] === this['y'];
};

/**
 * Returns the magnitude (length) of this vector.
 *
 * @param {boolean} [squared] Request squared magnitude.
 *
 * @returns {number}
 */
rune.geom.Vector2D.prototype.magnitude = function(squared) {
    var x = this['x'];
    var y = this['y'];
    
    var v = x * x + y * y;
    
    return (squared === true) ? v : Math.sqrt(v);
};

/**
 * Multiplies this vector by another vector, or by a number specified as a 
 * floating point number.
 *
 * @param {rune.geom.Vector2D|number} value The value to multiply by.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.multiply = function(value) {
    //@note: This violates object-oriented typing rules but it results in a cleaner interface.
    if (value instanceof rune.geom.Vector2D) {
        this['x'] *= value['x'];
        this['y'] *= value['y'];
    } else {
        this['x'] *= value;
        this['y'] *= value;
    }
    
    return this;
};

/**
 * Scales the line segment between (0,0) and the current vector to a set length.
 *
 * @param {number} [scale] The scaling value.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.normalize = function(scale) {
    return this.divide(scale || this.magnitude());
};

/**
 * Reverses this vector i.e multiplies it by -1.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.reverse = function() {
    this['x'] = -this['x'];
    this['y'] = -this['y'];
    
    return this;
};

/**
 * Rotates the vector with specified radians.
 *
 * @param {number} rads Amount of rotation specified in radians.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.rotate = function(rads) {
    var cos = Math.cos(rads);
    var sin = Math.sin(rads);
    
    var ox = this.x;
    var oy = this.y;
    
    this['x'] = ox * cos - oy * sin;
    this['y'] = ox * sin + oy * cos;
    
    return this;
};

/**
 * Rotates the vector by provided radians.
 *
 * @param {number} n Number of decimals for precision.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.round = function(n) {
    var p = rune.geom.Vector2D.PRECISION[n || 2];
    
    this['x'] = ((0.5 + this.x * p) << 0) / p;
    this['y'] = ((0.5 + this.y * p) << 0) / p;
    
    return this;
};

/**
 * Subtracts the argument vector from this vector.
 *
 * @param {rune.geom.Vector2D} vector The second vector.
 *
 * @returns {rune.geom.Vector2D}
 */
rune.geom.Vector2D.prototype.subtract = function(vector) {
    this['x'] -= vector['x'];
    this['y'] -= vector['y'];
    
    return this;
};