約束した緩動は?

16555 ワード

jQueryの緩動関数は力がなくて、自分で1つ書くように迫られて、書く以上、まず需要を並べます:
1.アニメーションの種類は:linear,easeIn,easeOut,easeInOut
2.バッファリング中に属性を変更してもよいし、呼び出し関数であってもよいし、関数のパラメータを変更してもよい(後者は私の初心であり、jqは属性のみをサポートし、0が0にぶつかるとを参照)
 
アニメーションはどのように生成されますか?Flashを学んだ人はフレームを知っているはずですが、フレームは1つの画面で、通常は1秒25フレーム、つまり1秒25画面を再生して、このように速く放して、静的にもダイナミックになりました(もちろん、25画面が同じ画面ではないことを前提にして、囧..)
 
まさかアニメーションをするにはN多図を描く必要があります.いいでしょう.これは「フレームごとのアニメーション」と呼ばれています.もしあなたが暇なら、このようにすることができます.このような効果は絶対にトップクラスで、瑕疵がありませんから.しかし、私は少しも暇ではありません.私の絵のレベルは幼稚園でも教えられないので、この道は直接銃殺することができます.
 
次に本題に入ります.Flashにはキーフレームの概念もあります.例えば、キーフレームA、物体boxの幅が100、キーフレームB、boxの幅が50、AとBの間に25フレームあります.次に、AからBまで放送します.効果はboxが1秒以内に縮小し続けることです.これを「補間アニメーション」と言います. 
ここでは、アニメーションオブジェクト(box)、アニメーションプロパティ(width,height)、アニメーション時間(1秒)の3つのものについて説明します.
アニメーションアトリビュートの値を特定するには、ある時点で
 
一般的なアニメーションには4つのタイプがあります.
linear:リニアアニメーション、すなわち均一速度
easeIn:速度が小さいから大きい、すなわちフェードイン
easeOut:速度が大きいから小さい、つまりフェードアウト
easeInOut:開始時に速度が小さいから大きい、終了時に速度が大きいから小さい、すなわちフェードアウト
================================================================
実は緩動といえば、Robert Pennerを言わざるを得ません.彼はN多緩動公式を発明しました.例を挙げます.
/**

 * @param t      

 * @param b    

 * @param c     ,  x     0,    100,     100

 * @param d      

 * @return      

 */

function linear(t, b, c, d){ 

	return c * t / d + b; 

}


説明しましょう.
現在の変化量をXとすると、
t/d=X/cなので、X=c*t/d、X+bで現在の属性値を得ることができます.
もう少し複雑なものを見てみましょう.
var easeInQuad =  function(t, b, c, d){

	return c * ( t /= d ) * t + b;

}


これにはフェードイン効果があります.つまり、アニメーションの開始時に値の変化量が小さいものから大きいものまでです.
両者の唯一の違いはt/dと(t/=d)*tであり、さっきt/dは>=0&&<=1の比であり、暫定的にaと名付けられたが、(t/=d)*tはMathに相当する.pow(a, 2). 
どうして平方ですか.
1.まずa>=Math.pow(a,2)は肯定的
2.関数を呼び出すたびに、t/dという比も均一に大きくなります.例えば、1回目の呼び出しでは0.1(平方0.01)、2回目の呼び出しでは0.2(平方0.04)などです.10回目の呼び出しでは、間違いなく1でしょう.このときc*1+b、アニメーションはこれで終わります
3.第2点は、比が小さいほど値の変化量が小さくなり、比が大きいほど値の変化量が大きくなり、二乗ではなく三次方であれば、淡入効果がより顕著になることを証明している.
 
