API Docs for:
Show:

File: yui3-gallery/src/gallery-cssmatrix2d/js/cssmatrix2d.js

/**
 * @module gallery-cssmatrix2d
 */
(function (Y) {
    'use strict';
    
    var _degreesToRadians = Math.PI / 180,
        
        _cos = Math.cos,
        _isUndefined = Y.Lang.isUndefined,
        _sin = Math.sin,
        _tan = Math.tan,
        
        /**
         * This represents the matrix used by 2d CSS transforms.  It helps
         * perform all of the necessary matrix calculations.  This is sort of an
         * implementation of the CSSMatrix object defined in this spec:
         * http://www.w3.org/TR/css3-2d-transforms/#cssmatrix-interface
         * The matrix defined in the spec is a 3x2 matrix.  I'm not exactly an
         * expert at matrix math, but most of the operations required by the
         * spec only work with square matrices.  The spec doesn't explain how a
         * 3x2 matrix is supposed to do these things.  In order to make the math
         * work correctly, this object internally treats it as the 4x4 matrix
         * defined in the 3d CSS transforms spec here:
         * http://www.w3.org/TR/css3-3d-transforms/#cssmatrix-interface
         * and it converts the 3x2 matrix into a 4x4 matrix by following the
         * examples provided in this spec:
         * http://www.w3.org/TR/2012/WD-css3-transforms-20120403/
         * Other implementations of these specs, like the WebKitCSSMatrix object
         * and others that have copied it, attempt to combine both the 2d and 3d
         * versions of CSSMatrix into the same object.  This implementation
         * only borrows ideas from the 3d version to make the math make sense,
         * but only the 2d functionality is implemented.  Since only the 6 2d
         * matrix items out of the total 16 3d matrix items are mutable, and the
         * remaining 3d matrix items are known to be either 0 or 1, most of the
         * complicated 4x4 matrix math is factored down and reduced, becoming
         * much more efficient.
         * @class CSSMatrix2d
         * @constructor
         */
        _class = function () {};
        
    _class.prototype = {
        /**
         * The 1,1 position in the matrix.
         * @property a
         * @default 1
         * @type Number
         */
        a: 1,
        /**
         * The 2,1 position in the matrix.
         * @property b
         * @default 0
         * @type Number
         */
        b: 0,
        /**
         * The 1,2 position in the matrix.
         * @property c
         * @default 0
         * @type Number
         */
        c: 0,
        /**
         * The 2,2 position in the matrix.
         * @property d
         * @default 1
         * @type Number
         */
        d: 1,
        /**
         * The 1,4 position in the matrix.
         * @property e
         * @default 0
         * @type Number
         */
        e: 0,
        /**
         * The 2,4 position in the matrix.
         * @property f
         * @default 0
         * @type Number
         */
        f: 0,
        /**
         * Returns a new matrix, the inverse of this one.
         * This matrix is not modified.
         * This method will throw if the matrix can not be inverted.
         * @method inverse
         * @return {CSSMatrix2d} inverse
         */
        inverse: function () {
            var me = this,
                meA = me.a,
                meB = me.b,
                meC = me.c,
                meD = me.d,
                meE = me.e,
                meF = me.f,

                determinant = meA * meD - meB * meC,
                inverse = new _class();

            if (!determinant) {
                throw 'Can not be inverted.';
            }

            inverse.a = meD / determinant;
            inverse.b = -meB / determinant;
            inverse.c = -meC / determinant;
            inverse.d = meA / determinant;
            inverse.e = (meC * meF - meD * meE) / determinant;
            inverse.f = (meB * meE - meA * meF) / determinant;

            return inverse;
        },
        /**
         * Returns a new matrix, the product of this one multiplied by
         * another one.  Neither this matrix nor the other one is
         * modified.
         * @method multiply
         * @param {CSSMatrix2d} other
         * @return {CSSMatrix2d} product
         */
        multiply: function (other) {
            var me = this,
                meA = me.a,
                meB = me.b,
                meC = me.c,
                meD = me.d,
                otherA = other.a,
                otherB = other.b,
                otherC = other.c,
                otherD = other.d,
                otherE = other.e,
                otherF = other.f,
                product = new _class();

            product.a = meA * otherA + meC * otherB;
            product.b = meB * otherA + meD * otherB;
            product.c = meA * otherC + meC * otherD;
            product.d = meB * otherC + meD * otherD;
            product.e = meA * otherE + meC * otherF + me.e;
            product.f = meB * otherE + meD * otherF + me.f;

            return product;
        },
        /**
         * Returns a new matrix, rotated the given angle clockwise.
         * This matrix is not modified.
         * @method rotate
         * @param {Number} angle The angle specified in degrees.
         * @return {CSSMatrix2d} rotated
         */
        rotate: function (angle) {
            return this.rotateRad(angle * _degreesToRadians);
        },
        /**
         * Returns a new matrix, rotated the given angle clockwise.
         * This matrix is not modified.
         * @method rotateRad
         * @param {Number} angle The angle specified in radians.
         * @return {CSSMatrix2d} rotated
         */
        rotateRad: function (angle) {
            var other = new _class();

            other.a = _cos(angle);
            other.b = _sin(angle);
            other.c = -_sin(angle);
            other.d = _cos(angle);

            return this.multiply(other);
        },
        /**
         * Returns a new matrix, scaled horizontally and vertically.
         * This matrix is not modified.
         * @method scale
         * @param {Number} x The horizontal scale factor.
         * @param {Number} y The vertical scale factor.  Optional.  If
         * undefined, x will be used for both the horizontal and
         * vertical scale factor.
         * @return {CSSMatrix2d} scaled.
         */
        scale: function (x, y) {
            var other = new _class();

            other.a = x;
            other.d = _isUndefined(y) ? x : y;

            return this.multiply(other);
        },
        /**
         * Sets the matrix based on a matrix string provided by the DOM.
         * The string is expected to be like 'matrix(a, b, c, d, e, f)'.
         * This format isn't specifically checked for, so other similar
         * strings might be accepted.  If 6 values can not be read from
         * from the string, this method will do nothing.  Invalid values
         * could result in NaN being assigned to matrix items.
         * @method setMatrixValue
         * @chainable
         * @param {String} matrixValue
         */
        setMatrixValue: function (matrixValue) {
            var me = this;

            matrixValue = matrixValue.split(',');

            if (matrixValue.length < 6) {
                return me;
            }

            me.a = parseFloat(matrixValue[0].substr(matrixValue[0].lastIndexOf('(') + 1));
            me.b = parseFloat(matrixValue[1]);
            me.c = parseFloat(matrixValue[2]);
            me.d = parseFloat(matrixValue[3]);
            me.e = parseFloat(matrixValue[4]);
            me.f = parseFloat(matrixValue[5]);

            return me;
        },
        /**
         * Returns a new matrix, skewed horizontally.
         * This matrix is not modified.
         * @method skewX
         * @param {Number} angle The horizontal skew angle specified in
         * degrees.
         * @return {CSSMatrix2d} skewed.
         */
        skewX: function (angle) {
            return this.skewXRad(angle * _degreesToRadians);
        },
        /**
         * Returns a new matrix, skewed horizontally.
         * This matrix is not modified.
         * @method skewXRad
         * @param {Number} angle The horizontal skew angle specified in radians.
         * @return {CSSMatrix2d} skewed.
         */
        skewXRad: function (angle) {
            var other = new _class();

            other.c = _tan(angle);

            return this.multiply(other);
        },
        /**
         * Returns a new matrix, skewed vertically.
         * This matrix is not modified.
         * @method skewY
         * @param {Number} angle The vertical skew angle specified in degrees.
         * @return {CSSMatrix2d} skewed.
         */
        skewY: function (angle) {
            return this.skewYRad(angle * _degreesToRadians);
        },
        /**
         * Returns a new matrix, skewed vertically.
         * This matrix is not modified.
         * @method skewYRad
         * @param {Number} angle The vertical skew angle specified in radians.
         * @return {CSSMatrix2d} skewed.
         */
        skewYRad: function (angle) {
            var other = new _class();

            other.b = _tan(angle);

            return this.multiply(other);
        },
        /**
         * Returns a string 'matrix(a, b, c, d, e, f)' which can be used by the
         * DOM for 2d CSS transforms.
         * @method toString
         * @return {String}
         */
        toString: function () {
            var me = this;

            return 'matrix(' + me.a + ', ' + me.b + ', ' + me.c + ', ' + me.d + ', ' + me.e + ', ' + me.f + ')';
        },
        /**
         * Returns a new matrix, translated horizontally and vertically.
         * This matrix is not modified.
         * @method translate
         * @param {Number} x The horizontal translation amount.
         * @param {Number} y The vertical translation amount.
         * @return {CSSMatrix2d} translated.
         */
        translate: function (x, y) {
            var other = new _class();

            other.e = x;
            other.f = y;

            return this.multiply(other);
        }
    };
    
    Y.CSSMatrix2d = _class;
}(Y));