PageSourceSearch

https://www.duaexplorer.com/Scripts/jquery.transform.js

js duaexplorer.com collected 2026-10-02 00:29:22 UTC 13,260 bytes, 532 lines download raw bytes

1/*
2 * transform: A jQuery cssHooks adding cross-browser 2d transform capabilities to $.fn.css() and $.fn.animate()
3 *
4 * limitations:
5 * - requires jQuery 1.4.3+
6 * - Should you use the *translate* property, then your elements need to be absolutely positionned in a relatively positionned wrapper **or it will fail in IE678**.
7 * - transformOrigin is not accessible
8 *
9 * latest version and complete README available on Github:
10 * https://github.com/louisremi/jquery.transform.js
11 *
12 * Copyright 2011 @louis_remi
13 * Licensed under the MIT license.
14 *
15 * This saved you an hour of work?
16 * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON
17 *
18 */
19(function( $ ) {
20
21/*
22 * Feature tests and global variables
23 */
24var div = document.createElement('div'),
25	divStyle = div.style,
26	propertyName = 'transform',
27	suffix = 'Transform',
28	testProperties = [
29		'O' + suffix,
30		'ms' + suffix,
31		'Webkit' + suffix,
32		'Moz' + suffix,
33		// prefix-less property
34		propertyName
35	],
36	i = testProperties.length,
37	supportProperty,
38	supportMatrixFilter,
39	propertyHook,
40	propertyGet,
41	rMatrix = /Matrix([^)]*)/;
42
43// test different vendor prefixes of this property
44while ( i-- ) {
45	if ( testProperties[i] in divStyle ) {
46		$.support[propertyName] = supportProperty = testProperties[i];
47		continue;
48	}
49}
50// IE678 alternative
51if ( !supportProperty ) {
52	$.support.matrixFilter = supportMatrixFilter = divStyle.filter === '';
53}
54// prevent IE memory leak
55div = divStyle = null;
56
57// px isn't the default unit of this property
58$.cssNumber[propertyName] = true;
59
60/*
61 * fn.css() hooks
62 */
63if ( supportProperty && supportProperty != propertyName ) {
64	// Modern browsers can use jQuery.cssProps as a basic hook
65	$.cssProps[propertyName] = supportProperty;
66	
67	// Firefox needs a complete hook because it stuffs matrix with 'px'
68	if ( supportProperty == 'Moz' + suffix ) {
69		propertyHook = {
70			get: function( elem, computed ) {
71				return (computed ?
72					// remove 'px' from the computed matrix
73					$.css( elem, supportProperty ).split('px').join(''):
74					elem.style[supportProperty]
75				)
76			},
77			set: function( elem, value ) {
78				// remove 'px' from matrices
79				elem.style[supportProperty] = /matrix[^)p]*\)/.test(value) ?
80					value.replace(/matrix((?:[^,]*,){4})([^,]*),([^)]*)/, 'matrix$1$2px,$3px'):
81					value;
82			}
83		}
84	/* Fix two jQuery bugs still present in 1.5.1
85	 * - rupper is incompatible with IE9, see http://jqbug.com/8346
86	 * - jQuery.css is not really jQuery.cssProps aware, see http://jqbug.com/8402
87	 */
88	} else if ( /^1\.[0-5](?:\.|$)/.test($.fn.jquery) ) {
89		propertyHook = {
90			get: function( elem, computed ) {
91				return (computed ?
92					$.css( elem, supportProperty.replace(/^ms/, 'Ms') ):
93					elem.style[supportProperty]
94				)
95			}
96		}
97	}
98	/* TODO: leverage hardware acceleration of 3d transform in Webkit only
99	else if ( supportProperty == 'Webkit' + suffix && support3dTransform ) {
100		propertyHook = {
101			set: function( elem, value ) {
102				elem.style[supportProperty] = 
103					value.replace();
104			}
105		}
106	}*/
107	
108} else if ( supportMatrixFilter ) {
109	propertyHook = {
110		get: function( elem, computed ) {
111			var elemStyle = ( computed && elem.currentStyle ? elem.currentStyle : elem.style ),
112				matrix;
113
114			if ( elemStyle && rMatrix.test( elemStyle.filter ) ) {
115				matrix = RegExp.$1.split(',');
116				matrix = [
117					matrix[0].split('=')[1],
118					matrix[2].split('=')[1],
119					matrix[1].split('=')[1],
120					matrix[3].split('=')[1]
121				];
122			} else {
123				matrix = [1,0,0,1];
124			}
125			matrix[4] = elemStyle ? elemStyle.left : 0;
126			matrix[5] = elemStyle ? elemStyle.top : 0;
127			return "matrix(" + matrix + ")";
128		},
129		set: function( elem, value, animate ) {
130			var elemStyle = elem.style,
131				currentStyle,
132				Matrix,
133				filter;
134
135			if ( !animate ) {
136				elemStyle.zoom = 1;
137			}
138
139			value = matrix(value);
140
141			// rotate, scale and skew
142			if ( !animate || animate.M ) {
143				Matrix = [
144					"Matrix("+
145						"M11="+value[0],
146						"M12="+value[2],
147						"M21="+value[1],
148						"M22="+value[3],
149						"SizingMethod='auto expand'"
150				].join();
151				filter = ( currentStyle = elem.currentStyle ) && currentStyle.filter || elemStyle.filter || "";
152
153				elemStyle.filter = rMatrix.test(filter) ?
154					filter.replace(rMatrix, Matrix) :
155					filter + " progid:DXImageTransform.Microsoft." + Matrix + ")";
156
157				// center the transform origin, from pbakaus's Transformie http://github.com/pbakaus/transformie
158				if ( (centerOrigin = $.transform.centerOrigin) ) {
159					elemStyle[centerOrigin == 'margin' ? 'marginLeft' : 'left'] = -(elem.offsetWidth/2) + (elem.clientWidth/2) + 'px';
160					elemStyle[centerOrigin == 'margin' ? 'marginTop' : 'top'] = -(elem.offsetHeight/2) + (elem.clientHeight/2) + 'px';
161				}
162			}
163
164			// translate
165			if ( !animate || animate.T ) {
166				// We assume that the elements are absolute positionned inside a relative positionned wrapper
167				elemStyle.left = value[4] + 'px';
168				elemStyle.top = value[5] + 'px';
169			}
170		}
171	}
172}
173// populate jQuery.cssHooks with the appropriate hook if necessary
174if ( propertyHook ) {
175	$.cssHooks[propertyName] = propertyHook;
176}
177// we need a unique setter for the animation logic
178propertyGet = propertyHook && propertyHook.get || $.css;
179
180/*
181 * fn.animate() hooks
182 */
183$.fx.step.transform = function( fx ) {
184	var elem = fx.elem,
185		start = fx.start,
186		end = fx.end,
187		split,
188		pos = fx.pos,
189		transform,
190		translate,
191		rotate,
192		scale,
193		skew,
194		T = false,
195		M = false,
196		prop;
197	translate = rotate = scale = skew = '';
198
199	// fx.end and fx.start need to be converted to their translate/rotate/scale/skew components
200	// so that we can interpolate them
201	if ( !start || typeof start === "string" ) {
202		// the following block can be commented out with jQuery 1.5.1+, see #7912
203		if (!start) {
204			start = propertyGet( elem, supportProperty );
205		}
206
207		// force layout only once per animation
208		if ( supportMatrixFilter ) {
209			elem.style.zoom = 1;
210		}
211
212		// if the start computed matrix is in end, we are doing a relative animation
213		split = end.split(start);
214		if ( split.length == 2 ) {
215			// remove the start computed matrix to make animations more accurate
216			end = split.join('');
217			fx.origin = start;
218			start = 'none';
219		}
220
221		// start is either 'none' or a matrix(...) that has to be parsed
222		fx.start = start = start == 'none'?
223			{
224				translate: [0,0],
225				rotate: 0,
226				scale: [1,1],
227				skew: [0,0]
228			}:
229			unmatrix( toArray(start) );
230
231		// fx.end has to be parsed and decomposed
232		fx.end = end = ~end.indexOf('matrix')?
233			// bullet-proof parser
234			unmatrix(matrix(end)):
235			// faster and more precise parser
236			components(end);
237
238		// get rid of properties that do not change
239		for ( prop in start) {
240			if ( prop == 'rotate' ?
241				start[prop] == end[prop]:
242				start[prop][0] == end[prop][0] && start[prop][1] == end[prop][1]
243			) {
244				delete start[prop];
245			}
246		}
247	}
248
249	/*
250	 * We want a fast interpolation algorithm.
251	 * This implies avoiding function calls and sacrifying DRY principle:
252	 * - avoid $.each(function(){})
253	 * - round values using bitewise hacks, see http://jsperf.com/math-round-vs-hack/3
254	 */
255	if ( start.translate ) {
256		// round translate to the closest pixel
257		translate = ' translate('+
258			((start.translate[0] + (end.translate[0] - start.translate[0]) * pos + .5) | 0) +'px,'+
259			((start.translate[1] + (end.translate[1] - start.translate[1]) * pos + .5) | 0) +'px'+
260		')';
261		T = true;
262	}
263	if ( start.rotate != undefined ) {
264		rotate = ' rotate('+ (start.rotate + (end.rotate - start.rotate) * pos) +'rad)';
265		M = true;
266	}
267	if ( start.scale ) {
268		scale = ' scale('+
269			(start.scale[0] + (end.scale[0] - start.scale[0]) * pos) +','+
270			(start.scale[1] + (end.scale[1] - start.scale[1]) * pos) +
271		')';
272		M = true;
273	}
274	if ( start.skew ) {
275		skew = ' skew('+
276			(start.skew[0] + (end.skew[0] - start.skew[0]) * pos) +'rad,'+
277			(start.skew[1] + (end.skew[1] - start.skew[1]) * pos) +'rad'+
278		')';
279		M = true;
280	}
281
282	// In case of relative animation, restore the origin computed matrix here.
283	transform = fx.origin ?
284		fx.origin + translate + skew + scale + rotate:
285		translate + rotate + scale + skew;
286
287	propertyHook && propertyHook.set ?
288		propertyHook.set( elem, transform, {M: M, T: T} ):
289		elem.style[supportProperty] = transform;
290};
291
292/*
293 * Utility functions
294 */
295
296// turns a transform string into its 'matrix(A,B,C,D,X,Y)' form (as an array, though)
297function matrix( transform ) {
298	transform = transform.split(')');
299	var
300			trim = $.trim
301		// last element of the array is an empty string, get rid of it
302		, i = transform.length -1
303		, split, prop, val
304		, A = 1
305		, B = 0
306		, C = 0
307		, D = 1
308		, A_, B_, C_, D_
309		, tmp1, tmp2
310		, X = 0
311		, Y = 0
312		;
313	// Loop through the transform properties, parse and multiply them
314	while (i--) {
315		split = transform[i].split('(');
316		prop = trim(split[0]);
317		val = split[1];
318		A_ = B_ = C_ = D_ = 0;
319
320		switch (prop) {
321			case 'translateX':
322				X += parseInt(val, 10);
323				continue;
324
325			case 'translateY':
326				Y += parseInt(val, 10);
327				continue;
328
329			case 'translate':
330				val = val.split(',');
331				X += parseInt(val[0], 10);
332				Y += parseInt(val[1] || 0, 10);
333				continue;
334
335			case 'rotate':
336				val = toRadian(val);
337				A_ = Math.cos(val);
338				B_ = Math.sin(val);
339				C_ = -Math.sin(val);
340				D_ = Math.cos(val);
341				break;
342
343			case 'scaleX':
344				A_ = val;
345				D_ = 1;
346				break;
347
348			case 'scaleY':
349				A_ = 1;
350				D_ = val;
351				break;
352
353			case 'scale':
354				val = val.split(',');
355				A_ = val[0];
356				D_ = val.length>1 ? val[1] : val[0];
357				break;
358
359			case 'skewX':
360				A_ = D_ = 1;
361				C_ = Math.tan(toRadian(val));
362				break;
363
364			case 'skewY':
365				A_ = D_ = 1;
366				B_ = Math.tan(toRadian(val));
367				break;
368
369			case 'skew':
370				A_ = D_ = 1;
371				val = val.split(',');
372				C_ = Math.tan(toRadian(val[0]));
373				B_ = Math.tan(toRadian(val[1] || 0));
374				break;
375
376			case 'matrix':
377				val = val.split(',');
378				A_ = +val[0];
379				B_ = +val[1];
380				C_ = +val[2];
381				D_ = +val[3];
382				X += parseInt(val[4], 10);
383				Y += parseInt(val[5], 10);
384		}
385		// Matrix product
386		tmp1 = A * A_ + B * C_;
387		B    = A * B_ + B * D_;
388		tmp2 = C * A_ + D * C_;
389		D    = C * B_ + D * D_;
390		A = tmp1;
391		C = tmp2;
392	}
393	return [A,B,C,D,X,Y];
394}
395
396// turns a matrix into its rotate, scale and skew components
397// algorithm from http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp
398function unmatrix(matrix) {
399	var
400			scaleX
401		, scaleY
402		, skew
403		, A = matrix[0]
404		, B = matrix[1]
405		, C = matrix[2]
406		, D = matrix[3]
407		;
408
409	// Make sure matrix is not singular
410	if ( A * D - B * C ) {
411		// step (3)
412		scaleX = Math.sqrt( A * A + B * B );
413		A /= scaleX;
414		B /= scaleX;
415		// step (4)
416		skew = A * C + B * D;
417		C -= A * skew;
418		D -= B * skew;
419		// step (5)
420		scaleY = Math.sqrt( C * C + D * D );
421		C /= scaleY;
422		D /= scaleY;
423		skew /= scaleY;
424		// step (6)
425		if ( A * D < B * C ) {
426			//scaleY = -scaleY;
427			//skew = -skew;
428			A = -A;
429			B = -B;
430			skew = -skew;
431			scaleX = -scaleX;
432		}
433
434	// matrix is singular and cannot be interpolated
435	} else {
436		rotate = scaleX = scaleY = skew = 0;
437	}
438
439	return {
440		translate: [+matrix[4], +matrix[5]],
441		rotate: Math.atan2(B, A),
442		scale: [scaleX, scaleY],
443		skew: [skew, 0]
444	}
445}
446
447// parse tranform components of a transform string not containing 'matrix(...)'
448function components( transform ) {
449	// split the != transforms
450  transform = transform.split(')');
451
452	var translate = [0,0],
453    rotate = 0,
454    scale = [1,1],
455    skew = [0,0],
456    i = transform.length -1,
457    trim = $.trim,
458    split, name, value;
459
460  // add components
461  while ( i-- ) {
462    split = transform[i].split('(');
463    name = trim(split[0]);
464    value = split[1];
465    
466    if (name == 'translateX') {
467      translate[0] += parseInt(value, 10);
468
469    } else if (name == 'translateY') {
470      translate[1] += parseInt(value, 10);
471
472    } else if (name == 'translate') {
473      value = value.split(',');
474      translate[0] += parseInt(value[0], 10);
475      translate[1] += parseInt(value[1] || 0, 10);
476
477    } else if (name == 'rotate') {
478      rotate += toRadian(value);
479
480    } else if (name == 'scaleX') {
481      scale[0] *= value;
482
483    } else if (name == 'scaleY') {
484      scale[1] *= value;
485
486    } else if (name == 'scale') {
487      value = value.split(',');
488      scale[0] *= value[0];
489      scale[1] *= (value.length>1? value[1] : value[0]);
490
491    } else if (name == 'skewX') {
492      skew[0] += toRadian(value);
493
494    } else if (name == 'skewY') {
495      skew[1] += toRadian(value);
496
497    } else if (name == 'skew') {
498      value = value.split(',');
499      skew[0] += toRadian(value[0]);
500      skew[1] += toRadian(value[1] || '0');
501    }
502	}
503
504  return {
505    translate: translate,
506    rotate: rotate,
507    scale: scale,
508    skew: skew
509  };
510}
511
512// converts an angle string in any unit to a radian Float
513function toRadian(value) {
514	return ~value.indexOf('deg') ?
515		parseInt(value,10) * (Math.PI * 2 / 360):
516		~value.indexOf('grad') ?
517			parseInt(value,10) * (Math.PI/200):
518			parseFloat(value);
519}
520
521// Converts 'matrix(A,B,C,D,X,Y)' to [A,B,C,D,X,Y]
522function toArray(matrix) {
523	// Fremove the unit of X and Y for Firefox
524	matrix = /\(([^,]*),([^,]*),([^,]*),([^,]*),([^,p]*)(?:px)?,([^)p]*)(?:px)?/.exec(matrix);
525	return [matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]];
526}
527
528$.transform = {
529	centerOrigin: 'margin'
530};
531
532})( jQuery );

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.