2つの例を挙げると、現在の属性値=総変化量*増分係数+初期値の法則がいくつか見られ、増分係数はアルゴリズムによって異なります. 
=========================================
増分係数のアルゴリズムは、司徒正美から持ってきて使いましょう.彼はたくさんまとめています.コレクションしなければなりません.
var tween = {

	linear : function(pos) {

		return 1;

	},

	easeInQuad : function(pos) {

		return Math.pow(pos, 2);

	},

	easeOutQuad : function(pos) {

		return -(Math.pow(( pos - 1), 2) - 1);

	},

	easeInOutQuad : function(pos) {

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(pos, 2);

		return -0.5 * ((pos -= 2) * pos - 2);

	},

	easeInCubic : function(pos) {

		return Math.pow(pos, 3);

	},

	easeOutCubic : function(pos) {

		return (Math.pow(( pos - 1), 3) + 1);

	},

	easeInOutCubic : function(pos) {

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(pos, 3);

		return 0.5 * (Math.pow(( pos - 2), 3) + 2);

	},

	easeInQuart : function(pos) {

		return Math.pow(pos, 4);

	},

	easeOutQuart : function(pos) {

		return -(Math.pow(( pos - 1), 4) - 1)

	},

	easeInOutQuart : function(pos) {

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(pos, 4);

		return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);

	},

	easeInQuint : function(pos) {

		return Math.pow(pos, 5);

	},

	easeOutQuint : function(pos) {

		return (Math.pow(( pos - 1), 5) + 1);

	},

	easeInOutQuint : function(pos) {

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(pos, 5);

		return 0.5 * (Math.pow(( pos - 2), 5) + 2);

	},

	easeInSine : function(pos) {

		return -Math.cos(pos * (Math.PI / 2)) + 1;

	},

	easeOutSine : function(pos) {

		return Math.sin(pos * (Math.PI / 2));

	},

	easeInOutSine : function(pos) {

		return (-.5 * (Math.cos(Math.PI * pos) - 1));

	},

	easeInExpo : function(pos) {

		return (pos == 0) ? 0 : Math.pow(2, 10 * ( pos - 1));

	},

	easeOutExpo : function(pos) {

		return (pos == 1) ? 1 : -Math.pow(2, -10 * pos) + 1;

	},

	easeInOutExpo : function(pos) {

		if(pos == 0)

			return 0;

		if(pos == 1)

			return 1;

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(2, 10 * ( pos - 1));

		return 0.5 * (-Math.pow(2, -10 * --pos) + 2);

	},

	easeInCirc : function(pos) {

		return -(Math.sqrt(1 - (pos * pos)) - 1);

	},

	easeOutCirc : function(pos) {

		return Math.sqrt(1 -  Math.pow(( pos - 1), 2))

	},

	easeInOutCirc : function(pos) {

		if((pos /= 0.5) < 1)

			return -0.5 * (Math.sqrt(1 - pos * pos) - 1);

		return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1);

	},

	easeOutBounce : function(pos) {

		if((pos) < (1 / 2.75)) {

			return (7.5625 * pos * pos);

		} else if(pos < (2 / 2.75)) {

			return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

		} else if(pos < (2.5 / 2.75)) {

			return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

		} else {

			return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

		}

	},

	easeInBack : function(pos) {

		var s = 1.70158;

		return (pos) * pos * ((s + 1) * pos - s);

	},

	easeOutBack : function(pos) {

		var s = 1.70158;

		return ( pos = pos - 1) * pos * ((s + 1) * pos + s) + 1;

	},

	easeInOutBack : function(pos) {

		var s = 1.70158;

		if((pos /= 0.5) < 1)

			return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));

		return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);

	},

	elastic : function(pos) {

		return -1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;

	},

	swingFromTo : function(pos) {

		var s = 1.70158;

		return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);

	},

	swingFrom : function(pos) {

		var s = 1.70158;

		return pos * pos * ((s + 1) * pos - s);

	},

	swingTo : function(pos) {

		var s = 1.70158;

		return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;

	},

	bounce : function(pos) {

		if(pos < (1 / 2.75)) {

			return (7.5625 * pos * pos);

		} else if(pos < (2 / 2.75)) {

			return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

		} else if(pos < (2.5 / 2.75)) {

			return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

		} else {

			return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

		}

	},

	bouncePast : function(pos) {

		if(pos < (1 / 2.75)) {

			return (7.5625 * pos * pos);

		} else if(pos < (2 / 2.75)) {

			return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

		} else if(pos < (2.5 / 2.75)) {

			return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

		} else {

			return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

		}

	},

	easeFromTo : function(pos) {

		if((pos /= 0.5) < 1)

			return 0.5 * Math.pow(pos, 4);

		return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);

	},

	easeFrom : function(pos) {

		return Math.pow(pos, 4);

	},

	easeTo : function(pos) {

		return Math.pow(pos, 0.25);

	},

	linear : function(pos) {

		return pos

	},

	sinusoidal : function(pos) {

		return (-Math.cos(pos * Math.PI) / 2) + 0.5;

	},

	reverse : function(pos) {

		return 1 - pos;

	},

	mirror : function(pos, transition) {

		transition = transition || tween.sinusoidal;

		if(pos < 0.5)

			return transition(pos * 2);

		else

			return transition(1 - ( pos - 0.5) * 2);

	},

	flicker : function(pos) {

		var pos = pos + (Math.random() - 0.5) / 5;

		return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);

	},

	wobble : function(pos) {

		return (-Math.cos(pos * Math.PI * (9 * pos)) / 2) + 0.5;

	},

	pulse : function(pos, pulses) {

		return (-Math.cos((pos * ((pulses || 5) - .5) * 2) * Math.PI) / 2) + .5;

	},

	blink : function(pos, blinks) {

		return Math.round(pos * (blinks || 5)) % 2;

	},

	spring : function(pos) {

		return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));

	},

	none : function(pos) {

		return 0;

	}

};


  
Quad、Cubic、Quartといった言葉があることに気づきますが、これらはいったいどういう意味なのでしょうか.ここでFlashのTweener公式ドキュメントを提供します.見てみればわかります(下が空白であれば、バッファに表示されています.こんな良いプレゼンテーションを見るために、辛抱強く待ってください)
上記の知識点から、私のアニメーション関数が出てきました.
/**

 * @param {HTMLElement/Function} obj    :    ;    :     

 * @param {Object} params    :{  :    };    :{startArgs:     [  ], endArgs:     [  ]};

 * @param {Number} duration      ,     

 * @param {String} type     ,   linear,     tween     

 * @param {Function} callback             

 */

