2

js动画框架设计

 2 years ago
source link: http://hcy2367.github.io/2015/01/08/js-anim.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Section One

游戏动画,Flash动画里一个比较重要的概念是帧频,即每秒播放多少帧动画,一般动画是30帧/秒,单位为fps(frames per second)。

对于匀速运动来说:如果一个动画的持续时间duration为500ms,帧频frequence为30fps,则总帧数frames为(500/1000)*30 = 15,即该动画过程有15个“画面”,每走一帧,都计算出一个画面:画面当前位置 = 开始位置 + (当前帧/总帧数)(结束位置-开始位置),如果当前帧是最后一帧,则动画结束。其中setTimeout或setInterval每隔(500/15)ms时间段调用一次函数,即计算一个画面。

来看下线性运动Linear缓动算法函数,t表示当前帧,b表示开始位置,c表示发生偏移的距离值,即当前位置-开始位置,d表示总帧数,符合上面的推理解释,对于其他的算法函数,道理其实都是一样,只不过在运动过程中的曲线不同,有些呈现抛物线,有些呈现线性指数,对于数学感兴趣的可以研究下这些算法函数,我也是略知皮毛:

Linear: function (t, b, c, d) {
	return c * t / d + b;
}

清楚了以上问题后,对于js的动画框架设计,就迎刃而解了,废话不多说,来个 demo 先。

Section Two

代码总体结构,具体说明看注释,需注意的问题:1)在私有作用域里定义的变量,要在外部能访问到,需挂在window全局对象下,如window.Anim = Anim;2)动画元素需要设置定位position属性;3)传入的外边距参数需要驼峰式命名,并且当同时设置targetPos(元素目标位置)和外边距时,外边距的值会覆盖targetPos的值,如marginLeft的值会覆盖targetPos.left的值,因为外边距实现动画的原理也是利用元素的left、top值:

(function(window) {
	/*
	 * 工具对象
	 * 包含基本的dom操作,event操作
	 */
	var util = {};
	util.dom = {
		// 获取元素计算样式
		getPropValue: function(element, propName) {
		},
		// 设置透明度
		setOpacity: function(obj, num) {
			document.all ? obj.filters.alpha.opacity = num : obj.style.opacity = num / 100;
	    }
	    // ......
	};
	util.event = {
		// 获取事件对象
		getEvent: function(event) {
		},
		// 获取事件源目标
		getTarget: function(event) {
		},
		// 注册事件
		addEvent: function(element, event, handler) {
		},
		// 删除事件
		removeEvent: function(element, event, handler) {
		},
		// 阻止默认行为
		preventDefault: function(event) {
		},
		// 阻止事件冒泡
		stopPropagation: function(event) {
		}
		// ......
	};

	/*
	* 动画缓动函数
	*/
	var Tween = {
	    Linear: function (t, b, c, d) { return c * t / d + b; },
	    Quad: {
	        easeIn: function (t, b, c, d) {
	            return c * (t /= d) * t + b;
	        },
	        easeOut: function (t, b, c, d) {
	            return -c * (t /= d) * (t - 2) + b;
	        },
	        easeInOut: function (t, b, c, d) {
	            if ((t /= d / 2) < 1) return c / 2 * t * t + b;
	            return -c / 2 * ((--t) * (t - 2) - 1) + b;
	        }
	    },
	    // ...
	};

	/*
	 * 核心动画
	 * @elem 要执行动画的元素
	 * @options left、top、opacity、width、height、border、marginLeft、marginRight、marginTop、marginBottom
	 */
	function Anim(elem, options) {
		this.elem = elem;
		this.options = options;
		// 默认样式属性
		this.defaults = {
		};
	}
	Anim.prototype = {
		constructor: Anim,
		// 初始化动画
		init: function() {
			this.isStart = false;
			this.isStop = false;
			this.isComplete = false;
			this.isBack = false;
			this.start();
		},
		// 初始化数据
		before: function() {
		},
		// 开始动画
		start: function() {
		},
		// 动画过程
		run: function() {
			this.before();
			// 动画参数匹配
			this.match();
			// 原路返回
			if (this.isBack) {
				// ...
			}
			if (this.isStart) {
				this.onStart.call(this.elem);
				// 计算动画
				this.count();
			}
		},
		// 匹配动画的参数
		match: function() {
		},
		// 计算动画
		count: function() {
		},
		// 原路返回
		back: function() {
		},
		// 停止动画
		stop: function() {
		},
		// 重置元素
		reset: function() {
		}
	};

	// 全局使用
	if (!window.util) {
		window.util = util;
	}
	if (!window.Anim) {
		window.Anim = Anim;
	}
	if (!window.Tween) {
		window.Tween = Tween;
	}

})(window);

使用非常简单,初始化参数对象,然后调用构造函数Anim即可:

// 动画参数设置
var options = {
	duration: 2000, // 动画持续时间
	frequence: 30, // 帧频
	tweenFunc: Tween.Linear, // 动画缓动函数
	targetPos: {left: 400, top: 300}, // 元素目标位置
	opacity: 40, // 透明度(可选)
	width: 80, // 宽度(可选)
	height: 80, // 高度(可选)
	// marginTop: 100, // 上边距(可选)
	border: '2px solid red', // 边框(可选)
	// 动画开始callback(可选)
	onStart: function() {
		// this指向当前动画元素
	},
	// 动画停止callback(可选)
	onStop: function() {
		// this指向当前动画元素
	},
	// 动画完成callback(可选)
	onComplete: function() {
		// this指向当前动画元素
	}
};
var anim = new Anim(animElem, options);

最后附上 源代码 以及easing算法函数的 demo

认真对待每一个人,每一件事,会有意想不到的收获!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK