1
YUI.add('matrix', function (Y, NAME) {
12
* Used as value for the _rounding method.
25
_round: function(val) {
26
val = Math.round(val * MatrixUtil._rounder) / MatrixUtil._rounder;
30
* Converts a radian value to a degree.
33
* @param {Number} rad Radian value to be converted.
36
rad2deg: function(rad) {
37
var deg = rad * (180 / Math.PI);
42
* Converts a degree value to a radian.
45
* @param {Number} deg Degree value to be converted to radian.
48
deg2rad: function(deg) {
49
var rad = deg * (Math.PI / 180);
54
* Converts an angle to a radian
57
* @param {Objecxt} val Value to be converted to radian.
60
angle2rad: function(val) {
61
if (typeof val === 'string' && val.indexOf('rad') > -1) {
62
val = parseFloat(val);
63
} else { // default to deg
64
val = MatrixUtil.deg2rad(parseFloat(val));
71
* Converts a transform object to an array of column vectors.
74
* | matrix[0][0] matrix[1][0] matrix[2][0] |
75
* | matrix[0][1] matrix[1][1] matrix[2][1] |
76
* | matrix[0][2] matrix[1][2] matrix[2][2] |
82
convertTransformToArray: function(matrix)
85
[matrix.a, matrix.c, matrix.dx],
86
[matrix.b, matrix.d, matrix.dy],
93
* Returns the determinant of a given matrix.
96
* | matrix[0][0] matrix[1][0] matrix[2][0] |
97
* | matrix[0][1] matrix[1][1] matrix[2][1] |
98
* | matrix[0][2] matrix[1][2] matrix[2][2] |
99
* | matrix[0][3] matrix[1][3] matrix[2][3] |
102
* @method getDeterminant
103
* @param {Array} matrix An nxn matrix represented an array of vector (column) arrays. Each vector array has index for each row.
106
getDeterminant: function(matrix)
115
return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
119
multiplier = matrix[i][0];
120
if(i % 2 === 0 || i === 0)
122
determinant += multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
126
determinant -= multiplier * MatrixUtil.getDeterminant(MatrixUtil.getMinors(matrix, i, 0));
133
* Returns the inverse of a matrix
136
* @param Array matrix An array representing an nxn matrix
140
* | matrix[0][0] matrix[1][0] matrix[2][0] |
141
* | matrix[0][1] matrix[1][1] matrix[2][1] |
142
* | matrix[0][2] matrix[1][2] matrix[2][2] |
143
* | matrix[0][3] matrix[1][3] matrix[2][3] |
146
inverse: function(matrix)
154
//vector representing 2x2 matrix
158
determinant = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
160
[matrix[1][1] * determinant, -matrix[1][0] * determinant],
161
[-matrix[0][1] * determinant, matrix[0][0] * determinant]
166
determinant = MatrixUtil.getDeterminant(matrix);
170
for(j = 0; j < len; ++j)
172
minor = MatrixUtil.getMinors(matrix, j, i);
173
adjunct[i][j] = MatrixUtil.getDeterminant(minor);
174
if((i + j) % 2 !== 0 && (i + j) !== 0)
180
inverse = MatrixUtil.scalarMultiply(adjunct, 1/determinant);
186
* Multiplies a matrix by a numeric value.
188
* @method scalarMultiply
189
* @param {Array} matrix The matrix to be altered.
190
* @param {Number} multiplier The number to multiply against the matrix.
193
scalarMultiply: function(matrix, multiplier)
200
for(j = 0; j < len; ++j)
202
matrix[i][j] = MatrixUtil._round(matrix[i][j] * multiplier);
209
* Returns the transpose for an nxn matrix.
212
* @param matrix An nxn matrix represented by an array of vector arrays.
215
transpose: function(matrix)
217
var len = matrix.length,
224
for(j = 0; j < len; ++j)
226
transpose[i].push(matrix[j][i]);
233
* Returns a matrix of minors based on a matrix, column index and row index.
236
* @param {Array} matrix The matrix from which to extract the matrix of minors.
237
* @param {Number} columnIndex A zero-based index representing the specified column to exclude.
238
* @param {Number} rowIndex A zero-based index represeenting the specified row to exclude.
241
getMinors: function(matrix, columnIndex, rowIndex)
250
if(i !== columnIndex)
253
for(j = 0; j < len; ++j)
257
column.push(matrix[i][j]);
267
* Returns the sign of value
270
* @param {Number} val value to be interpreted
275
return val === 0 ? 1 : val/Math.abs(val);
279
* Multiplies a vector and a matrix
281
* @method vectorMatrixProduct
282
* @param {Array} vector Array representing a column vector
283
* @param {Array} matrix Array representing an nxn matrix
286
vectorMatrixProduct: function(vector, matrix)
293
for(i = 0; i < len; ++i)
296
for(j = 0; j < len; ++j)
298
rowProduct += vector[i] * matrix[i][j];
300
product[i] = rowProduct;
306
* Breaks up a 2d transform matrix into a series of transform operations.
309
* @param {Array} matrix A 3x3 multidimensional array
312
decompose: function(matrix)
314
var a = parseFloat(matrix[0][0]),
315
b = parseFloat(matrix[1][0]),
316
c = parseFloat(matrix[0][1]),
317
d = parseFloat(matrix[1][1]),
318
dx = parseFloat(matrix[0][2]),
319
dy = parseFloat(matrix[1][2]),
324
if((a * d - b * c) === 0)
328
//get length of vector(ab)
329
sx = MatrixUtil._round(Math.sqrt(a * a + b * b));
330
//normalize components of vector(ab)
333
shear = MatrixUtil._round(a * c + b * d);
336
//get length of vector(cd)
337
sy = MatrixUtil._round(Math.sqrt(c * c + d * d));
338
//normalize components of vector(cd)
342
shear = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan(shear)));
343
rotate = MatrixUtil._round(MatrixUtil.rad2deg(Math.atan2(matrix[1][0], matrix[0][0])));
346
["translate", dx, dy],
354
* Parses a transform string and returns an array of transform arrays.
356
* @method getTransformArray
357
* @param {String} val A transform string
360
getTransformArray: function(transform) {
361
var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
366
methods = MatrixUtil.transformMethods;
368
while ((m = re.exec(transform))) {
369
if (methods.hasOwnProperty(m[1]))
371
args = m[2].split(',');
373
transforms.push(args);
375
else if(m[1] == "matrix")
377
args = m[2].split(',');
378
decomp = MatrixUtil.decompose([
379
[args[0], args[2], args[4]],
380
[args[1], args[3], args[5]],
383
transforms.push(decomp[0]);
384
transforms.push(decomp[1]);
385
transforms.push(decomp[2]);
386
transforms.push(decomp[3]);
393
* Returns an array of transform arrays representing transform functions and arguments.
395
* @method getTransformFunctionArray
398
getTransformFunctionArray: function(transform) {
403
list = [transform, 0, 0];
406
list = [transform, 1, 1];
409
list = [transform, 1];
412
list = [transform, 1];
415
list = [transform, 0, 0];
418
list = [transform, 0];
425
* Compares to arrays or transform functions to ensure both contain the same functions in the same
428
* @method compareTransformSequence
429
* @param {Array} list1 Array to compare
430
* @param {Array} list2 Array to compare
433
compareTransformSequence: function(list1, list2)
438
isEqual = len === len2;
443
if(list1[i][0] != list2[i][0])
454
* Mapping of possible transform method names.
456
* @property transformMethods
464
translate: "translate",
465
translateX: "translateX",
466
translateY: "tranlsateY",
474
Y.MatrixUtil = MatrixUtil;
477
* Matrix is a class that allows for the manipulation of a transform matrix.
478
* This class is a work in progress.
484
var Matrix = function(config) {
490
* Used as value for the _rounding method.
498
* Updates the matrix.
508
multiply: function(a, b, c, d, dx, dy) {
510
matrix_a = matrix.a * a + matrix.c * b,
511
matrix_b = matrix.b * a + matrix.d * b,
512
matrix_c = matrix.a * c + matrix.c * d,
513
matrix_d = matrix.b * c + matrix.d * d,
514
matrix_dx = matrix.a * dx + matrix.c * dy + matrix.dx,
515
matrix_dy = matrix.b * dx + matrix.d * dy + matrix.dy;
517
matrix.a = this._round(matrix_a);
518
matrix.b = this._round(matrix_b);
519
matrix.c = this._round(matrix_c);
520
matrix.d = this._round(matrix_d);
521
matrix.dx = this._round(matrix_dx);
522
matrix.dy = this._round(matrix_dy);
527
* Parses a string and updates the matrix.
529
* @method applyCSSText
530
* @param {String} val A css transform string
532
applyCSSText: function(val) {
533
var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
537
val = val.replace(/matrix/g, "multiply");
538
while ((m = re.exec(val))) {
539
if (typeof this[m[1]] === 'function') {
540
args = m[2].split(',');
541
this[m[1]].apply(this, args);
547
* Parses a string and returns an array of transform arrays.
549
* @method getTransformArray
550
* @param {String} val A css transform string
553
getTransformArray: function(val) {
554
var re = /\s*([a-z]*)\(([\w,\.,\-,\s]*)\)/gi,
559
val = val.replace(/matrix/g, "multiply");
560
while ((m = re.exec(val))) {
561
if (typeof this[m[1]] === 'function') {
562
args = m[2].split(',');
564
transforms.push(args);
571
* Default values for the matrix
573
* @property _defaults
591
_round: function(val) {
592
val = Math.round(val * this._rounder) / this._rounder;
597
* Initializes a matrix.
600
* @param {Object} config Specified key value pairs for matrix properties. If a property is not explicitly defined in the config argument,
601
* the default value will be used.
603
init: function(config) {
604
var defaults = this._defaults,
607
config = config || {};
609
for (prop in defaults) {
610
if(defaults.hasOwnProperty(prop))
612
this[prop] = (prop in config) ? config[prop] : defaults[prop];
616
this._config = config;
620
* Applies a scale transform
623
* @param {Number} val
625
scale: function(x, y) {
626
this.multiply(x, 0, 0, y, 0, 0);
631
* Applies a skew transformation.
634
* @param {Number} x The value to skew on the x-axis.
635
* @param {Number} y The value to skew on the y-axis.
637
skew: function(x, y) {
641
if (x !== undefined) { // null or undef
642
x = Math.tan(this.angle2rad(x));
646
if (y !== undefined) { // null or undef
647
y = Math.tan(this.angle2rad(y));
650
this.multiply(1, y, x, 1, 0, 0);
655
* Applies a skew to the x-coordinate
658
* @param {Number} x x-coordinate
666
* Applies a skew to the y-coordinate
669
* @param {Number} y y-coordinate
677
* Returns a string of text that can be used to populate a the css transform property of an element.
682
toCSSText: function() {
695
* Returns a string that can be used to populate the css filter property of an element.
697
* @method toFilterText
700
toFilterText: function() {
702
text = 'progid:DXImageTransform.Microsoft.Matrix(';
703
text += 'M11=' + matrix.a + ',' +
704
'M21=' + matrix.b + ',' +
705
'M12=' + matrix.c + ',' +
706
'M22=' + matrix.d + ',' +
707
'sizingMethod="auto expand")';
715
* Converts a radian value to a degree.
718
* @param {Number} rad Radian value to be converted.
721
rad2deg: function(rad) {
722
var deg = rad * (180 / Math.PI);
727
* Converts a degree value to a radian.
730
* @param {Number} deg Degree value to be converted to radian.
733
deg2rad: function(deg) {
734
var rad = deg * (Math.PI / 180);
738
angle2rad: function(val) {
739
if (typeof val === 'string' && val.indexOf('rad') > -1) {
740
val = parseFloat(val);
741
} else { // default to deg
742
val = this.deg2rad(parseFloat(val));
749
* Applies a rotate transform.
752
* @param {Number} deg The degree of the rotation.
754
rotate: function(deg, x, y) {
755
var rad = this.angle2rad(deg),
758
this.multiply(cos, sin, 0 - sin, cos, 0, 0);
763
* Applies translate transformation.
766
* @param {Number} x The value to transate on the x-axis.
767
* @param {Number} y The value to translate on the y-axis.
769
translate: function(x, y) {
770
x = parseFloat(x) || 0;
771
y = parseFloat(y) || 0;
772
this.multiply(1, 0, 0, 1, x, y);
777
* Applies a translate to the x-coordinate
780
* @param {Number} x x-coordinate
782
translateX: function(x) {
788
* Applies a translate to the y-coordinate
791
* @param {Number} y y-coordinate
793
translateY: function(y) {
794
this.translate(null, y);
800
* Returns an identity matrix.
805
identity: function() {
806
var config = this._config,
807
defaults = this._defaults,
810
for (prop in config) {
811
if (prop in defaults) {
812
this[prop] = defaults[prop];
819
* Returns a 3x3 Matrix array
822
* | matrix[0][0] matrix[1][0] matrix[2][0] |
823
* | matrix[0][1] matrix[1][1] matrix[2][1] |
824
* | matrix[0][2] matrix[1][2] matrix[2][2] |
827
* @method getMatrixArray
830
getMatrixArray: function()
834
[matrix.a, matrix.c, matrix.dx],
835
[matrix.b, matrix.d, matrix.dy],
842
* Returns the left, top, right and bottom coordinates for a transformed
845
* @method getContentRect
846
* @param {Number} width The width of the item.
847
* @param {Number} height The height of the item.
848
* @param {Number} x The x-coordinate of the item.
849
* @param {Number} y The y-coordinate of the item.
852
getContentRect: function(width, height, x, y)
854
var left = !isNaN(x) ? x : 0,
855
top = !isNaN(y) ? y : 0,
856
right = left + width,
857
bottom = top + height,
865
x1 = (a * left + c * top + dx),
866
y1 = (b * left + d * top + dy),
868
x2 = (a * right + c * top + dx),
869
y2 = (b * right + d * top + dy),
871
x3 = (a * left + c * bottom + dx),
872
y3 = (b * left + d * bottom + dy),
874
x4 = (a * right + c * bottom + dx),
875
y4 = (b * right + d * bottom + dy);
877
left: Math.min(x3, Math.min(x1, Math.min(x2, x4))),
878
right: Math.max(x3, Math.max(x1, Math.max(x2, x4))),
879
top: Math.min(y2, Math.min(y4, Math.min(y3, y1))),
880
bottom: Math.max(y2, Math.max(y4, Math.max(y3, y1)))
885
* Returns the determinant of the matrix.
887
* @method getDeterminant
890
getDeterminant: function()
892
return Y.MatrixUtil.getDeterminant(this.getMatrixArray());
896
* Returns the inverse (in array form) of the matrix.
903
return Y.MatrixUtil.inverse(this.getMatrixArray());
907
* Returns the transpose of the matrix
912
transpose: function()
914
return Y.MatrixUtil.transpose(this.getMatrixArray());
918
* Returns an array of transform commands that represent the matrix.
923
decompose: function()
925
return Y.MatrixUtil.decompose(this.getMatrixArray());
932
}, '@VERSION@', {"requires": ["yui-base"]});