1 /*
  2 * jquery.transform.js
  3 * Visit the internets for documentation, updates and examples.
  4 * https://github.com/pwhisenhunt/jquery.transform.js
  5 *
  6 *
  7 * Copyright (c) 2010 Phillip J. Whisenhunt phillip.whisenhunt@gmail.com http://phillipwhisenhunt.com
  8 * 
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without
 12 * restriction, including without limitation the rights to use,
 13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 14 * copies of the Software, and to permit persons to whom the
 15 * Software is furnished to do so, subject to the following
 16 * conditions:
 17 * 
 18 * The above copyright notice and this permission notice shall be
 19 * included in all copies or substantial portions of the Software.
 20 * 
 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 28 * OTHER DEALINGS IN THE SOFTWARE.
 29 */
 30 
 31 
 32 /** @fileoverview jQuery Transform - A jQuery plugin for 3D and 2D transformations.
 33  *  @author  Phillip J. Whisenhunt
 34  *  @version 1.0
 35  *  @requires jQuery 1.6 +
 36  */
 37 (function( $ ){
 38 	/** @class jQuery.Transform
 39 	*/
 40 	var methods = {		
 41 		/** Decrease the height of the given element.
 42  		* @param {int} value The amount in pixels to decrease height of the element.
 43 		* @return {void} none
 44 		* @name decreaseHeight
 45 		* @function
 46  		*/
 47 		decreaseHeight : function( value ) {
 48     	return this.each(function(){
 49 				$(this).data({ 'height' : ($(this).data("height") - value) });
 50 				$(this).animate({ height:  $(this).data("height") }, $(this).data('animationDuration') * 1000);	//multiply by 1000 since animationDuration is in secs.
 51 			});
 52 		},
 53 		
 54 		/** Decrease the width of the given element.
 55  		* @param {int} value The amount in pixels to decrease the width of the element.
 56 		* @return {void} none
 57 		* @name decreaseWidth
 58 		* @function
 59  		*/
 60 		decreaseWidth : function( value ) {
 61     	return this.each(function(){
 62 				$(this).data({ 'width' : ($(this).data("width") - value) });
 63 				$(this).animate({ width:  $(this).data("width") }, $(this).data('animationDuration') * 1000);	//multiply by 1000 since animationDuration is in secs.
 64 			});
 65 		},
 66 		
 67 		/** Returns the x-axis position of the element
 68 		* @return {int} x-axis value
 69 		* @name getX
 70 		* @function
 71 		 */
 72 		getX : function() { if(!isNaN($(this).data('x'))){ return $(this).data('x'); } else{ init(this); return 0; }; },
 73 		/** Returns the y-axis position of the element 
 74 		* @return {int} y-axis value
 75 		* @name getY
 76 		* @function
 77 		*/
 78 		getY : function() { if(!isNaN($(this).data('y'))){ return $(this).data('y'); } else{ init(this); return 0; }; },
 79 		/** Returns the z-axis position of the element 
 80 		* @return {int} z-axis value
 81 		* @name getZ
 82 		* @function
 83 		*/
 84 		getZ : function() { if(!isNaN($(this).data('z'))){ return $(this).data('z'); } else{ init(this); return 0; }; },
 85 		/** Returns the scale of the element 
 86 		* @return {int} scale value
 87 		* @name getScale
 88 		* @function
 89 		*/
 90 		getScale : function() { if(!isNaN($(this).data('scale'))){ return $(this).data('scale'); } else{ init(this); return 0; }; },
 91 		/** Returns the animation duration of the element 
 92 		* @return {float} animation duration value
 93 		* @name getAnimationDuration
 94 		* @function
 95 		*/
 96 		getAnimationDuration : function() { if(!isNaN($(this).data('animationDuration'))){ return $(this).data('animationDuration'); } else{ init(this); return 0; }; },
 97 		/** Returns the width of the element 
 98 		* @return {int} width value
 99 		* @name getWidth
100 		* @function
101 		*/
102 		getWidth : function() { if(!isNaN($(this).data('width'))){ return $(this).data('width'); } else{ init(this); return $(this).outerWidth(); }; },
103 		/** Returns the height of the element 
104 		* @return {int} height value
105 		* @name getHeight
106 		* @function
107 		*/
108 		getHeight : function() { if(!isNaN($(this).data('width'))){ return $(this).data('width'); } else{ init(this); return $(this).outerHeight(); }; },
109 		/** Returns the elements amount of rotation about the x-axis 
110 		* @return {int} x rotation value
111 		* @name getRotationX
112 		* @function
113 		*/
114 		getRotationX : function() { if(!isNaN($(this).data('rotationX'))){ return $(this).data('rotationX'); } else{ init(this); return 0; }; },
115 		/** Returns the elements amount of rotation about the y-axis 
116 		* @return {int} y rotation value
117 		* @name getRotationY
118 		* @function
119 		*/
120 		getRotationY : function() { if(!isNaN($(this).data('rotationY'))){ return $(this).data('rotationY'); } else{ init(this); return 0; }; },
121 		/** Returns the elements amount of rotation about the z-axis 
122 		* @return {int} z rotation value
123 		* @name getRotationZ
124 		* @function
125 		*/
126 		getRotationZ : function() { if(!isNaN($(this).data('rotationZ'))){ return $(this).data('rotationZ'); } else{ init(this); return 0; }; },
127 	
128 		/**
129  		* Increases the height of the given element.
130  		* @param {int} value The amount in pixels to increase the height of the element.
131 		* @return {void} none
132 		* @name increaseHeight
133 		* @function
134  		*/
135 		increaseHeight : function( value ) {
136     	return this.each(function(){
137 				$(this).data({ 'height' : (value + $(this).data("height")) });
138 				$(this).animate({ height:  $(this).data("height") }, $(this).data('animationDuration') * 1000);	//multiply by 1000 since animationDuration is in secs.
139 			});
140 		},
141 		
142 		/**
143  		* Increases the width of the given element.
144  		* @param {int} value The amount in pixels to increase the width of the element.
145 		* @return {void} none
146 		* @name increaseWidth
147 		* @function
148  		*/
149 		increaseWidth : function( value ) {
150     	return this.each(function(){
151 				$(this).data({ 'width' : (value + $(this).data("width")) });
152 				$(this).animate({ width:  $(this).data("width") }, $(this).data('animationDuration') * 1000);	//multiply by 1000 since animationDuration is in secs.
153 			});
154 		},
155 
156 		/**
157 	 	* Rotates the element along the x axis in addition to the current rotation.
158 	 	* @param {int} value The degree of rotation along the x-axis
159 		* @return {int} none
160 		* @name rotateX
161 		* @function
162 	 */
163 		rotateX : function( value ){
164 			return this.each(function(){
165 				if(isNaN($(this).data('rotationX'))){
166 					init(this);
167 					$(this).transform('rotateX', value);
168 				}
169 				else{
170 					$(this).data( { 'rotationX' : $(this).data('rotationX') + value } );
171 					updateTransform(this);
172 				}
173 			});
174 		},
175 		
176 		/**
177 	 	* Rotates the element along the y axis in addition to the current rotation.
178 	 	* @param {int} value The degree of rotation along the y-axis
179 		* @return {int} none
180 		* @name rotateY
181 		* @function
182 	 */
183 		rotateY : function( value ){
184 			return this.each(function(){
185 				if(isNaN($(this).data('rotationY'))){
186 					init(this);
187 					$(this).transform('rotateY', value);
188 				}
189 				else{
190 					$(this).data( { 'rotationY' : $(this).data('rotationY') + value } );
191 					updateTransform(this);
192 				}
193 			});
194 		},
195 		
196 		/**
197 	 	* Rotates the element along the z axis in addition to the current rotation.
198 	 	* @param {int} value The degree of rotation along the z-axis
199 		* @return {int} none
200 		* @name rotateZ
201 		* @function
202 	 */
203 		rotateZ : function( value ){
204 			return this.each(function(){
205 				if(isNaN($(this).data('rotationZ'))){
206 					init(this);
207 					$(this).transform('rotateZ', value);
208 				}
209 				else{
210 					$(this).data( { 'rotationZ' : $(this).data('rotationZ') + value } );
211 					updateTransform(this);
212 				}
213 			});
214 		},
215 		
216 		/**
217 	 	* Rotates the element along the x, y, and z-axis.
218 	 	* @param {int} y The amount of rotation along x-axis.
219 	 	* @param {int} x The amount of rotation along y-axis.
220 	 	* @param {int} z The amount of rotation along z-axis.
221 		* @return {void} none
222 		* @name rotateXYZ
223 		* @function
224 	 */
225 		rotateXYZ : function( x, y, z ){
226 			return this.each(function(){
227 				if(isNaN($(this).data('rotationX')) || isNaN($(this).data('rotationY')) || isNaN($(this).data('rotationZ'))){
228 					init(this);
229 					$(this).transform('rotateXYZ', x, y, z);
230 				}
231 				else{
232 					$(this).data( { 'rotationX' : $(this).data('rotationX') + x } );
233 					$(this).data( { 'rotationY' : $(this).data('rotationY') + y } );
234 					$(this).data( { 'rotationZ' : $(this).data('rotationZ') + z } );
235 					updateTransform(this);
236 				}
237 			});
238 		},
239 		
240 		/**
241 	 	* Sets the animation duration of the given element.
242 	 	* @param {int} value The animation duration for the given element.
243 		* @return {void} none
244 		* @name setAnimationDuration
245 		* @function
246 	 */
247 		setAnimationDuration : function( value ){
248 			return this.each(function(){
249 				if(isNaN($(this).data('animationDuration'))){
250 					init(this);
251 					$(this).transform('setAnimationDuration', value);
252 				}
253 				else{
254 					$(this).data({ 'animationDuration' : value });
255 					updateTransform(this);
256 				}
257 			});
258 		},
259 
260 		/**
261  		* Sets the height of the given element.
262  		* @param {int} value The height of the element.
263 		* @return {void} none
264 		* @name setHeight
265 		* @function
266  		*/
267 		setHeight : function( value ){
268 			return this.each(function(){
269 				$(this).animate({ height: value }, $(this).data('animationDuration') * 1000);		//multiply by 1000 since animationDuration is in secs.
270 				$(this).data({ 'height' : value });
271 			});
272 		},
273 		
274 		/**
275  		* Sets the width of the given element.
276  		* @param {int} value The width of the element.
277 		* @return {void} none
278 		* @name setWidth
279 		* @function
280  		*/
281 		setWidth : function( value ) {
282     	return this.each(function(){
283 				$(this).animate({ width: value }, $(this).data('animationDuration') * 1000);	//multiply by 1000 since animationDuration is in secs.
284 				$(this).data({ 'width' : value });
285 			});
286 		},
287 
288 		/**
289  		* Sets the scale of the given element.
290  		* @param {int} value The scale of the given element.
291 		* @return {void} none
292 		* @name setScale
293 		* @function
294  		*/
295 		setScale : function( value ){
296 			return this.each(function(){
297 				if(isNaN($(this).data('scale'))){
298 					init(this);
299 					$(this).transform('setScale', value);
300 				}
301 				else{
302 					$(this).data({ 'scale' : value });
303 					updateTransform(this);
304 				}
305 			});
306 		},
307 
308 		/**
309  		* Sets the elements x position.
310  		* @param {int} value The position along the x-axis to set the element.
311 		* @return {void} none
312 		* @name setX
313 		* @function
314  		*/
315 		setX : function( value ){
316 			return this.each(function(){
317 				if(isNaN($(this).data('x'))){
318 					init(this);
319 					$(this).transform('setX', value);
320 				}
321 				else{
322 					$(this).data({ 'x' : value });
323 					updateTransform(this);
324 				}
325 			});
326 		},
327 		
328 		/**
329 	 	* Sets the elements y position.
330 	 	* @param {int} value The position along the y-axis to set the element.
331 		* @return {void} none
332 		* @name setY
333 		* @function
334 	 */
335 		setY : function( value ){
336 			return this.each(function(){
337 				if(isNaN($(this).data('y'))){
338 					init(this);
339 					$(this).transform('setY', value);
340 				}
341 				else{
342 					$(this).data({ 'y' : value });
343 					updateTransform(this);
344 				}
345 			});			
346 		},
347 		
348 		/**
349 	 	* Sets the elements z position.
350 	 	* @param {int} value The position along the z-axis to set the element.
351 		* @return {void} none
352 		* @name setZ
353 		* @function
354 	 */
355 		setZ : function( value ){
356 			return this.each(function(){
357 				if(isNaN($(this).data('z'))){
358 					init(this);
359 					$(this).transform('setZ', value);
360 				}
361 				else{
362 					$(this).data({ 'z' : value });
363 					updateTransform(this);
364 				}
365 			});
366 		},
367 
368 		/** Sets the amount of rotation of the x-axis.
369 	 	* @param {int} value The amount of rotation along the x-axis.
370 		* @return {void} none
371 		* @name setRotationX
372 		* @function
373 	 */
374 		setRotationX : function( value ){
375 			return this.each(function(){
376 				if(isNaN($(this).data('rotationX'))){
377 					init(this);
378 					$(this).transform('setRotationX', value);
379 				}
380 				else{
381 					$(this).data({ 'rotationX' : value });
382 					updateTransform(this);
383 				}
384 			});
385 		},
386 		
387 		/**
388 	 	* Sets the amount of rotation along the x, y, and z-axis.
389 	 	* @param {int} x The amount of rotation along the x-axis.
390 	 	* @param {int} y The amount of rotation along the y-axis.
391 	 	* @param {int} z The amount of rotation along the z-axis.	
392 		* @return {void} none
393 		* @name setRotationXYZ
394 		* @function
395 	 */
396 		setRotationXYZ : function( x, y, z ){
397 			return this.each(function(){
398 				if(isNaN($(this).data('rotationX')) || isNaN($(this).data('rotationY')) || isNaN($(this).data('rotationZ'))){
399 					init(this);
400 					$(this).transform('setRotationXYZ', x, y, z);
401 				}
402 				else{
403 					$(this).data( { 'rotationX' : x } );
404 					$(this).data( { 'rotationY' : y } );
405 					$(this).data( { 'rotationZ' : z } );
406 					updateTransform(this);
407 				}
408 			});
409 		},
410 		
411 		/**
412 	 	* Sets the amount of rotation of the y-axis.
413 	 	* @param {int} value The amount of rotation along the y-axis.
414 		* @return {void} none
415 		* @name setRotationY
416 		* @function
417 	 */
418 		setRotationY : function( value ){
419 			return this.each(function(){
420 				if(isNaN($(this).data('rotationY'))){
421 					init(this);
422 					$(this).transform('setRotationY', value);
423 				}
424 				else{
425 					$(this).data({ 'rotationY' : value });
426 					updateTransform(this);
427 				}
428 			});	
429 		},
430 		
431 		/**
432 	 	* Sets the amount of rotation of the z-axis.
433 	 	* @param {int} value The amount of rotation along the z-axis.
434 		* @return {void} none
435 		* @name setRotationZ
436 		* @function
437 	 */
438 		setRotationZ : function( value ){
439 			return this.each(function(){
440 				if(isNaN($(this).data('rotationZ'))){
441 					init(this);
442 					$(this).transform('setRotationZ', value);
443 				}
444 				else{
445 					$(this).data({ 'rotationZ' : value });
446 					updateTransform(this);
447 				}
448 			});
449 		},
450 				
451 		/**
452 	 	* Translates the element along the x axis.
453 	 	* @param {int} value The amount to translate on the x-axis
454 		* @return {void} none
455 		* @name translateX
456 		* @function
457 	 */
458 		translateX : function( value ){
459 			return this.each(function(){
460 				if(isNaN($(this).data('x'))){
461 					init(this);
462 					$(this).transform('translateX', value);
463 				}
464 				else{
465 					$(this).data({ 'x' : $(this).data('x') + value });
466 					updateTransform(this);
467 				}
468 			});
469 		},
470 		
471 		/**
472 	 	* Translates the element along the x, y, and z-axis.
473 	 	* @param {int} x The amount of translation along x-axis.
474 	 	* @param {int} y The amount of translation along y-axis.
475 	 	* @param {int} z The amount of translation along z-axis.
476 		* @return {void} none
477 		* @name translateXYZ
478 		* @function
479 	 */
480 		translateXYZ : function( x, y, z ){
481 			return this.each(function(){
482 				if(isNaN($(this).data('x')) || isNaN($(this).data('y')) || isNaN($(this).data('z'))){
483 					init(this);
484 					$(this).transform('translateXYZ', x, y, z);
485 				}
486 				else{
487 					$(this).data({ 'x' : $(this).data('x') + x });
488 					$(this).data({ 'y' : $(this).data('y') + y });
489 					$(this).data({ 'z' : $(this).data('z') + z });
490 					updateTransform(this);
491 				}
492 			});			
493 		},
494 		
495 		/**
496 	 	* Translates the element along the y axis.
497 	 	* @param {int} value The amount to translate on the y-axis
498 		* @return {void} none
499 		* @name translateY
500 		* @function
501 	 */
502 		translateY : function( value ){
503 			return this.each(function(){
504 				if(isNaN($(this).data('y'))){
505 					init(this);
506 					$(this).transform('translateY', value);
507 				}
508 				else{
509 					$(this).data({ 'y' : $(this).data('y') + value });
510 					updateTransform(this);
511 				}
512 			});
513 		},
514 		
515 		/**
516 	 	* Translates the element along the z axis.
517 	 	* @param {int} value The amount to translate on the z-axis
518 		* @return {void} none
519 		* @name translateZ
520 		* @function
521 	 */
522 		translateZ : function( value ){
523 			return this.each(function(){
524 				if(isNaN($(this).data('z'))){
525 					init(this);
526 					$(this).transform('translateZ', value);
527 				}
528 				else{
529 					$(this).data({ 'z' : $(this).data('z') + value });
530 					updateTransform(this);
531 				}
532 			});
533 		}
534 	};
535 	
536 	/**
537  	* Updates the webkit, moz, and transform transformation of the element based on stored data.
538  	* @param {DOM element} element The element to transform.
539 	* @return {void} none
540 	* @name updateTransform
541 	* @function
542  */
543 	function updateTransform(element){
544 		$(element).css({ "-webkit-transition": "-webkit-transform " + $(element).data('animationDuration') + "s",
545 		"-webkit-transform-style": "preserve-3d", 
546 		"-webkit-transform": "translateX(" + $(element).data('x') + "px)" + " translateY(" + $(element).data('y') + "px)" +  " translateZ(" + $(element).data('z') + "px)" + " scale(" + $(element).data('scale') + ")" + " rotateX(" + $(element).data('rotationX') + "deg)" + " rotateY(" + $(element).data('rotationY') + "deg)" + " rotateZ(" + $(element).data('rotationZ') + "deg)",
547 		"-moz-transform": "translateX(" + $(element).data('x') + "px)" + " translateY(" + $(element).data('y') + "px)" +  " translateZ(" + $(element).data('z') + "px)" + " scale(" + $(element).data('scale') + ")" + " rotateX(" + $(element).data('rotationX') + "deg)" + " rotateY(" + $(element).data('rotationY') + "deg)" + " rotateZ(" + $(element).data('rotationZ') + "deg)",
548 		"-moz-transition": "-moz-transform " + $(element).data('animationDuration') + "s",
549 		"-moz-transform-style": "preserve-3d",
550 		"transform": "translateX(" + $(element).data('x') + "px)" + " translateY(" + $(element).data('y') + "px)" +  " translateZ(" + $(element).data('z') + "px)" + " scale(" + $(element).data('scale') + ")" + " rotateX(" + $(element).data('rotationX') + "deg)" + " rotateY(" + $(element).data('rotationY') + "deg)" + " rotateZ(" + $(element).data('rotationZ') + "deg)",
551 		"transition": "transform " + $(element).data('animationDuration') + "s",
552 		"transform-style": "preserve-3d",
553 	  });
554 	}
555 	
556 	/**
557  	* Sets 3D data corresponding to a DOM element.
558 	* @param {element} element the element to update.
559  	* @param {int} rotationX
560  	* @param {int} rotationY
561  	* @param {int} rotationZ
562  	* @param {int} x
563  	* @param {int} y
564  	* @param {int} z
565  	* @param {int} scale
566  	* @param {int} animationDuration
567  	* @param {int} width
568  	* @param {int} height
569 	* @return {void} none
570 	* @name init
571 	* @function
572  */
573 	function init(element, options){
574 		// default values
575 		defaults = {
576 			x: 0,
577 			y: 0,
578 			z: 0,
579 			rotationX: 0,
580 			rotationY: 0,
581 			rotationZ: 0,
582 			scale: 1,
583 			animationDuration: 0.01,
584 			width: $(element).outerWidth(),
585 			height: $(element).outerHeight()
586 		};
587 		// override defaults values with those passed in by the user
588 		options = $.extend(defaults, options);
589 		
590 		//trigger 3D hardware accelleration
591 		$(element).css({"-webkit-transition": "translateZ(0px) translateX(0px) translateY(0px)", "-webkit-transform-style": "preserve-3d", "-moz-transition": "translateZ(0px) translateX(0px) translateY(0px)", "-moz-transform-style": "preserve-3d", "transition": "translateZ(0px) translateX(0px) translateY(0px)", "transform-style": "preserve-3d",});
592 		
593 		//store the data associated with the dom element.
594 		$(element).data({
595 			"x" : options.x, 
596 			"y" : options.y, 
597 			"z" : options.z, 
598 			"rotationX" : options.rotationX, 
599 			"rotationY" : options.rotationY, 
600 			"rotationZ" : options.rotationX,
601 			"scale": 1,
602 			"animationDuration": options.animationDuration,
603 			"width" : options.width, 
604 			"height" : options.height
605 			});
606 	}
607 
608 	/**
609  	* Extending the jQuery namespace for the plugin.
610  	* @param {string} method The method to call.
611 	* @return {void} none
612 	* @name $.fn.tranform
613 	* @function
614  */
615 	$.fn.transform = function( method ) {
616 		if ( methods[method] ) {
617 			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
618 		} 
619 		else if ( typeof method === 'object' || ! method ) {
620 			return methods.init.apply( this, arguments );
621 		} 
622 		else {
623 			$.error( 'Method ' +  method + ' does not exist on jQuery.transform' );
624 		}    
625 	};
626 })( jQuery );