zui53 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1961 @@
1
+ /*!
2
+ * jQuery 2d Transform v0.9.3
3
+ * http://wiki.github.com/heygrady/transform/
4
+ *
5
+ * Copyright 2010, Grady Kuhnline
6
+ * Dual licensed under the MIT or GPL Version 2 licenses.
7
+ * http://jquery.org/license
8
+ *
9
+ * Date: Sat Dec 4 15:46:09 2010 -0800
10
+ */
11
+ ///////////////////////////////////////////////////////
12
+ // Transform
13
+ ///////////////////////////////////////////////////////
14
+ (function($, window, document, undefined) {
15
+ /**
16
+ * @var Regex identify the matrix filter in IE
17
+ */
18
+ var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/,
19
+ rfxnum = /^([\+\-]=)?([\d+.\-]+)(.*)$/,
20
+ rperc = /%/;
21
+
22
+ // Steal some code from Modernizr
23
+ var m = document.createElement( 'modernizr' ),
24
+ m_style = m.style;
25
+
26
+ function stripUnits(arg) {
27
+ return parseFloat(arg);
28
+ }
29
+
30
+ /**
31
+ * Find the prefix that this browser uses
32
+ */
33
+ function getVendorPrefix() {
34
+ var property = {
35
+ transformProperty : '',
36
+ MozTransform : '-moz-',
37
+ WebkitTransform : '-webkit-',
38
+ OTransform : '-o-',
39
+ msTransform : '-ms-'
40
+ };
41
+ for (var p in property) {
42
+ if (typeof m_style[p] != 'undefined') {
43
+ return property[p];
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+
49
+ function supportCssTransforms() {
50
+ if (typeof(window.Modernizr) !== 'undefined') {
51
+ return Modernizr.csstransforms;
52
+ }
53
+
54
+ var props = [ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ];
55
+ for ( var i in props ) {
56
+ if ( m_style[ props[i] ] !== undefined ) {
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+
62
+ // Capture some basic properties
63
+ var vendorPrefix = getVendorPrefix(),
64
+ transformProperty = vendorPrefix !== null ? vendorPrefix + 'transform' : false,
65
+ transformOriginProperty = vendorPrefix !== null ? vendorPrefix + 'transform-origin' : false;
66
+
67
+ // store support in the jQuery Support object
68
+ $.support.csstransforms = supportCssTransforms();
69
+
70
+ // IE9 public preview 6 requires the DOM names
71
+ if (vendorPrefix == '-ms-') {
72
+ transformProperty = 'msTransform';
73
+ transformOriginProperty = 'msTransformOrigin';
74
+ }
75
+
76
+ /**
77
+ * Class for creating cross-browser transformations
78
+ * @constructor
79
+ */
80
+ $.extend({
81
+ transform: function(elem) {
82
+ // Cache the transform object on the element itself
83
+ elem.transform = this;
84
+
85
+ /**
86
+ * The element we're working with
87
+ * @var jQueryCollection
88
+ */
89
+ this.$elem = $(elem);
90
+
91
+ /**
92
+ * Remember the matrix we're applying to help the safeOuterLength func
93
+ */
94
+ this.applyingMatrix = false;
95
+ this.matrix = null;
96
+
97
+ /**
98
+ * Remember the css height and width to save time
99
+ * This is only really used in IE
100
+ * @var Number
101
+ */
102
+ this.height = null;
103
+ this.width = null;
104
+ this.outerHeight = null;
105
+ this.outerWidth = null;
106
+
107
+ /**
108
+ * We need to know the box-sizing in IE for building the outerHeight and outerWidth
109
+ * @var string
110
+ */
111
+ this.boxSizingValue = null;
112
+ this.boxSizingProperty = null;
113
+
114
+ this.attr = null;
115
+ this.transformProperty = transformProperty;
116
+ this.transformOriginProperty = transformOriginProperty;
117
+ }
118
+ });
119
+
120
+ $.extend($.transform, {
121
+ /**
122
+ * @var Array list of all valid transform functions
123
+ */
124
+ funcs: ['matrix', 'origin', 'reflect', 'reflectX', 'reflectXY', 'reflectY', 'rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY']
125
+ });
126
+
127
+ /**
128
+ * Create Transform as a jQuery plugin
129
+ * @param Object funcs
130
+ * @param Object options
131
+ */
132
+ $.fn.transform = function(funcs, options) {
133
+ return this.each(function() {
134
+ var t = this.transform || new $.transform(this);
135
+ if (funcs) {
136
+ t.exec(funcs, options);
137
+ }
138
+ });
139
+ };
140
+
141
+ $.transform.prototype = {
142
+ /**
143
+ * Applies all of the transformations
144
+ * @param Object funcs
145
+ * @param Object options
146
+ * forceMatrix - uses the matrix in all browsers
147
+ * preserve - tries to preserve the values from previous runs
148
+ */
149
+ exec: function(funcs, options) {
150
+ // extend options
151
+ options = $.extend(true, {
152
+ forceMatrix: false,
153
+ preserve: false
154
+ }, options);
155
+
156
+ // preserve the funcs from the previous run
157
+ this.attr = null;
158
+ if (options.preserve) {
159
+ funcs = $.extend(true, this.getAttrs(true, true), funcs);
160
+ } else {
161
+ funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness
162
+ }
163
+
164
+ // Record the custom attributes on the element itself
165
+ this.setAttrs(funcs);
166
+
167
+ // apply the funcs
168
+ if ($.support.csstransforms && !options.forceMatrix) {
169
+ // CSS3 is supported
170
+ return this.execFuncs(funcs);
171
+ } else if ($.browser.msie || ($.support.csstransforms && options.forceMatrix)) {
172
+ // Internet Explorer or Forced matrix
173
+ return this.execMatrix(funcs);
174
+ }
175
+ return false;
176
+ },
177
+
178
+ /**
179
+ * Applies all of the transformations as functions
180
+ * @param Object funcs
181
+ */
182
+ execFuncs: function(funcs) {
183
+ var values = [];
184
+
185
+ // construct a CSS string
186
+ for (var func in funcs) {
187
+ // handle origin separately
188
+ if (func == 'origin') {
189
+ this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]);
190
+ } else if ($.inArray(func, $.transform.funcs) !== -1) {
191
+ values.push(this.createTransformFunc(func, funcs[func]));
192
+ }
193
+ }
194
+ this.$elem.css(transformProperty, values.join(' '));
195
+ return true;
196
+ },
197
+
198
+ /**
199
+ * Applies all of the transformations as a matrix
200
+ * @param Object funcs
201
+ */
202
+ execMatrix: function(funcs) {
203
+ var matrix,
204
+ tempMatrix,
205
+ args;
206
+
207
+ var elem = this.$elem[0],
208
+ _this = this;
209
+ function normalPixels(val, i) {
210
+ if (rperc.test(val)) {
211
+ // this really only applies to translation
212
+ return parseFloat(val) / 100 * _this['safeOuter' + (i ? 'Height' : 'Width')]();
213
+ }
214
+ return toPx(elem, val);
215
+ }
216
+
217
+ var rtranslate = /translate[X|Y]?/,
218
+ trans = [];
219
+
220
+ for (var func in funcs) {
221
+ switch ($.type(funcs[func])) {
222
+ case 'array': args = funcs[func]; break;
223
+ case 'string': args = $.map(funcs[func].split(','), $.trim); break;
224
+ default: args = [funcs[func]];
225
+ }
226
+
227
+ if ($.matrix[func]) {
228
+
229
+ if ($.cssAngle[func]) {
230
+ // normalize on degrees
231
+ args = $.map(args, $.angle.toDegree);
232
+ } else if (!$.cssNumber[func]) {
233
+ // normalize to pixels
234
+ args = $.map(args, normalPixels);
235
+ } else {
236
+ // strip units
237
+ args = $.map(args, stripUnits);
238
+ }
239
+
240
+ tempMatrix = $.matrix[func].apply(this, args);
241
+ if (rtranslate.test(func)) {
242
+ //defer translation
243
+ trans.push(tempMatrix);
244
+ } else {
245
+ matrix = matrix ? matrix.x(tempMatrix) : tempMatrix;
246
+ }
247
+ } else if (func == 'origin') {
248
+ this[func].apply(this, args);
249
+ }
250
+ }
251
+
252
+ // check that we have a matrix
253
+ matrix = matrix || $.matrix.identity();
254
+
255
+ // Apply translation
256
+ $.each(trans, function(i, val) { matrix = matrix.x(val); });
257
+
258
+ // pull out the relevant values
259
+ var a = parseFloat(matrix.e(1,1).toFixed(6)),
260
+ b = parseFloat(matrix.e(2,1).toFixed(6)),
261
+ c = parseFloat(matrix.e(1,2).toFixed(6)),
262
+ d = parseFloat(matrix.e(2,2).toFixed(6)),
263
+ tx = matrix.rows === 3 ? parseFloat(matrix.e(1,3).toFixed(6)) : 0,
264
+ ty = matrix.rows === 3 ? parseFloat(matrix.e(2,3).toFixed(6)) : 0;
265
+
266
+ //apply the transform to the element
267
+ if ($.support.csstransforms && vendorPrefix === '-moz-') {
268
+ // -moz-
269
+ this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)');
270
+ } else if ($.support.csstransforms) {
271
+ // -webkit, -o-, w3c
272
+ // NOTE: WebKit and Opera don't allow units on the translate variables
273
+ this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')');
274
+ } else if ($.browser.msie) {
275
+ // IE requires the special transform Filter
276
+
277
+ //TODO: Use Nearest Neighbor during animation FilterType=\'nearest neighbor\'
278
+ var filterType = ', FilterType=\'nearest neighbor\''; //bilinear
279
+ var style = this.$elem[0].style;
280
+ var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(' +
281
+ 'M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d +
282
+ ', sizingMethod=\'auto expand\'' + filterType + ')';
283
+ var filter = style.filter || $.curCSS( this.$elem[0], "filter" ) || "";
284
+ style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter;
285
+
286
+ // Let's know that we're applying post matrix fixes and the height/width will be static for a bit
287
+ this.applyingMatrix = true;
288
+ this.matrix = matrix;
289
+
290
+ // IE can't set the origin or translate directly
291
+ this.fixPosition(matrix, tx, ty);
292
+
293
+ this.applyingMatrix = false;
294
+ this.matrix = null;
295
+ }
296
+ return true;
297
+ },
298
+
299
+ /**
300
+ * Sets the transform-origin
301
+ * This really needs to be percentages
302
+ * @param Number x length
303
+ * @param Number y length
304
+ */
305
+ origin: function(x, y) {
306
+ // use CSS in supported browsers
307
+ if ($.support.csstransforms) {
308
+ if (typeof y === 'undefined') {
309
+ this.$elem.css(transformOriginProperty, x);
310
+ } else {
311
+ this.$elem.css(transformOriginProperty, x + ' ' + y);
312
+ }
313
+ return true;
314
+ }
315
+
316
+ // correct for keyword lengths
317
+ switch (x) {
318
+ case 'left': x = '0'; break;
319
+ case 'right': x = '100%'; break;
320
+ case 'center': // no break
321
+ case undefined: x = '50%';
322
+ }
323
+ switch (y) {
324
+ case 'top': y = '0'; break;
325
+ case 'bottom': y = '100%'; break;
326
+ case 'center': // no break
327
+ case undefined: y = '50%'; //TODO: does this work?
328
+ }
329
+
330
+ // store mixed values with units, assumed pixels
331
+ this.setAttr('origin', [
332
+ rperc.test(x) ? x : toPx(this.$elem[0], x) + 'px',
333
+ rperc.test(y) ? y : toPx(this.$elem[0], y) + 'px'
334
+ ]);
335
+ //console.log(this.getAttr('origin'));
336
+ return true;
337
+ },
338
+
339
+ /**
340
+ * Create a function suitable for a CSS value
341
+ * @param string func
342
+ * @param Mixed value
343
+ */
344
+ createTransformFunc: function(func, value) {
345
+ if (func.substr(0, 7) === 'reflect') {
346
+ // let's fake reflection, false value
347
+ // falsey sets an identity matrix
348
+ var m = value ? $.matrix[func]() : $.matrix.identity();
349
+ return 'matrix(' + m.e(1,1) + ', ' + m.e(2,1) + ', ' + m.e(1,2) + ', ' + m.e(2,2) + ', 0, 0)';
350
+ }
351
+
352
+ //value = _correctUnits(func, value);
353
+
354
+ if (func == 'matrix') {
355
+ if (vendorPrefix === '-moz-') {
356
+ value[4] = value[4] ? value[4] + 'px' : 0;
357
+ value[5] = value[5] ? value[5] + 'px' : 0;
358
+ }
359
+ }
360
+ return func + '(' + ($.isArray(value) ? value.join(', ') : value) + ')';
361
+ },
362
+
363
+ /**
364
+ * @param Matrix matrix
365
+ * @param Number tx
366
+ * @param Number ty
367
+ * @param Number height
368
+ * @param Number width
369
+ */
370
+ fixPosition: function(matrix, tx, ty, height, width) {
371
+ // now we need to fix it!
372
+ var calc = new $.matrix.calc(matrix, this.safeOuterHeight(), this.safeOuterWidth()),
373
+ origin = this.getAttr('origin'); // mixed percentages and px
374
+
375
+ // translate a 0, 0 origin to the current origin
376
+ var offset = calc.originOffset(new $.matrix.V2(
377
+ rperc.test(origin[0]) ? parseFloat(origin[0])/100*calc.outerWidth : parseFloat(origin[0]),
378
+ rperc.test(origin[1]) ? parseFloat(origin[1])/100*calc.outerHeight : parseFloat(origin[1])
379
+ ));
380
+
381
+ // IE glues the top-most and left-most pixels of the transformed object to top/left of the original object
382
+ //TODO: This seems wrong in the calculations
383
+ var sides = calc.sides();
384
+
385
+ // Protect against an item that is already positioned
386
+ var cssPosition = this.$elem.css('position');
387
+ if (cssPosition == 'static') {
388
+ cssPosition = 'relative';
389
+ }
390
+
391
+ //TODO: if the element is already positioned, we should attempt to respect it (somehow)
392
+ //NOTE: we could preserve our offset top and left in an attr on the elem
393
+ var pos = {top: 0, left: 0};
394
+
395
+ // Approximates transform-origin, tx, and ty
396
+ var css = {
397
+ 'position': cssPosition,
398
+ 'top': (offset.top + ty + sides.top + pos.top) + 'px',
399
+ 'left': (offset.left + tx + sides.left + pos.left) + 'px',
400
+ 'zoom': 1
401
+ };
402
+
403
+ this.$elem.css(css);
404
+ }
405
+ };
406
+
407
+ /**
408
+ * Ensure that values have the appropriate units on them
409
+ * @param string func
410
+ * @param Mixed value
411
+ */
412
+ function toPx(elem, val) {
413
+ var parts = rfxnum.exec($.trim(val));
414
+
415
+ if (parts[3] && parts[3] !== 'px') {
416
+ var prop = 'paddingBottom',
417
+ orig = $.style( elem, prop );
418
+
419
+ $.style( elem, prop, val );
420
+ val = cur( elem, prop );
421
+ $.style( elem, prop, orig );
422
+ return val;
423
+ }
424
+ return parseFloat( val );
425
+ }
426
+
427
+ function cur(elem, prop) {
428
+ if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
429
+ return elem[ prop ];
430
+ }
431
+
432
+ var r = parseFloat( $.css( elem, prop ) );
433
+ return r && r > -10000 ? r : 0;
434
+ }
435
+ })(jQuery, this, this.document);
436
+
437
+
438
+ ///////////////////////////////////////////////////////
439
+ // Safe Outer Length
440
+ ///////////////////////////////////////////////////////
441
+ (function($, window, document, undefined) {
442
+ $.extend($.transform.prototype, {
443
+ /**
444
+ * @param void
445
+ * @return Number
446
+ */
447
+ safeOuterHeight: function() {
448
+ return this.safeOuterLength('height');
449
+ },
450
+
451
+ /**
452
+ * @param void
453
+ * @return Number
454
+ */
455
+ safeOuterWidth: function() {
456
+ return this.safeOuterLength('width');
457
+ },
458
+
459
+ /**
460
+ * Returns reliable outer dimensions for an object that may have been transformed.
461
+ * Only use this if the matrix isn't handy
462
+ * @param String dim height or width
463
+ * @return Number
464
+ */
465
+ safeOuterLength: function(dim) {
466
+ var funcName = 'outer' + (dim == 'width' ? 'Width' : 'Height');
467
+
468
+ if (!$.support.csstransforms && $.browser.msie) {
469
+ // make the variables more generic
470
+ dim = dim == 'width' ? 'width' : 'height';
471
+
472
+ // if we're transforming and have a matrix; we can shortcut.
473
+ // the true outerHeight is the transformed outerHeight divided by the ratio.
474
+ // the ratio is equal to the height of a 1px by 1px box that has been transformed by the same matrix.
475
+ if (this.applyingMatrix && !this[funcName] && this.matrix) {
476
+ // calculate and return the correct size
477
+ var calc = new $.matrix.calc(this.matrix, 1, 1),
478
+ ratio = calc.offset(),
479
+ length = this.$elem[funcName]() / ratio[dim];
480
+ this[funcName] = length;
481
+
482
+ return length;
483
+ } else if (this.applyingMatrix && this[funcName]) {
484
+ // return the cached calculation
485
+ return this[funcName];
486
+ }
487
+
488
+ // map dimensions to box sides
489
+ var side = {
490
+ height: ['top', 'bottom'],
491
+ width: ['left', 'right']
492
+ };
493
+
494
+ // setup some variables
495
+ var elem = this.$elem[0],
496
+ outerLen = parseFloat($.curCSS(elem, dim, true)), //TODO: this can be cached on animations that do not animate height/width
497
+ boxSizingProp = this.boxSizingProperty,
498
+ boxSizingValue = this.boxSizingValue;
499
+
500
+ // IE6 && IE7 will never have a box-sizing property, so fake it
501
+ if (!this.boxSizingProperty) {
502
+ boxSizingProp = this.boxSizingProperty = _findBoxSizingProperty() || 'box-sizing';
503
+ boxSizingValue = this.boxSizingValue = this.$elem.css(boxSizingProp) || 'content-box';
504
+ }
505
+
506
+ // return it immediately if we already know it
507
+ if (this[funcName] && this[dim] == outerLen) {
508
+ return this[funcName];
509
+ } else {
510
+ this[dim] = outerLen;
511
+ }
512
+
513
+ // add in the padding and border
514
+ if (boxSizingProp && (boxSizingValue == 'padding-box' || boxSizingValue == 'content-box')) {
515
+ outerLen += parseFloat($.curCSS(elem, 'padding-' + side[dim][0], true)) || 0 +
516
+ parseFloat($.curCSS(elem, 'padding-' + side[dim][1], true)) || 0;
517
+ }
518
+ if (boxSizingProp && boxSizingValue == 'content-box') {
519
+ outerLen += parseFloat($.curCSS(elem, 'border-' + side[dim][0] + '-width', true)) || 0 +
520
+ parseFloat($.curCSS(elem, 'border-' + side[dim][1] + '-width', true)) || 0;
521
+ }
522
+
523
+ // remember and return the outerHeight
524
+ this[funcName] = outerLen;
525
+ return outerLen;
526
+ }
527
+ return this.$elem[funcName]();
528
+ }
529
+ });
530
+
531
+ /**
532
+ * Determine the correct property for checking the box-sizing property
533
+ * @param void
534
+ * @return string
535
+ */
536
+ var _boxSizingProperty = null;
537
+ function _findBoxSizingProperty () {
538
+ if (_boxSizingProperty) {
539
+ return _boxSizingProperty;
540
+ }
541
+
542
+ var property = {
543
+ boxSizing : 'box-sizing',
544
+ MozBoxSizing : '-moz-box-sizing',
545
+ WebkitBoxSizing : '-webkit-box-sizing',
546
+ OBoxSizing : '-o-box-sizing'
547
+ },
548
+ elem = document.body;
549
+
550
+ for (var p in property) {
551
+ if (typeof elem.style[p] != 'undefined') {
552
+ _boxSizingProperty = property[p];
553
+ return _boxSizingProperty;
554
+ }
555
+ }
556
+ return null;
557
+ }
558
+ })(jQuery, this, this.document);
559
+
560
+
561
+ ///////////////////////////////////////////////////////
562
+ // Attr
563
+ ///////////////////////////////////////////////////////
564
+ (function($, window, document, undefined) {
565
+ var rfuncvalue = /([\w\-]*?)\((.*?)\)/g, // with values
566
+ attr = 'data-transform',
567
+ rspace = /\s/,
568
+ rcspace = /,\s?/;
569
+
570
+ $.extend($.transform.prototype, {
571
+ /**
572
+ * This overrides all of the attributes
573
+ * @param Object funcs a list of transform functions to store on this element
574
+ * @return void
575
+ */
576
+ setAttrs: function(funcs) {
577
+ var string = '',
578
+ value;
579
+ for (var func in funcs) {
580
+ value = funcs[func];
581
+ if ($.isArray(value)) {
582
+ value = value.join(', ');
583
+ }
584
+ string += ' ' + func + '(' + value + ')';
585
+ }
586
+ this.attr = $.trim(string);
587
+ this.$elem.attr(attr, this.attr);
588
+ },
589
+
590
+ /**
591
+ * This sets only a specific atribute
592
+ * @param string func name of a transform function
593
+ * @param mixed value with proper units
594
+ * @return void
595
+ */
596
+ setAttr: function(func, value) {
597
+ // stringify the value
598
+ if ($.isArray(value)) {
599
+ value = value.join(', ');
600
+ }
601
+
602
+ // pull from a local variable to look it up
603
+ var transform = this.attr || this.$elem.attr(attr);
604
+ if (!transform || transform.indexOf(func) == -1) {
605
+ // we don't have any existing values, save it
606
+ // we don't have this function yet, save it
607
+ this.attr = $.trim(transform + ' ' + func + '(' + value + ')');
608
+ this.$elem.attr(attr, this.attr);
609
+ } else {
610
+ // replace the existing value
611
+ var funcs = [], parts;
612
+
613
+ // regex split
614
+ rfuncvalue.lastIndex = 0; // reset the regex pointer
615
+ while (parts = rfuncvalue.exec(transform)) {
616
+ if (func == parts[1]) {
617
+ funcs.push(func + '(' + value + ')');
618
+ } else {
619
+ funcs.push(parts[0]);
620
+ }
621
+ }
622
+ this.attr = funcs.join(' ');
623
+ this.$elem.attr(attr, this.attr);
624
+ }
625
+ },
626
+
627
+ /**
628
+ * @return Object
629
+ */
630
+ getAttrs: function() {
631
+ var transform = this.attr || this.$elem.attr(attr);
632
+ if (!transform) {
633
+ // We don't have any existing values, return empty object
634
+ return {};
635
+ }
636
+
637
+ // replace the existing value
638
+ var attrs = {}, parts, value;
639
+
640
+ rfuncvalue.lastIndex = 0; // reset the regex pointer
641
+ while ((parts = rfuncvalue.exec(transform)) !== null) {
642
+ if (parts) {
643
+ value = parts[2].split(rcspace);
644
+ attrs[parts[1]] = value.length == 1 ? value[0] : value;
645
+ }
646
+ }
647
+ return attrs;
648
+ },
649
+
650
+ /**
651
+ * @param String func
652
+ * @return mixed
653
+ */
654
+ getAttr: function(func) {
655
+ var attrs = this.getAttrs();
656
+ if (typeof attrs[func] !== 'undefined') {
657
+ return attrs[func];
658
+ }
659
+
660
+ //TODO: move the origin to a function
661
+ if (func === 'origin' && $.support.csstransforms) {
662
+ // supported browsers return percentages always
663
+ return this.$elem.css(this.transformOriginProperty).split(rspace);
664
+ } else if (func === 'origin') {
665
+ // just force IE to also return a percentage
666
+ return ['50%', '50%'];
667
+ }
668
+
669
+ return $.cssDefault[func] || 0;
670
+ }
671
+ });
672
+
673
+ // Define
674
+ if (typeof($.cssAngle) == 'undefined') {
675
+ $.cssAngle = {};
676
+ }
677
+ $.extend($.cssAngle, {
678
+ rotate: true,
679
+ skew: true,
680
+ skewX: true,
681
+ skewY: true
682
+ });
683
+
684
+ // Define default values
685
+ if (typeof($.cssDefault) == 'undefined') {
686
+ $.cssDefault = {};
687
+ }
688
+
689
+ $.extend($.cssDefault, {
690
+ scale: [1, 1],
691
+ scaleX: 1,
692
+ scaleY: 1,
693
+ matrix: [1, 0, 0, 1, 0, 0],
694
+ origin: ['50%', '50%'], // TODO: allow this to be a function, like get
695
+ reflect: [1, 0, 0, 1, 0, 0],
696
+ reflectX: [1, 0, 0, 1, 0, 0],
697
+ reflectXY: [1, 0, 0, 1, 0, 0],
698
+ reflectY: [1, 0, 0, 1, 0, 0]
699
+ });
700
+
701
+ // Define functons with multiple values
702
+ if (typeof($.cssMultipleValues) == 'undefined') {
703
+ $.cssMultipleValues = {};
704
+ }
705
+ $.extend($.cssMultipleValues, {
706
+ matrix: 6,
707
+ origin: {
708
+ length: 2,
709
+ duplicate: true
710
+ },
711
+ reflect: 6,
712
+ reflectX: 6,
713
+ reflectXY: 6,
714
+ reflectY: 6,
715
+ scale: {
716
+ length: 2,
717
+ duplicate: true
718
+ },
719
+ skew: 2,
720
+ translate: 2
721
+ });
722
+
723
+ // specify unitless funcs
724
+ $.extend($.cssNumber, {
725
+ matrix: true,
726
+ reflect: true,
727
+ reflectX: true,
728
+ reflectXY: true,
729
+ reflectY: true,
730
+ scale: true,
731
+ scaleX: true,
732
+ scaleY: true
733
+ });
734
+
735
+ // override all of the css functions
736
+ $.each($.transform.funcs, function(i, func) {
737
+ $.cssHooks[func] = {
738
+ set: function(elem, value) {
739
+ var transform = elem.transform || new $.transform(elem),
740
+ funcs = {};
741
+ funcs[func] = value;
742
+ transform.exec(funcs, {preserve: true});
743
+ },
744
+ get: function(elem, computed) {
745
+ var transform = elem.transform || new $.transform(elem);
746
+ return transform.getAttr(func);
747
+ }
748
+ };
749
+ });
750
+
751
+ // Support Reflection animation better by returning a matrix
752
+ $.each(['reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
753
+ $.cssHooks[func].get = function(elem, computed) {
754
+ var transform = elem.transform || new $.transform(elem);
755
+ return transform.getAttr('matrix') || $.cssDefault[func];
756
+ };
757
+ });
758
+ })(jQuery, this, this.document);
759
+ ///////////////////////////////////////////////////////
760
+ // Animation
761
+ ///////////////////////////////////////////////////////
762
+ (function($, window, document, undefined) {
763
+ /**
764
+ * @var Regex looks for units on a string
765
+ */
766
+ var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
767
+
768
+ /**
769
+ * Doctors prop values in the event that they contain spaces
770
+ * @param Object prop
771
+ * @param String speed
772
+ * @param String easing
773
+ * @param Function callback
774
+ * @return bool
775
+ */
776
+ var _animate = $.fn.animate;
777
+ $.fn.animate = function( prop, speed, easing, callback ) {
778
+ var optall = $.speed(speed, easing, callback),
779
+ mv = $.cssMultipleValues;
780
+
781
+ // Speed always creates a complete function that must be reset
782
+ optall.complete = optall.old;
783
+
784
+ // Capture multiple values
785
+ if (!$.isEmptyObject(prop)) {
786
+ if (typeof optall.original === 'undefined') {
787
+ optall.original = {};
788
+ }
789
+ $.each( prop, function( name, val ) {
790
+ if (mv[name]
791
+ || $.cssAngle[name]
792
+ || (!$.cssNumber[name] && $.inArray(name, $.transform.funcs) !== -1)) {
793
+
794
+ // Handle special easing
795
+ var specialEasing = null;
796
+ if (jQuery.isArray(prop[name])) {
797
+ var mvlen = 1, len = val.length;
798
+ if (mv[name]) {
799
+ mvlen = (typeof mv[name].length === 'undefined' ? mv[name] : mv[name].length);
800
+ }
801
+ if ( len > mvlen
802
+ || (len < mvlen && len == 2)
803
+ || (len == 2 && mvlen == 2 && isNaN(parseFloat(val[len - 1])))) {
804
+
805
+ specialEasing = val[len - 1];
806
+ val.splice(len - 1, 1);
807
+ }
808
+ }
809
+
810
+ // Store the original values onto the optall
811
+ optall.original[name] = val.toString();
812
+
813
+ // reduce to a unitless number (to trick animate)
814
+ prop[name] = parseFloat(val);
815
+ }
816
+ } );
817
+ }
818
+
819
+ //NOTE: we edited prop above to trick animate
820
+ //NOTE: we pre-convert to an optall so we can doctor it
821
+ return _animate.apply(this, [arguments[0], optall]);
822
+ };
823
+
824
+ var prop = 'paddingBottom';
825
+ function cur(elem, prop) {
826
+ if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
827
+ //return elem[ prop ];
828
+ }
829
+
830
+ var r = parseFloat( $.css( elem, prop ) );
831
+ return r && r > -10000 ? r : 0;
832
+ }
833
+
834
+ var _custom = $.fx.prototype.custom;
835
+ $.fx.prototype.custom = function(from, to, unit) {
836
+ var multiple = $.cssMultipleValues[this.prop],
837
+ angle = $.cssAngle[this.prop];
838
+
839
+ //TODO: simply check for the existence of CSS Hooks?
840
+ if (multiple || (!$.cssNumber[this.prop] && $.inArray(this.prop, $.transform.funcs) !== -1)) {
841
+ this.values = [];
842
+
843
+ if (!multiple) {
844
+ multiple = 1;
845
+ }
846
+
847
+ // Pull out the known values
848
+ var values = this.options.original[this.prop],
849
+ currentValues = $(this.elem).css(this.prop),
850
+ defaultValues = $.cssDefault[this.prop] || 0;
851
+
852
+ // make sure the current css value is an array
853
+ if (!$.isArray(currentValues)) {
854
+ currentValues = [currentValues];
855
+ }
856
+
857
+ // make sure the new values are an array
858
+ if (!$.isArray(values)) {
859
+ if ($.type(values) === 'string') {
860
+ values = values.split(',');
861
+ } else {
862
+ values = [values];
863
+ }
864
+ }
865
+
866
+ // make sure we have enough new values
867
+ var length = multiple.length || multiple, i = 0;
868
+ while (values.length < length) {
869
+ values.push(multiple.duplicate ? values[0] : defaultValues[i] || 0);
870
+ i++;
871
+ }
872
+
873
+ // calculate a start, end and unit for each new value
874
+ var start, parts, end, //unit,
875
+ fx = this,
876
+ transform = fx.elem.transform;
877
+ orig = $.style(fx.elem, prop);
878
+
879
+ $.each(values, function(i, val) {
880
+ // find a sensible start value
881
+ if (currentValues[i]) {
882
+ start = currentValues[i];
883
+ } else if (defaultValues[i] && !multiple.duplicate) {
884
+ start = defaultValues[i];
885
+ } else if (multiple.duplicate) {
886
+ start = currentValues[0];
887
+ } else {
888
+ start = 0;
889
+ }
890
+
891
+ // Force the correct unit on the start
892
+ if (angle) {
893
+ start = $.angle.toDegree(start);
894
+ } else if (!$.cssNumber[fx.prop]) {
895
+ parts = rfxnum.exec($.trim(start));
896
+ if (parts[3] && parts[3] !== 'px') {
897
+ if (parts[3] === '%') {
898
+ start = parseFloat( parts[2] ) / 100 * transform['safeOuter' + (i ? 'Height' : 'Width')]();
899
+ } else {
900
+ $.style( fx.elem, prop, start);
901
+ start = cur(fx.elem, prop);
902
+ $.style( fx.elem, prop, orig);
903
+ }
904
+ }
905
+ }
906
+ start = parseFloat(start);
907
+
908
+ // parse the value with a regex
909
+ parts = rfxnum.exec($.trim(val));
910
+
911
+ if (parts) {
912
+ // we found a sensible value and unit
913
+ end = parseFloat( parts[2] );
914
+ unit = parts[3] || "px"; //TODO: change to an appropriate default unit
915
+
916
+ if (angle) {
917
+ end = $.angle.toDegree(end + unit);
918
+ unit = 'deg';
919
+ } else if (!$.cssNumber[fx.prop] && unit === '%') {
920
+ start = (start / transform['safeOuter' + (i ? 'Height' : 'Width')]()) * 100;
921
+ } else if (!$.cssNumber[fx.prop] && unit !== 'px') {
922
+ $.style( fx.elem, prop, (end || 1) + unit);
923
+ start = ((end || 1) / cur(fx.elem, prop)) * start;
924
+ $.style( fx.elem, prop, orig);
925
+ }
926
+
927
+ // If a +=/-= token was provided, we're doing a relative animation
928
+ if (parts[1]) {
929
+ end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
930
+ }
931
+ } else {
932
+ // I don't know when this would happen
933
+ end = val;
934
+ unit = '';
935
+ }
936
+
937
+ // Save the values
938
+ fx.values.push({
939
+ start: start,
940
+ end: end,
941
+ unit: unit
942
+ });
943
+ });
944
+ }
945
+ return _custom.apply(this, arguments);
946
+ };
947
+
948
+ /**
949
+ * Animates a multi value attribute
950
+ * @param Object fx
951
+ * @return null
952
+ */
953
+ $.fx.multipleValueStep = {
954
+ _default: function(fx) {
955
+ $.each(fx.values, function(i, val) {
956
+ fx.values[i].now = val.start + ((val.end - val.start) * fx.pos);
957
+ });
958
+ }
959
+ };
960
+ $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
961
+ $.fx.multipleValueStep[func] = function(fx) {
962
+ var d = fx.decomposed,
963
+ $m = $.matrix;
964
+ m = $m.identity();
965
+
966
+ d.now = {};
967
+
968
+ // increment each part of the decomposition and recompose it
969
+ $.each(d.start, function(k) {
970
+ // calculate the current value
971
+ d.now[k] = parseFloat(d.start[k]) + ((parseFloat(d.end[k]) - parseFloat(d.start[k])) * fx.pos);
972
+
973
+ // skip functions that won't affect the transform
974
+ if (((k === 'scaleX' || k === 'scaleY') && d.now[k] === 1) ||
975
+ (k !== 'scaleX' && k !== 'scaleY' && d.now[k] === 0)) {
976
+ return true;
977
+ }
978
+
979
+ // calculating
980
+ m = m.x($m[k](d.now[k]));
981
+ });
982
+
983
+ // save the correct matrix values for the value of now
984
+ var val;
985
+ $.each(fx.values, function(i) {
986
+ switch (i) {
987
+ case 0: val = parseFloat(m.e(1, 1).toFixed(6)); break;
988
+ case 1: val = parseFloat(m.e(2, 1).toFixed(6)); break;
989
+ case 2: val = parseFloat(m.e(1, 2).toFixed(6)); break;
990
+ case 3: val = parseFloat(m.e(2, 2).toFixed(6)); break;
991
+ case 4: val = parseFloat(m.e(1, 3).toFixed(6)); break;
992
+ case 5: val = parseFloat(m.e(2, 3).toFixed(6)); break;
993
+ }
994
+ fx.values[i].now = val;
995
+ });
996
+ };
997
+ });
998
+ /**
999
+ * Step for animating tranformations
1000
+ */
1001
+ $.each($.transform.funcs, function(i, func) {
1002
+ $.fx.step[func] = function(fx) {
1003
+ var transform = fx.elem.transform || new $.transform(fx.elem),
1004
+ funcs = {};
1005
+
1006
+ if ($.cssMultipleValues[func] || (!$.cssNumber[func] && $.inArray(func, $.transform.funcs) !== -1)) {
1007
+ ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
1008
+ funcs[fx.prop] = [];
1009
+ $.each(fx.values, function(i, val) {
1010
+ funcs[fx.prop].push(val.now + ($.cssNumber[fx.prop] ? '' : val.unit));
1011
+ });
1012
+ } else {
1013
+ funcs[fx.prop] = fx.now + ($.cssNumber[fx.prop] ? '' : fx.unit);
1014
+ }
1015
+
1016
+ transform.exec(funcs, {preserve: true});
1017
+ };
1018
+ });
1019
+
1020
+ // Support matrix animation
1021
+ $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
1022
+ $.fx.step[func] = function(fx) {
1023
+ var transform = fx.elem.transform || new $.transform(fx.elem),
1024
+ funcs = {};
1025
+
1026
+ if (!fx.initialized) {
1027
+ fx.initialized = true;
1028
+
1029
+ // Reflections need a sensible end value set
1030
+ if (func !== 'matrix') {
1031
+ var values = $.matrix[func]().elements;
1032
+ var val;
1033
+ $.each(fx.values, function(i) {
1034
+ switch (i) {
1035
+ case 0: val = values[0]; break;
1036
+ case 1: val = values[2]; break;
1037
+ case 2: val = values[1]; break;
1038
+ case 3: val = values[3]; break;
1039
+ default: val = 0;
1040
+ }
1041
+ fx.values[i].end = val;
1042
+ });
1043
+ }
1044
+
1045
+ // Decompose the start and end
1046
+ fx.decomposed = {};
1047
+ var v = fx.values;
1048
+
1049
+ fx.decomposed.start = $.matrix.matrix(v[0].start, v[1].start, v[2].start, v[3].start, v[4].start, v[5].start).decompose();
1050
+ fx.decomposed.end = $.matrix.matrix(v[0].end, v[1].end, v[2].end, v[3].end, v[4].end, v[5].end).decompose();
1051
+ }
1052
+
1053
+ ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
1054
+ funcs.matrix = [];
1055
+ $.each(fx.values, function(i, val) {
1056
+ funcs.matrix.push(val.now);
1057
+ });
1058
+
1059
+ transform.exec(funcs, {preserve: true});
1060
+ };
1061
+ });
1062
+ })(jQuery, this, this.document);
1063
+ ///////////////////////////////////////////////////////
1064
+ // Angle
1065
+ ///////////////////////////////////////////////////////
1066
+ (function($, window, document, undefined) {
1067
+ /**
1068
+ * Converting a radian to a degree
1069
+ * @const
1070
+ */
1071
+ var RAD_DEG = 180/Math.PI;
1072
+
1073
+ /**
1074
+ * Converting a radian to a grad
1075
+ * @const
1076
+ */
1077
+ var RAD_GRAD = 200/Math.PI;
1078
+
1079
+ /**
1080
+ * Converting a degree to a radian
1081
+ * @const
1082
+ */
1083
+ var DEG_RAD = Math.PI/180;
1084
+
1085
+ /**
1086
+ * Converting a degree to a grad
1087
+ * @const
1088
+ */
1089
+ var DEG_GRAD = 2/1.8;
1090
+
1091
+ /**
1092
+ * Converting a grad to a degree
1093
+ * @const
1094
+ */
1095
+ var GRAD_DEG = 0.9;
1096
+
1097
+ /**
1098
+ * Converting a grad to a radian
1099
+ * @const
1100
+ */
1101
+ var GRAD_RAD = Math.PI/200;
1102
+
1103
+
1104
+ var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
1105
+
1106
+ /**
1107
+ * Functions for converting angles
1108
+ * @var Object
1109
+ */
1110
+ $.extend({
1111
+ angle: {
1112
+ /**
1113
+ * available units for an angle
1114
+ * @var Regex
1115
+ */
1116
+ runit: /(deg|g?rad)/,
1117
+
1118
+ /**
1119
+ * Convert a radian into a degree
1120
+ * @param Number rad
1121
+ * @return Number
1122
+ */
1123
+ radianToDegree: function(rad) {
1124
+ return rad * RAD_DEG;
1125
+ },
1126
+
1127
+ /**
1128
+ * Convert a radian into a degree
1129
+ * @param Number rad
1130
+ * @return Number
1131
+ */
1132
+ radianToGrad: function(rad) {
1133
+ return rad * RAD_GRAD;
1134
+ },
1135
+
1136
+ /**
1137
+ * Convert a degree into a radian
1138
+ * @param Number deg
1139
+ * @return Number
1140
+ */
1141
+ degreeToRadian: function(deg) {
1142
+ return deg * DEG_RAD;
1143
+ },
1144
+
1145
+ /**
1146
+ * Convert a degree into a radian
1147
+ * @param Number deg
1148
+ * @return Number
1149
+ */
1150
+ degreeToGrad: function(deg) {
1151
+ return deg * DEG_GRAD;
1152
+ },
1153
+
1154
+ /**
1155
+ * Convert a grad into a degree
1156
+ * @param Number grad
1157
+ * @return Number
1158
+ */
1159
+ gradToDegree: function(grad) {
1160
+ return grad * GRAD_DEG;
1161
+ },
1162
+
1163
+ /**
1164
+ * Convert a grad into a radian
1165
+ * @param Number grad
1166
+ * @return Number
1167
+ */
1168
+ gradToRadian: function(grad) {
1169
+ return grad * GRAD_RAD;
1170
+ },
1171
+
1172
+ /**
1173
+ * Convert an angle with a unit to a degree
1174
+ * @param String val angle with a unit
1175
+ * @return Number
1176
+ */
1177
+ toDegree: function (val) {
1178
+ var parts = rfxnum.exec(val);
1179
+ if (parts) {
1180
+ val = parseFloat( parts[2] );
1181
+ switch (parts[3] || 'deg') {
1182
+ case 'grad':
1183
+ val = $.angle.gradToDegree(val);
1184
+ break;
1185
+ case 'rad':
1186
+ val = $.angle.radianToDegree(val);
1187
+ break;
1188
+ }
1189
+ return val;
1190
+ }
1191
+ return 0;
1192
+ }
1193
+ }
1194
+ });
1195
+ })(jQuery, this, this.document);
1196
+ ///////////////////////////////////////////////////////
1197
+ // Matrix
1198
+ ///////////////////////////////////////////////////////
1199
+ (function($, window, document, undefined) {
1200
+ /**
1201
+ * Matrix object for creating matrices relevant for 2d Transformations
1202
+ * @var Object
1203
+ */
1204
+ if (typeof($.matrix) == 'undefined') {
1205
+ $.extend({
1206
+ matrix: {}
1207
+ });
1208
+ }
1209
+ var $m = $.matrix;
1210
+
1211
+ $.extend( $m, {
1212
+ /**
1213
+ * A 2-value vector
1214
+ * @param Number x
1215
+ * @param Number y
1216
+ * @constructor
1217
+ */
1218
+ V2: function(x, y){
1219
+ if ($.isArray(arguments[0])) {
1220
+ this.elements = arguments[0].slice(0, 2);
1221
+ } else {
1222
+ this.elements = [x, y];
1223
+ }
1224
+ this.length = 2;
1225
+ },
1226
+
1227
+ /**
1228
+ * A 2-value vector
1229
+ * @param Number x
1230
+ * @param Number y
1231
+ * @param Number z
1232
+ * @constructor
1233
+ */
1234
+ V3: function(x, y, z){
1235
+ if ($.isArray(arguments[0])) {
1236
+ this.elements = arguments[0].slice(0, 3);
1237
+ } else {
1238
+ this.elements = [x, y, z];
1239
+ }
1240
+ this.length = 3;
1241
+ },
1242
+
1243
+ /**
1244
+ * A 2x2 Matrix, useful for 2D-transformations without translations
1245
+ * @param Number mn
1246
+ * @constructor
1247
+ */
1248
+ M2x2: function(m11, m12, m21, m22) {
1249
+ if ($.isArray(arguments[0])) {
1250
+ this.elements = arguments[0].slice(0, 4);
1251
+ } else {
1252
+ this.elements = Array.prototype.slice.call(arguments).slice(0, 4);
1253
+ }
1254
+ this.rows = 2;
1255
+ this.cols = 2;
1256
+ },
1257
+
1258
+ /**
1259
+ * A 3x3 Matrix, useful for 3D-transformations without translations
1260
+ * @param Number mn
1261
+ * @constructor
1262
+ */
1263
+ M3x3: function(m11, m12, m13, m21, m22, m23, m31, m32, m33) {
1264
+ if ($.isArray(arguments[0])) {
1265
+ this.elements = arguments[0].slice(0, 9);
1266
+ } else {
1267
+ this.elements = Array.prototype.slice.call(arguments).slice(0, 9);
1268
+ }
1269
+ this.rows = 3;
1270
+ this.cols = 3;
1271
+ }
1272
+ });
1273
+
1274
+ /** generic matrix prototype */
1275
+ var Matrix = {
1276
+ /**
1277
+ * Return a specific element from the matrix
1278
+ * @param Number row where 1 is the 0th row
1279
+ * @param Number col where 1 is the 0th column
1280
+ * @return Number
1281
+ */
1282
+ e: function(row, col) {
1283
+ var rows = this.rows,
1284
+ cols = this.cols;
1285
+
1286
+ // return 0 on nonsense rows and columns
1287
+ if (row > rows || col > rows || row < 1 || col < 1) {
1288
+ return 0;
1289
+ }
1290
+
1291
+ return this.elements[(row - 1) * cols + col - 1];
1292
+ },
1293
+
1294
+ /**
1295
+ * Taken from Zoomooz
1296
+ * https://github.com/jaukia/zoomooz/blob/c7a37b9a65a06ba730bd66391bbd6fe8e55d3a49/js/jquery.zoomooz.js
1297
+ */
1298
+ decompose: function() {
1299
+ var a = this.e(1, 1),
1300
+ b = this.e(2, 1),
1301
+ c = this.e(1, 2),
1302
+ d = this.e(2, 2),
1303
+ e = this.e(1, 3),
1304
+ f = this.e(2, 3);
1305
+
1306
+ // In case the matrix can't be decomposed
1307
+ if (Math.abs(a * d - b * c) < 0.01) {
1308
+ return {
1309
+ rotate: 0 + 'deg',
1310
+ skewX: 0 + 'deg',
1311
+ scaleX: 1,
1312
+ scaleY: 1,
1313
+ translateX: 0 + 'px',
1314
+ translateY: 0 + 'px'
1315
+ };
1316
+ }
1317
+
1318
+ // Translate is easy
1319
+ var tx = e, ty = f;
1320
+
1321
+ // factor out the X scale
1322
+ var sx = Math.sqrt(a * a + b * b);
1323
+ a = a/sx;
1324
+ b = b/sx;
1325
+
1326
+ // factor out the skew
1327
+ var k = a * c + b * d;
1328
+ c -= a * k;
1329
+ d -= b * k;
1330
+
1331
+ // factor out the Y scale
1332
+ var sy = Math.sqrt(c * c + d * d);
1333
+ c = c / sy;
1334
+ d = d / sy;
1335
+ k = k / sy;
1336
+
1337
+ // account for negative scale
1338
+ if ((a * d - b * c) < 0.0) {
1339
+ a = -a;
1340
+ b = -b;
1341
+ //c = -c; // accomplishes nothing to negate it
1342
+ //d = -d; // accomplishes nothing to negate it
1343
+ sx = -sx;
1344
+ //sy = -sy //Scale Y shouldn't ever be negated
1345
+ }
1346
+
1347
+ // calculate the rotation angle and skew angle
1348
+ var rad2deg = $.angle.radianToDegree;
1349
+ var r = rad2deg(Math.atan2(b, a));
1350
+ k = rad2deg(Math.atan(k));
1351
+
1352
+ return {
1353
+ rotate: r + 'deg',
1354
+ skewX: k + 'deg',
1355
+ scaleX: sx,
1356
+ scaleY: sy,
1357
+ translateX: tx + 'px',
1358
+ translateY: ty + 'px'
1359
+ };
1360
+ }
1361
+ };
1362
+
1363
+ /** Extend all of the matrix types with the same prototype */
1364
+ $.extend($m.M2x2.prototype, Matrix, {
1365
+ toM3x3: function() {
1366
+ var a = this.elements;
1367
+ return new $m.M3x3(
1368
+ a[0], a[1], 0,
1369
+ a[2], a[3], 0,
1370
+ 0, 0, 1
1371
+ );
1372
+ },
1373
+
1374
+ /**
1375
+ * Multiply a 2x2 matrix by a similar matrix or a vector
1376
+ * @param M2x2 | V2 matrix
1377
+ * @return M2x2 | V2
1378
+ */
1379
+ x: function(matrix) {
1380
+ var isVector = typeof(matrix.rows) === 'undefined';
1381
+
1382
+ // Ensure the right-sized matrix
1383
+ if (!isVector && matrix.rows == 3) {
1384
+ return this.toM3x3().x(matrix);
1385
+ }
1386
+
1387
+ var a = this.elements,
1388
+ b = matrix.elements;
1389
+
1390
+ if (isVector && b.length == 2) {
1391
+ // b is actually a vector
1392
+ return new $m.V2(
1393
+ a[0] * b[0] + a[1] * b[1],
1394
+ a[2] * b[0] + a[3] * b[1]
1395
+ );
1396
+ } else if (b.length == a.length) {
1397
+ // b is a 2x2 matrix
1398
+ return new $m.M2x2(
1399
+ a[0] * b[0] + a[1] * b[2],
1400
+ a[0] * b[1] + a[1] * b[3],
1401
+
1402
+ a[2] * b[0] + a[3] * b[2],
1403
+ a[2] * b[1] + a[3] * b[3]
1404
+ );
1405
+ }
1406
+ return false; // fail
1407
+ },
1408
+
1409
+ /**
1410
+ * Generates an inverse of the current matrix
1411
+ * @param void
1412
+ * @return M2x2
1413
+ * @link http://www.dr-lex.be/random/matrix_inv.html
1414
+ */
1415
+ inverse: function() {
1416
+ var d = 1/this.determinant(),
1417
+ a = this.elements;
1418
+ return new $m.M2x2(
1419
+ d * a[3], d * -a[1],
1420
+ d * -a[2], d * a[0]
1421
+ );
1422
+ },
1423
+
1424
+ /**
1425
+ * Calculates the determinant of the current matrix
1426
+ * @param void
1427
+ * @return Number
1428
+ * @link http://www.dr-lex.be/random/matrix_inv.html
1429
+ */
1430
+ determinant: function() {
1431
+ var a = this.elements;
1432
+ return a[0] * a[3] - a[1] * a[2];
1433
+ }
1434
+ });
1435
+
1436
+ $.extend($m.M3x3.prototype, Matrix, {
1437
+ /**
1438
+ * Multiply a 3x3 matrix by a similar matrix or a vector
1439
+ * @param M3x3 | V3 matrix
1440
+ * @return M3x3 | V3
1441
+ */
1442
+ x: function(matrix) {
1443
+ var isVector = typeof(matrix.rows) === 'undefined';
1444
+
1445
+ // Ensure the right-sized matrix
1446
+ if (!isVector && matrix.rows < 3) {
1447
+ matrix = matrix.toM3x3();
1448
+ }
1449
+
1450
+ var a = this.elements,
1451
+ b = matrix.elements;
1452
+
1453
+ if (isVector && b.length == 3) {
1454
+ // b is actually a vector
1455
+ return new $m.V3(
1456
+ a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
1457
+ a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
1458
+ a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
1459
+ );
1460
+ } else if (b.length == a.length) {
1461
+ // b is a 3x3 matrix
1462
+ return new $m.M3x3(
1463
+ a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
1464
+ a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
1465
+ a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
1466
+
1467
+ a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
1468
+ a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
1469
+ a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
1470
+
1471
+ a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
1472
+ a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
1473
+ a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
1474
+ );
1475
+ }
1476
+ return false; // fail
1477
+ },
1478
+
1479
+ /**
1480
+ * Generates an inverse of the current matrix
1481
+ * @param void
1482
+ * @return M3x3
1483
+ * @link http://www.dr-lex.be/random/matrix_inv.html
1484
+ */
1485
+ inverse: function() {
1486
+ var d = 1/this.determinant(),
1487
+ a = this.elements;
1488
+ return new $m.M3x3(
1489
+ d * ( a[8] * a[4] - a[7] * a[5]),
1490
+ d * (-(a[8] * a[1] - a[7] * a[2])),
1491
+ d * ( a[5] * a[1] - a[4] * a[2]),
1492
+
1493
+ d * (-(a[8] * a[3] - a[6] * a[5])),
1494
+ d * ( a[8] * a[0] - a[6] * a[2]),
1495
+ d * (-(a[5] * a[0] - a[3] * a[2])),
1496
+
1497
+ d * ( a[7] * a[3] - a[6] * a[4]),
1498
+ d * (-(a[7] * a[0] - a[6] * a[1])),
1499
+ d * ( a[4] * a[0] - a[3] * a[1])
1500
+ );
1501
+ },
1502
+
1503
+ /**
1504
+ * Calculates the determinant of the current matrix
1505
+ * @param void
1506
+ * @return Number
1507
+ * @link http://www.dr-lex.be/random/matrix_inv.html
1508
+ */
1509
+ determinant: function() {
1510
+ var a = this.elements;
1511
+ return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
1512
+ }
1513
+ });
1514
+
1515
+ /** generic vector prototype */
1516
+ var Vector = {
1517
+ /**
1518
+ * Return a specific element from the vector
1519
+ * @param Number i where 1 is the 0th value
1520
+ * @return Number
1521
+ */
1522
+ e: function(i) {
1523
+ return this.elements[i - 1];
1524
+ }
1525
+ };
1526
+
1527
+ /** Extend all of the vector types with the same prototype */
1528
+ $.extend($m.V2.prototype, Vector);
1529
+ $.extend($m.V3.prototype, Vector);
1530
+ })(jQuery, this, this.document);
1531
+ ///////////////////////////////////////////////////////
1532
+ // Matrix Calculations
1533
+ ///////////////////////////////////////////////////////
1534
+ (function($, window, document, undefined) {
1535
+ /**
1536
+ * Matrix object for creating matrices relevant for 2d Transformations
1537
+ * @var Object
1538
+ */
1539
+ if (typeof($.matrix) == 'undefined') {
1540
+ $.extend({
1541
+ matrix: {}
1542
+ });
1543
+ }
1544
+
1545
+ $.extend( $.matrix, {
1546
+ /**
1547
+ * Class for calculating coordinates on a matrix
1548
+ * @param Matrix matrix
1549
+ * @param Number outerHeight
1550
+ * @param Number outerWidth
1551
+ * @constructor
1552
+ */
1553
+ calc: function(matrix, outerHeight, outerWidth) {
1554
+ /**
1555
+ * @var Matrix
1556
+ */
1557
+ this.matrix = matrix;
1558
+
1559
+ /**
1560
+ * @var Number
1561
+ */
1562
+ this.outerHeight = outerHeight;
1563
+
1564
+ /**
1565
+ * @var Number
1566
+ */
1567
+ this.outerWidth = outerWidth;
1568
+ }
1569
+ });
1570
+
1571
+ $.matrix.calc.prototype = {
1572
+ /**
1573
+ * Calculate a coord on the new object
1574
+ * @return Object
1575
+ */
1576
+ coord: function(x, y, z) {
1577
+ //default z and w
1578
+ z = typeof(z) !== 'undefined' ? z : 0;
1579
+
1580
+ var matrix = this.matrix,
1581
+ vector;
1582
+
1583
+ switch (matrix.rows) {
1584
+ case 2:
1585
+ vector = matrix.x(new $.matrix.V2(x, y));
1586
+ break;
1587
+ case 3:
1588
+ vector = matrix.x(new $.matrix.V3(x, y, z));
1589
+ break;
1590
+ }
1591
+
1592
+ return vector;
1593
+ },
1594
+
1595
+ /**
1596
+ * Calculate the corners of the new object
1597
+ * @return Object
1598
+ */
1599
+ corners: function(x, y) {
1600
+ // Try to save the corners if this is called a lot
1601
+ var save = !(typeof(x) !=='undefined' || typeof(y) !=='undefined'),
1602
+ c;
1603
+ if (!this.c || !save) {
1604
+ y = y || this.outerHeight;
1605
+ x = x || this.outerWidth;
1606
+
1607
+ c = {
1608
+ tl: this.coord(0, 0),
1609
+ bl: this.coord(0, y),
1610
+ tr: this.coord(x, 0),
1611
+ br: this.coord(x, y)
1612
+ };
1613
+ } else {
1614
+ c = this.c;
1615
+ }
1616
+
1617
+ if (save) {
1618
+ this.c = c;
1619
+ }
1620
+ return c;
1621
+ },
1622
+
1623
+ /**
1624
+ * Calculate the sides of the new object
1625
+ * @return Object
1626
+ */
1627
+ sides: function(corners) {
1628
+ // The corners of the box
1629
+ var c = corners || this.corners();
1630
+
1631
+ return {
1632
+ top: Math.min(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
1633
+ bottom: Math.max(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
1634
+ left: Math.min(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1)),
1635
+ right: Math.max(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1))
1636
+ };
1637
+ },
1638
+
1639
+ /**
1640
+ * Calculate the offset of the new object
1641
+ * @return Object
1642
+ */
1643
+ offset: function(corners) {
1644
+ // The corners of the box
1645
+ var s = this.sides(corners);
1646
+
1647
+ // return size
1648
+ return {
1649
+ height: Math.abs(s.bottom - s.top),
1650
+ width: Math.abs(s.right - s.left)
1651
+ };
1652
+ },
1653
+
1654
+ /**
1655
+ * Calculate the area of the new object
1656
+ * @return Number
1657
+ * @link http://en.wikipedia.org/wiki/Quadrilateral#Area_of_a_convex_quadrilateral
1658
+ */
1659
+ area: function(corners) {
1660
+ // The corners of the box
1661
+ var c = corners || this.corners();
1662
+
1663
+ // calculate the two diagonal vectors
1664
+ var v1 = {
1665
+ x: c.tr.e(1) - c.tl.e(1) + c.br.e(1) - c.bl.e(1),
1666
+ y: c.tr.e(2) - c.tl.e(2) + c.br.e(2) - c.bl.e(2)
1667
+ },
1668
+ v2 = {
1669
+ x: c.bl.e(1) - c.tl.e(1) + c.br.e(1) - c.tr.e(1),
1670
+ y: c.bl.e(2) - c.tl.e(2) + c.br.e(2) - c.tr.e(2)
1671
+ };
1672
+
1673
+ return 0.25 * Math.abs(v1.e(1) * v2.e(2) - v1.e(2) * v2.e(1));
1674
+ },
1675
+
1676
+ /**
1677
+ * Calculate the non-affinity of the new object
1678
+ * @return Number
1679
+ */
1680
+ nonAffinity: function() {
1681
+ // The corners of the box
1682
+ var sides = this.sides(),
1683
+ xDiff = sides.top - sides.bottom,
1684
+ yDiff = sides.left - sides.right;
1685
+
1686
+ return parseFloat(parseFloat(Math.abs(
1687
+ (Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) /
1688
+ (sides.top * sides.bottom + sides.left * sides.right)
1689
+ )).toFixed(8));
1690
+ },
1691
+
1692
+ /**
1693
+ * Calculate a proper top and left for IE
1694
+ * @param Object toOrigin
1695
+ * @param Object fromOrigin
1696
+ * @return Object
1697
+ */
1698
+ originOffset: function(toOrigin, fromOrigin) {
1699
+ // the origin to translate to
1700
+ toOrigin = toOrigin ? toOrigin : new $.matrix.V2(
1701
+ this.outerWidth * 0.5,
1702
+ this.outerHeight * 0.5
1703
+ );
1704
+
1705
+ // the origin to translate from (IE has a fixed origin of 0, 0)
1706
+ fromOrigin = fromOrigin ? fromOrigin : new $.matrix.V2(
1707
+ 0,
1708
+ 0
1709
+ );
1710
+
1711
+ // transform the origins
1712
+ var toCenter = this.coord(toOrigin.e(1), toOrigin.e(2));
1713
+ var fromCenter = this.coord(fromOrigin.e(1), fromOrigin.e(2));
1714
+
1715
+ // return the offset
1716
+ return {
1717
+ top: (fromCenter.e(2) - fromOrigin.e(2)) - (toCenter.e(2) - toOrigin.e(2)),
1718
+ left: (fromCenter.e(1) - fromOrigin.e(1)) - (toCenter.e(1) - toOrigin.e(1))
1719
+ };
1720
+ }
1721
+ };
1722
+ })(jQuery, this, this.document);
1723
+ ///////////////////////////////////////////////////////
1724
+ // 2d Matrix Functions
1725
+ ///////////////////////////////////////////////////////
1726
+ (function($, window, document, undefined) {
1727
+ /**
1728
+ * Matrix object for creating matrices relevant for 2d Transformations
1729
+ * @var Object
1730
+ */
1731
+ if (typeof($.matrix) == 'undefined') {
1732
+ $.extend({
1733
+ matrix: {}
1734
+ });
1735
+ }
1736
+ var $m = $.matrix,
1737
+ $m2x2 = $m.M2x2,
1738
+ $m3x3 = $m.M3x3;
1739
+
1740
+ $.extend( $m, {
1741
+ /**
1742
+ * Identity matrix
1743
+ * @param Number size
1744
+ * @return Matrix
1745
+ */
1746
+ identity: function(size) {
1747
+ size = size || 2;
1748
+ var length = size * size,
1749
+ elements = new Array(length),
1750
+ mod = size + 1;
1751
+ for (var i = 0; i < length; i++) {
1752
+ elements[i] = (i % mod) === 0 ? 1 : 0;
1753
+ }
1754
+ return new $m['M'+size+'x'+size](elements);
1755
+ },
1756
+
1757
+ /**
1758
+ * Matrix
1759
+ * @return Matrix
1760
+ */
1761
+ matrix: function() {
1762
+ var args = Array.prototype.slice.call(arguments);
1763
+ // arguments are in column-major order
1764
+ switch (arguments.length) {
1765
+ case 4:
1766
+ return new $m2x2(
1767
+ args[0], args[2],
1768
+ args[1], args[3]
1769
+ );
1770
+ case 6:
1771
+ return new $m3x3(
1772
+ args[0], args[2], args[4],
1773
+ args[1], args[3], args[5],
1774
+ 0, 0, 1
1775
+ );
1776
+ }
1777
+ },
1778
+
1779
+ /**
1780
+ * Reflect (same as rotate(180))
1781
+ * @return Matrix
1782
+ */
1783
+ reflect: function() {
1784
+ return new $m2x2(
1785
+ -1, 0,
1786
+ 0, -1
1787
+ );
1788
+ },
1789
+
1790
+ /**
1791
+ * Reflect across the x-axis (mirrored upside down)
1792
+ * @return Matrix
1793
+ */
1794
+ reflectX: function() {
1795
+ return new $m2x2(
1796
+ 1, 0,
1797
+ 0, -1
1798
+ );
1799
+ },
1800
+
1801
+ /**
1802
+ * Reflect by swapping x an y (same as reflectX + rotate(-90))
1803
+ * @return Matrix
1804
+ */
1805
+ reflectXY: function() {
1806
+ return new $m2x2(
1807
+ 0, 1,
1808
+ 1, 0
1809
+ );
1810
+ },
1811
+
1812
+ /**
1813
+ * Reflect across the y-axis (mirrored)
1814
+ * @return Matrix
1815
+ */
1816
+ reflectY: function() {
1817
+ return new $m2x2(
1818
+ -1, 0,
1819
+ 0, 1
1820
+ );
1821
+ },
1822
+
1823
+ /**
1824
+ * Rotates around the origin
1825
+ * @param Number deg
1826
+ * @return Matrix
1827
+ * @link http://www.w3.org/TR/SVG/coords.html#RotationDefined
1828
+ */
1829
+ rotate: function(deg) {
1830
+ //TODO: detect units
1831
+ var rad = $.angle.degreeToRadian(deg),
1832
+ costheta = Math.cos(rad),
1833
+ sintheta = Math.sin(rad);
1834
+
1835
+ var a = costheta,
1836
+ b = sintheta,
1837
+ c = -sintheta,
1838
+ d = costheta;
1839
+
1840
+ return new $m2x2(
1841
+ a, c,
1842
+ b, d
1843
+ );
1844
+ },
1845
+
1846
+ /**
1847
+ * Scale
1848
+ * @param Number sx
1849
+ * @param Number sy
1850
+ * @return Matrix
1851
+ * @link http://www.w3.org/TR/SVG/coords.html#ScalingDefined
1852
+ */
1853
+ scale: function (sx, sy) {
1854
+ sx = sx || sx === 0 ? sx : 1;
1855
+ sy = sy || sy === 0 ? sy : sx;
1856
+
1857
+ return new $m2x2(
1858
+ sx, 0,
1859
+ 0, sy
1860
+ );
1861
+ },
1862
+
1863
+ /**
1864
+ * Scale on the X-axis
1865
+ * @param Number sx
1866
+ * @return Matrix
1867
+ */
1868
+ scaleX: function (sx) {
1869
+ return $m.scale(sx, 1);
1870
+ },
1871
+
1872
+ /**
1873
+ * Scale on the Y-axis
1874
+ * @param Number sy
1875
+ * @return Matrix
1876
+ */
1877
+ scaleY: function (sy) {
1878
+ return $m.scale(1, sy);
1879
+ },
1880
+
1881
+ /**
1882
+ * Skews on the X-axis and Y-axis
1883
+ * @param Number degX
1884
+ * @param Number degY
1885
+ * @return Matrix
1886
+ */
1887
+ skew: function (degX, degY) {
1888
+ degX = degX || 0;
1889
+ degY = degY || 0;
1890
+
1891
+ //TODO: detect units
1892
+ var radX = $.angle.degreeToRadian(degX),
1893
+ radY = $.angle.degreeToRadian(degY),
1894
+ x = Math.tan(radX),
1895
+ y = Math.tan(radY);
1896
+
1897
+ return new $m2x2(
1898
+ 1, x,
1899
+ y, 1
1900
+ );
1901
+ },
1902
+
1903
+ /**
1904
+ * Skews on the X-axis
1905
+ * @param Number degX
1906
+ * @return Matrix
1907
+ * @link http://www.w3.org/TR/SVG/coords.html#SkewXDefined
1908
+ */
1909
+ skewX: function (degX) {
1910
+ return $m.skew(degX);
1911
+ },
1912
+
1913
+ /**
1914
+ * Skews on the Y-axis
1915
+ * @param Number degY
1916
+ * @return Matrix
1917
+ * @link http://www.w3.org/TR/SVG/coords.html#SkewYDefined
1918
+ */
1919
+ skewY: function (degY) {
1920
+ return $m.skew(0, degY);
1921
+ },
1922
+
1923
+ /**
1924
+ * Translate
1925
+ * @param Number tx
1926
+ * @param Number ty
1927
+ * @return Matrix
1928
+ * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1929
+ */
1930
+ translate: function (tx, ty) {
1931
+ tx = tx || 0;
1932
+ ty = ty || 0;
1933
+
1934
+ return new $m3x3(
1935
+ 1, 0, tx,
1936
+ 0, 1, ty,
1937
+ 0, 0, 1
1938
+ );
1939
+ },
1940
+
1941
+ /**
1942
+ * Translate on the X-axis
1943
+ * @param Number tx
1944
+ * @return Matrix
1945
+ * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1946
+ */
1947
+ translateX: function (tx) {
1948
+ return $m.translate(tx);
1949
+ },
1950
+
1951
+ /**
1952
+ * Translate on the Y-axis
1953
+ * @param Number ty
1954
+ * @return Matrix
1955
+ * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1956
+ */
1957
+ translateY: function (ty) {
1958
+ return $m.translate(0, ty);
1959
+ }
1960
+ });
1961
+ })(jQuery, this, this.document);