PageSourceSearch

https://www.marumine.co.jp/js/jquery.transform.js

js marumine.co.jp collected 2026-10-04 05:01:38 UTC 58,792 bytes, 2,288 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.