diff --git a/README.markdown b/README.markdown index 5e1197e..7054c21 100644 --- a/README.markdown +++ b/README.markdown @@ -41,10 +41,9 @@ Bezier curves are made form a start point, an end point each with a control poin Arc --- -Exampe: animate along an arc +Example: animate along an arc -
-  
+
  
 var arc_params = {
     center: [285,185],	
 		radius: 100,	
@@ -62,6 +61,128 @@ $("my_elem").animate({path : new $.path.arc(arc_params)})
 * end is the angle of the start point. 0 is "North", measured clockwise
 * dir is the direction to move in. Only required if not obvious from start and end (e.g. if start is 100, end is 30, but you want to animate clockwise)
 
+### Advanced Arcs ###
+
+Example: add a spiral to the arc
+
+
+var arc_params = {
+    center: [285, 185],
+    spiral: [1, 100],
+    start: 30,
+    end: 200,
+    dir: -1
+  }
+
+  $('my_elem').animate({path : new $.path.arc(arc_params)})
+
+ +Example: use another path as the center of the arc + +
+var bezier_params = {
+    start: { 
+      x: 185, 
+      y: 185, 
+      angle: 10
+    },  
+    end: { 
+      x:540,
+      y:110, 
+      angle: -10, 
+      length: 0.25
+    }
+  }
+
+var arc_params = {
+    center: new $.path.bezier(bezier_params),
+    radius: 100,
+    start: 30,
+    end: 200,
+    dir: -1
+  }
+
+$('my_elem').animate({path : new $.path.arc(arc_params)})
+
+ +Example: combine both the spiral and center paths +
+var bezier_params = {
+    start: { 
+      x: 185, 
+      y: 185, 
+      angle: 10
+    },  
+    end: { 
+      x:540,
+      y:110, 
+      angle: -10, 
+      length: 0.25
+    }
+  }
+
+var arc_params = {
+    center: new $.path.bezier(bezier_params),
+    radius: [1, 100],
+    start: 30,
+    end: 200,
+    dir: -1
+  }
+
+$('my_elem').animate({path : new $.path.arc(arc_params)})
+
+ +Rotation +--- +Rotation can be added to any path by specifying a rotator. + +Example: keep the top of the element facing forward on the path + +
+var bezier_params = {
+    start: { 
+      x: 185, 
+      y: 185, 
+      angle: 10
+    },  
+    end: { 
+      x:540,
+      y:110, 
+      angle: -10, 
+      length: 0.25
+    },
+    rotator: new $.path.rotators.followPath()
+  }
+  
+$("my_elem").animate({path : new $.path.bezier(bezier_params)})
+
+ +Example: make the element spin +
+var spin_params = {
+    start: 30,
+    end: 200,
+    dir: -1
+  }
+
+var bezier_params = {
+    start: { 
+      x: 185, 
+      y: 185, 
+      angle: 10
+    },  
+    end: { 
+      x:540,
+      y:110, 
+      angle: -10, 
+      length: 0.25
+    },
+    rotator: new $.path.rotators.spin(spin_params)
+  }
+  
+$("my_elem").animate({path : new $.path.bezier(bezier_params)})
+
+ Other Paths ---- diff --git a/jquery.path.js b/jquery.path.js index 220b5a0..63be199 100644 --- a/jquery.path.js +++ b/jquery.path.js @@ -1,6 +1,6 @@ /* * jQuery css bezier animation support -- Jonah Fox - * version 0.0.1 + * version 0.0.3 * Released under the MIT license. */ /* @@ -14,7 +14,13 @@ ;(function($){ - $.path = {}; + $.path = { + isPath: function(path) { + return path && + path.css && + path.css.constructor == Function; + } + }; var V = { rotate: function(p, degrees) { @@ -34,7 +40,9 @@ } }; - $.path.bezier = function( params, rotate ) { + $.path.bezier = function(params) { + this.x = params.start.x; + this.y = params.start.y; params.start = $.extend( {angle: 0, length: 0.3333}, params.start ); params.end = $.extend( {angle: 0, length: 0.3333}, params.end ); @@ -60,10 +68,6 @@ /* p from 0 to 1 */ this.css = function(p) { var f1 = this.f1(p), f2 = this.f2(p), f3 = this.f3(p), f4=this.f4(p), css = {}; - if (rotate) { - css.prevX = this.x; - css.prevY = this.y; - } css.x = this.x = ( this.p1[0]*f1 + this.p2[0]*f2 +this.p3[0]*f3 + this.p4[0]*f4 +.5 )|0; css.y = this.y = ( this.p1[1]*f1 + this.p2[1]*f2 +this.p3[1]*f3 + this.p4[1]*f4 +.5 )|0; css.left = css.x + "px"; @@ -72,11 +76,10 @@ }; }; - $.path.arc = function(params, rotate) { + $.path.arc = function(params) { for ( var i in params ) { this[i] = params[i]; } - this.dir = this.dir || 1; while ( this.start > this.end && this.dir > 0 ) { @@ -87,27 +90,102 @@ this.start += 360; } + if(this.spiral) { + if(this.spiral.constructor == Array && this.spiral.length > 1) { + this.radiusStart = this.spiral[0] || 1; + this.radiusEnd = this.spiral[1] || 1; + } else { + this.radiusStart = 1; + this.radiusEnd = (this.spiral.constructor == Array ? this.spiral[0] : this.spiral) || 1; + } + this.radius = this.radiusStart; + this.radiusDiff = Math.abs(this.radiusEnd - this.radiusStart); + } + + if($.path.isPath(this.center)) { + this.centerPath = this.center; + this.center = [0,0]; + } + this.css = function(p) { var a = ( this.start * (p ) + this.end * (1-(p )) ) * Math.PI / 180, css = {}; - if (rotate) { - css.prevX = this.x; - css.prevY = this.y; + if(this.centerPath) { + var pos = this.centerPath.css(p); + this.center[0] = pos.x; + this.center[1] = pos.y; } + css.x = this.x = ( Math.sin(a) * this.radius + this.center[0] +.5 )|0; css.y = this.y = ( Math.cos(a) * this.radius + this.center[1] +.5 )|0; css.left = css.x + "px"; css.top = css.y + "px"; + + if(this.spiral) { + this.radius = this.radiusStart + (this.radiusDiff - (this.radiusDiff * p)); + } + return css; }; }; + // rotators + $.path.rotators = { + isRotator: function(rotator) { + return rotator && + rotator.rotate && + rotator.rotate.constructor == Function && + rotator.unit; + }, + units: { + degrees: 'deg', + gradians: 'grad', + radians: 'rad', + turns: 'turn' + } + }; + + $.path.rotators.followPath = function() { + this.unit = $.path.rotators.units.radians; + this.rotate = function(p, css, prevState) { + return Math.atan2(prevState.y - css.y, prevState.x - css.x); + }; + }; + + $.path.rotators.spin = function (params) { + this.unit = $.path.rotators.units.degrees; + for ( var i in params ) { + this[i] = params[i]; + } + this.dir = this.dir || 1; + + while ( this.start > this.end && this.dir > 0 ) { + this.start -= 360; + } + + while ( this.start < this.end && this.dir < 0 ) { + this.start += 360; + } + + this.diff = this.end - this.start; + + this.rotate = function(p, css, prevCss) { + var pos = this.start - (this.diff - (this.diff * p)); + return pos % 360; + }; + }; + $.fx.step.path = function(fx) { + var prevState = $.extend(true, {}, fx.end); var css = fx.end.css( 1 - fx.pos ); - if ( css.prevX != null ) { - $.cssHooks.transform.set( fx.elem, "rotate(" + Math.atan2(css.prevY - css.y, css.prevX - css.x) + ")" ); + + // note: rotation requires the transform CSS hook (https://github.com/brandonaaron/jquery-cssHooks/blob/master/transform.js) + if($.path.rotators.isRotator(fx.end.rotator) && $.cssHooks.transform) { + var rotation = fx.end.rotator.rotate(1 - fx.pos, css, prevState); + $.cssHooks.transform.set( fx.elem, "rotate(" + rotation + fx.end.rotator.unit + ")" ); } + fx.elem.style.top = css.top; fx.elem.style.left = css.left; };