var animate = function(obj, params, duration, type, callback){

	window.requestAnimationFrame = (function(){

		return  window.requestAnimationFrame ||

		  window.webkitRequestAnimationFrame ||

		  window.mozRequestAnimationFrame    ||

		  window.oRequestAnimationFrame      ||

		  window.msRequestAnimationFrame     ||

		  function(callback){

			window.setTimeout(callback, 1000 / 60);

          };

      })();



	var tween = {

		linear : function(pos) {

			return 1;

		},

		easeInQuad : function(pos) {

			return Math.pow(pos, 2);

		},

		easeOutQuad : function(pos) {

			return -(Math.pow(( pos - 1), 2) - 1);

		},

		easeInOutQuad : function(pos) {

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(pos, 2);

			return -0.5 * ((pos -= 2) * pos - 2);

		},

		easeInCubic : function(pos) {

			return Math.pow(pos, 3);

		},

		easeOutCubic : function(pos) {

			return (Math.pow(( pos - 1), 3) + 1);

		},

		easeInOutCubic : function(pos) {

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(pos, 3);

			return 0.5 * (Math.pow(( pos - 2), 3) + 2);

		},

		easeInQuart : function(pos) {

			return Math.pow(pos, 4);

		},

		easeOutQuart : function(pos) {

			return -(Math.pow(( pos - 1), 4) - 1)

		},

		easeInOutQuart : function(pos) {

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(pos, 4);

			return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);

		},

		easeInQuint : function(pos) {

			return Math.pow(pos, 5);

		},

		easeOutQuint : function(pos) {

			return (Math.pow(( pos - 1), 5) + 1);

		},

		easeInOutQuint : function(pos) {

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(pos, 5);

			return 0.5 * (Math.pow(( pos - 2), 5) + 2);

		},

		easeInSine : function(pos) {

			return -Math.cos(pos * (Math.PI / 2)) + 1;

		},

		easeOutSine : function(pos) {

			return Math.sin(pos * (Math.PI / 2));

		},

		easeInOutSine : function(pos) {

			return (-.5 * (Math.cos(Math.PI * pos) - 1));

		},

		easeInExpo : function(pos) {

			return (pos == 0) ? 0 : Math.pow(2, 10 * ( pos - 1));

		},

		easeOutExpo : function(pos) {

			return (pos == 1) ? 1 : -Math.pow(2, -10 * pos) + 1;

		},

		easeInOutExpo : function(pos) {

			if(pos == 0)

				return 0;

			if(pos == 1)

				return 1;

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(2, 10 * ( pos - 1));

			return 0.5 * (-Math.pow(2, -10 * --pos) + 2);

		},

		easeInCirc : function(pos) {

			return -(Math.sqrt(1 - (pos * pos)) - 1);

		},

		easeOutCirc : function(pos) {

			return Math.sqrt(1 -  Math.pow(( pos - 1), 2))

		},

		easeInOutCirc : function(pos) {

			if((pos /= 0.5) < 1)

				return -0.5 * (Math.sqrt(1 - pos * pos) - 1);

			return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1);

		},

		easeOutBounce : function(pos) {

			if((pos) < (1 / 2.75)) {

				return (7.5625 * pos * pos);

			} else if(pos < (2 / 2.75)) {

				return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

			} else if(pos < (2.5 / 2.75)) {

				return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

			} else {

				return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

			}

		},

		easeInBack : function(pos) {

			var s = 1.70158;

			return (pos) * pos * ((s + 1) * pos - s);

		},

		easeOutBack : function(pos) {

			var s = 1.70158;

			return ( pos = pos - 1) * pos * ((s + 1) * pos + s) + 1;

		},

		easeInOutBack : function(pos) {

			var s = 1.70158;

			if((pos /= 0.5) < 1)

				return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));

			return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);

		},

		elastic : function(pos) {

			return -1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;

		},

		swingFromTo : function(pos) {

			var s = 1.70158;

			return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);

		},

		swingFrom : function(pos) {

			var s = 1.70158;

			return pos * pos * ((s + 1) * pos - s);

		},

		swingTo : function(pos) {

			var s = 1.70158;

			return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;

		},

		bounce : function(pos) {

			if(pos < (1 / 2.75)) {

				return (7.5625 * pos * pos);

			} else if(pos < (2 / 2.75)) {

				return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

			} else if(pos < (2.5 / 2.75)) {

				return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

			} else {

				return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

			}

		},

		bouncePast : function(pos) {

			if(pos < (1 / 2.75)) {

				return (7.5625 * pos * pos);

			} else if(pos < (2 / 2.75)) {

				return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);

			} else if(pos < (2.5 / 2.75)) {

				return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);

			} else {

				return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);

			}

		},

		easeFromTo : function(pos) {

			if((pos /= 0.5) < 1)

				return 0.5 * Math.pow(pos, 4);

			return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);

		},

		easeFrom : function(pos) {

			return Math.pow(pos, 4);

		},

		easeTo : function(pos) {

			return Math.pow(pos, 0.25);

		},

		linear : function(pos) {

			return pos

		},

		sinusoidal : function(pos) {

			return (-Math.cos(pos * Math.PI) / 2) + 0.5;

		},

		reverse : function(pos) {

			return 1 - pos;

		},

		mirror : function(pos, transition) {

			transition = transition || tween.sinusoidal;

			if(pos < 0.5)

				return transition(pos * 2);

			else

				return transition(1 - ( pos - 0.5) * 2);

		},

		flicker : function(pos) {

			var pos = pos + (Math.random() - 0.5) / 5;

			return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);

		},

		wobble : function(pos) {

			return (-Math.cos(pos * Math.PI * (9 * pos)) / 2) + 0.5;

		},

		pulse : function(pos, pulses) {

			return (-Math.cos((pos * ((pulses || 5) - .5) * 2) * Math.PI) / 2) + .5;

		},

		blink : function(pos, blinks) {

			return Math.round(pos * (blinks || 5)) % 2;

		},

		spring : function(pos) {

			return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));

		},

		none : function(pos) {

			return 0;

		}

	};



	animate = function(obj, params, duration, type, callback){

		var startValue = {},//   

			changeValue = null,//    

			startTime = new Date().getTime(),

			ease = tween[type || 'linear'];

			

		if(typeof obj !== 'function'){

			obj = obj.style;

			for(var name in params){

				startValue[name] = getStyle(obj, name);

			}

			changeValue = {};

			for(name in params){

				changeValue[name] = params[name] - startValue[name];

			}

		}else{

			changeValue = [];

			var startArgs = params.startArgs,

				endArgs = params.endArgs,

				toString = Object.prototype.toString;

			for(var i = 0, len = startArgs.length; i < len; i++){

				changeValue[i] = endArgs[i] - startArgs[i];

			}

		}

		

		var run = function(){

			var timeStamp = new Date().getTime() - startTime,

				factor = ease(timeStamp / duration);//    

			if(!(toString.call(changeValue) === '[object Array]')){

				for(name in params){

					obj[name] = (changeValue[name] * factor + startValue[name]) + 'px';//    , 

				}

			}else{

				var curArgs = [];

				for(i = 0; i < len; i++){

					curArgs[i] = changeValue[i] * factor + startArgs[i];

				}

				obj.apply(null, curArgs);

			}

			if(factor < 1){

				window.requestAnimationFrame(run);	

			}else{

				if(callback)callback();

			}

		};

		window.requestAnimationFrame(run);	

	}

	animate(obj, params, duration, type, callback);

};



var getStyle = function(el, style){

	var value = null;

	if(window.defaultView){

		value = window.getComputedStyle(el, null).getPropertyValue(style);

	}else{

		style = style.replace(/\-(\w)/g, function($0, $1){

			return $1.toUpperCase();

		});

		value = el.currentStyle[style];

		if(value === 'auto'){

			value = '0';

		}

	}

	return parseFloat(value) || 0;

};