2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('matrix', function (Y, NAME) {
19 * Used as value for the _rounding method.
32 _round: function(val) {
33 val = Math.round(val * MatrixUtil._rounder) / MatrixUtil._rounder;
37 * Converts a radian value to a degree.
40 * @param {Number} rad Radian value to be converted.
43 rad2deg: function(rad) {
44 var deg = rad * (180 / Math.PI);
49 * Converts a degree value to a radian.
52 * @param {Number} deg Degree value to be converted to radian.
55 deg2rad: function(deg) {
56 var rad = deg * (Math.PI / 180);
61 * Converts an angle to a radian
64 * @param {Objecxt} val Value to be converted to radian.
67 angle2rad: function(val) {
68 if (typeof val === 'string' && val.indexOf('rad') > -1) {
69 val = parseFloat(val);
70 } else { // default to deg
71 val = MatrixUtil.deg2rad(parseFloat(val));
78 * Converts a transform object to an array of column vectors.
81 * | matrix[0][0] matrix[1][0] matrix[2][0] |
82 * | matrix[0][1] matrix[1][1] matrix[2][1] |
83 * | matrix[0][2] matrix[1][2] matrix[2][2] |
89 convertTransformToArray: function(matrix)
92 [matrix.a, matrix.c, matrix.dx],
93 [matrix.b, matrix.d, matrix.dy],
100 * Returns the determinant of a given matrix.
103 * | matrix[0][0] matrix[1][0] matrix[2][0] |
104 * | matrix[0][1] matrix[1][1] matrix[2][1] |
105 * | matrix[0][2] matrix[1][2] matrix[2][2] |
106 * | matrix[0][3] matrix[1][3] matrix[2][3] |
109 * @method getDeterminant
110 * @param {Array} matrix An nxn matrix represented an array of vector (column) arrays. Each vector array has index for each row.
113 getDeterminant: function(matrix)
122 return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
126 multiplier = matrix[i][0];
127 if(i % 2 === 0 || i === 0)
129 determinant += multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
133 determinant -= multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
140 * Returns the inverse of a matrix
143 * @param Array matrix An array representing an nxn matrix
147 * | matrix[0][0] matrix[1][0] matrix[2][0] |
148 * | matrix[0][1] matrix[1][1] matrix[2][1] |
149 * | matrix[0][2] matrix[1][2] matrix[2][2] |
150 * | matrix[0][3] matrix[1][3] matrix[2][3] |
153 inverse: function(matrix)
161 //vector representing 2x2 matrix
165 determinant = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
167 [matrix[1][1] * determinant, -matrix[1][0] * determinant],
168 [-matrix[0][1] * determinant, matrix[0][0] * determinant]
173 determinant = MatrixUtil.getDeterminant(matrix);
177 for(j = 0; j < len; ++j)
179 minor = MatrixUtil.getMinors(matrix, j, i);
180 adjunct[i][j] = MatrixUtil.getDeterminant(minor);
181 if((i + j) % 2 !== 0 && (i + j) !== 0)
187 inverse = MatrixUtil.scalarMultiply(adjunct, 1/determinant);
193 * Multiplies a matrix by a numeric value.
195 * @method scalarMultiply
196 * @param {Array} matrix The matrix to be altered.
197 * @param {Number} multiplier The number to multiply against the matrix.
200 scalarMultiply: function(matrix, multiplier)
207 for(j = 0; j < len; ++j)
209 matrix[i][j] = MatrixUtil._round(matrix[i][j] * multiplier);
216 * Returns the transpose for an nxn matrix.
219 * @param matrix An nxn matrix represented by an array of vector arrays.
222 transpose: function(matrix)
224 var len = matrix.length,
231 for(j = 0; j < len; ++j)
233 transpose[i].push(matrix[j][i]);
240 * Returns a matrix of minors based on a matrix, column index and row index.
243 * @param {Array} matrix The matrix from which to extract the matrix of minors.
244 * @param {Number} columnIndex A zero-based index representing the specified column to exclude.
245 * @param {Number} rowIndex A zero-based index represeenting the specified row to exclude.
248 getMinors: function(matrix, columnIndex, rowIndex)
257 if(i !== columnIndex)
260 for(j = 0; j < len; ++j)
264 column.push(matrix[i][j]);
274 * Returns the sign of value
277 * @param {Number} val value to be interpreted
282 return val === 0 ? 1 : val/Math.abs(val);
286 * Multiplies a vector and a matrix
288 * @method vectorMatrixProduct
289 * @param {Array} vector Array representing a column vector
290 * @param {Array} matrix Array representing an nxn matrix
293 vectorMatrixProduct: function(vector, matrix)
300 for(i = 0; i < len; ++i)
303 for(j = 0; j < len; ++j)
305 rowProduct += vector[i] * matrix[i][j];
307 product[i] = rowProduct;
313 * Breaks up a 2d transform matrix into a series of transform operations.
316 * @param {Array} 3x3 matrix array
319 decompose: function(matrix)
321 var a = parseFloat(matrix[0][0]),
322 b = parseFloat(matrix[1][0]),
323 c = parseFloat(matrix[0][1]),
324 d = parseFloat(matrix[1][1]),
325 dx = parseFloat(matrix[0][2]),
326 dy = parseFloat(matrix[1][2]),
331 if((a * d - b * c) === 0)
335 //get length of vector(ab)
336 sx = MatrixUtil._round(Math.sqrt(a * a + b * b));
337 //normalize components of vector(ab)
340 shear = MatrixUtil._round(a * c + b * d);
343 //get length of vector(cd)
344 sy = MatrixUtil._round(Math.sqrt(c * c + d * d));
345 //normalize components of vector(cd)
349 shear = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan(shear)));
350 rotate = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan2(matrix[1][0], matrix[0][0])));
353 ["translate", dx, dy],
361 * Parses a transform string and returns an array of transform arrays.
363 * @method getTransformArray
364 * @param {String} val A transform string
367 getTransformArray: function(transform) {
368 var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
373 methods = MatrixUtil.transformMethods;
375 while ((m = re.exec(transform))) {
376 if (methods.hasOwnProperty(m[1]))
378 args = m[2].split(',');
380 transforms.push(args);
382 else if(m[1] == "matrix")
384 args = m[2].split(',');
385 decomp = MatrixUtil.decompose([
386 [args[0], args[2], args[4]],
387 [args[1], args[3], args[5]],
390 transforms.push(decomp[0]);
391 transforms.push(decomp[1]);
392 transforms.push(decomp[2]);
393 transforms.push(decomp[3]);
400 * Returns an array of transform arrays representing transform functions and arguments.
402 * @method getTransformFunctionArray
405 getTransformFunctionArray: function(transform) {
410 list = [transform, 0, 0];
413 list = [transform, 1, 1];
416 list = [transform, 1];
419 list = [transform, 1];
422 list = [transform, 0, 0];
425 list = [transform, 0];
432 * Compares to arrays or transform functions to ensure both contain the same functions in the same
435 * @method compareTransformSequence
436 * @param {Array} list1 Array to compare
437 * @param {Array} list2 Array to compare
440 compareTransformSequence: function(list1, list2)
445 isEqual = len === len2;
450 if(list1[i][0] != list2[i][0])
461 * Mapping of possible transform method names.
463 * @property transformMethods
471 translate: "translate",
472 translateX: "translateX",
473 translateY: "tranlsateY",
481 Y.MatrixUtil = MatrixUtil;
484 * Matrix is a class that allows for the manipulation of a transform matrix.
485 * This class is a work in progress.
491 var Matrix = function(config) {
497 * Used as value for the _rounding method.
505 * Updates the matrix.
515 multiply: function(a, b, c, d, dx, dy) {
517 matrix_a = matrix.a * a + matrix.c * b,
518 matrix_b = matrix.b * a + matrix.d * b,
519 matrix_c = matrix.a * c + matrix.c * d,
520 matrix_d = matrix.b * c + matrix.d * d,
521 matrix_dx = matrix.a * dx + matrix.c * dy + matrix.dx,
522 matrix_dy = matrix.b * dx + matrix.d * dy + matrix.dy;
524 matrix.a = this._round(matrix_a);
525 matrix.b = this._round(matrix_b);
526 matrix.c = this._round(matrix_c);
527 matrix.d = this._round(matrix_d);
528 matrix.dx = this._round(matrix_dx);
529 matrix.dy = this._round(matrix_dy);
534 * Parses a string and updates the matrix.
536 * @method applyCSSText
537 * @param {String} val A css transform string
539 applyCSSText: function(val) {
540 var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
544 val = val.replace(/matrix/g, "multiply");
545 while ((m = re.exec(val))) {
546 if (typeof this[m[1]] === 'function') {
547 args = m[2].split(',');
548 this[m[1]].apply(this, args);
554 * Parses a string and returns an array of transform arrays.
556 * @method getTransformArray
557 * @param {String} val A css transform string
560 getTransformArray: function(val) {
561 var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
566 val = val.replace(/matrix/g, "multiply");
567 while ((m = re.exec(val))) {
568 if (typeof this[m[1]] === 'function') {
569 args = m[2].split(',');
571 transforms.push(args);
578 * Default values for the matrix
580 * @property _defaults
598 _round: function(val) {
599 val = Math.round(val * this._rounder) / this._rounder;
604 * Initializes a matrix.
607 * @param {Object} config Specified key value pairs for matrix properties. If a property is not explicitly defined in the config argument,
608 * the default value will be used.
610 init: function(config) {
611 var defaults = this._defaults,
614 config = config || {};
616 for (prop in defaults) {
617 if(defaults.hasOwnProperty(prop))
619 this[prop] = (prop in config) ? config[prop] : defaults[prop];
623 this._config = config;
627 * Applies a scale transform
630 * @param {Number} val
632 scale: function(x, y) {
633 this.multiply(x, 0, 0, y, 0, 0);
638 * Applies a skew transformation.
641 * @param {Number} x The value to skew on the x-axis.
642 * @param {Number} y The value to skew on the y-axis.
644 skew: function(x, y) {
648 if (x !== undefined) { // null or undef
649 x = Math.tan(this.angle2rad(x));
653 if (y !== undefined) { // null or undef
654 y = Math.tan(this.angle2rad(y));
657 this.multiply(1, y, x, 1, 0, 0);
662 * Applies a skew to the x-coordinate
665 * @param {Number} x x-coordinate
673 * Applies a skew to the y-coordinate
676 * @param {Number} y y-coordinate
684 * Returns a string of text that can be used to populate a the css transform property of an element.
689 toCSSText: function() {
702 * Returns a string that can be used to populate the css filter property of an element.
704 * @method toFilterText
707 toFilterText: function() {
709 text = 'progid:DXImageTransform.Microsoft.Matrix(';
710 text += 'M11=' + matrix.a + ',' +
711 'M21=' + matrix.b + ',' +
712 'M12=' + matrix.c + ',' +
713 'M22=' + matrix.d + ',' +
714 'sizingMethod="auto expand")';
722 * Converts a radian value to a degree.
725 * @param {Number} rad Radian value to be converted.
728 rad2deg: function(rad) {
729 var deg = rad * (180 / Math.PI);
734 * Converts a degree value to a radian.
737 * @param {Number} deg Degree value to be converted to radian.
740 deg2rad: function(deg) {
741 var rad = deg * (Math.PI / 180);
745 angle2rad: function(val) {
746 if (typeof val === 'string' && val.indexOf('rad') > -1) {
747 val = parseFloat(val);
748 } else { // default to deg
749 val = this.deg2rad(parseFloat(val));
756 * Applies a rotate transform.
759 * @param {Number} deg The degree of the rotation.
761 rotate: function(deg, x, y) {
762 var rad = this.angle2rad(deg),
765 this.multiply(cos, sin, 0 - sin, cos, 0, 0);
770 * Applies translate transformation.
773 * @param {Number} x The value to transate on the x-axis.
774 * @param {Number} y The value to translate on the y-axis.
776 translate: function(x, y) {
777 x = parseFloat(x) || 0;
778 y = parseFloat(y) || 0;
779 this.multiply(1, 0, 0, 1, x, y);
784 * Applies a translate to the x-coordinate
787 * @param {Number} x x-coordinate
789 translateX: function(x) {
795 * Applies a translate to the y-coordinate
798 * @param {Number} y y-coordinate
800 translateY: function(y) {
801 this.translate(null, y);
807 * Returns an identity matrix.
812 identity: function() {
813 var config = this._config,
814 defaults = this._defaults,
817 for (prop in config) {
818 if (prop in defaults) {
819 this[prop] = defaults[prop];
826 * Returns a 3x3 Matrix array
829 * | matrix[0][0] matrix[1][0] matrix[2][0] |
830 * | matrix[0][1] matrix[1][1] matrix[2][1] |
831 * | matrix[0][2] matrix[1][2] matrix[2][2] |
834 * @method getMatrixArray
837 getMatrixArray: function()
841 [matrix.a, matrix.c, matrix.dx],
842 [matrix.b, matrix.d, matrix.dy],
849 * Returns the left, top, right and bottom coordinates for a transformed
852 * @method getContentRect
853 * @param {Number} width The width of the item.
854 * @param {Number} height The height of the item.
855 * @param {Number} x The x-coordinate of the item.
856 * @param {Number} y The y-coordinate of the item.
859 getContentRect: function(width, height, x, y)
861 var left = !isNaN(x) ? x : 0,
862 top = !isNaN(y) ? y : 0,
863 right = left + width,
864 bottom = top + height,
872 x1 = (a * left + c * top + dx),
873 y1 = (b * left + d * top + dy),
875 x2 = (a * right + c * top + dx),
876 y2 = (b * right + d * top + dy),
878 x3 = (a * left + c * bottom + dx),
879 y3 = (b * left + d * bottom + dy),
881 x4 = (a * right + c * bottom + dx),
882 y4 = (b * right + d * bottom + dy);
884 left: Math.min(x3, Math.min(x1, Math.min(x2, x4))),
885 right: Math.max(x3, Math.max(x1, Math.max(x2, x4))),
886 top: Math.min(y2, Math.min(y4, Math.min(y3, y1))),
887 bottom: Math.max(y2, Math.max(y4, Math.max(y3, y1)))
892 * Returns the determinant of the matrix.
894 * @method getDeterminant
897 getDeterminant: function()
899 return Y.MatrixUtil.getDeterminant(this.getMatrixArray());
903 * Returns the inverse (in array form) of the matrix.
910 return Y.MatrixUtil.inverse(this.getMatrixArray());
914 * Returns the transpose of the matrix
919 transpose: function()
921 return Y.MatrixUtil.transpose(this.getMatrixArray());
925 * Returns an array of transform commands that represent the matrix.
930 decompose: function()
932 return Y.MatrixUtil.decompose(this.getMatrixArray());
939 }, '3.13.0', {"requires": ["yui-base"]});