[转帖]Mootools源码分析-28 -- Fx
原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-405254
原作者:我佛山人
/*
Fx是Effect的简写,顾名思义,是用于产生效果的基类
事实上,Fx的名气更多是在作为Prototype效果插件时被称作Moo.fx的轻量级实现
其实就是用最少的代码,做最好的事
*/
var Fx = new Class({
//链式执行,事件和可选参数的接口实现
Implements: [Chain, Events, Options],
options: {
/*
onStart: $empty, //特效开始时的事件
onCancel: $empty, //特效取消时的事件
onComplete: $empty, //特效完成时的事件
*/
fps: 50, //frame per second,每秒的帧数,用于计时器的时间间隔换算
unit: false, //单位,派生类使用
duration: 500,
//周期,特效完成所花的时间
link: 'ignore', //当新旧两次特效转换冲突时的处理
//转换,其实就是目标数值的变化速度函数,可以根据曲线看出速度的变化规律
transition: function(p) {
return -(Math.cos(Math.PI * p) - 1) / 2;
}
},
//构造函数
initialize: function(options) {
this.subject = this.subject || this;
this.setOptions(options);
//先判断是否使用易记的命名周期,否则再取整
this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
//同下兼容的写法,旧版本使用的是wait参数
var wait = this.options.wait;
//使用绝对等于,避免不传wait参数时的意外
if (wait === false) this.options.link = 'cancel';
},
//每一步执行的操作
step: function() {
//取当前时间
var time = $time();
//如果没到结束时间
if (time < this.time + this.options.duration) {
//计算出转换效果中的变量值
var delta = this.options.transition((time - this.time) / this.options.duration);
//根据变量设置目标值
this.set(this.compute(this.from, this.to, delta));
//执行结束
} else {
//此时变量值为定值1
this.set(this.compute(this.from, this.to, 1));
this.complete();
}
},
//设置目标值,留作派生类实现
set: function(now) {
return now;
},
//根据初始值,结束值和变量求目标值
compute: function(from, to, delta) {
//使用因为有很多效果使用相同的算法,所以使用静态方法
return Fx.compute(from, to, delta);
},
//检查当前特效运行状态
check: function() {
//如果特效没有运行
if (!this.timer) return true;
switch (this.options.link) {
//如果wait为false或link为cancel,不等待正在运行的特效,直接取消并重新开始
case 'cancel': this.cancel(); return true;
//如果link为cancel,等待当前特效运行结束后再继续运行新特效
case 'chain': this.chain(this.start.bind(this, arguments)); return false;
//其它取值是等同于ignore,直接忽略新特效,继续完成当前特效
}
return false;
},
//特效开始,从from变换到to
start: function(from, to) {
//检查当前特效运行状态,决定是否运行新特效
if (!this.check(from, to)) return this;
//因为在其它地方多次用到,所以需要转为属性
this.from = from;
this.to = to;
this.time = 0;
//开始计时
this.startTimer();
//发送onStart事件通知
this.onStart();
return this;
},
//完成特效
complete: function() {
//停止计时器,并触发onComplete事件
if (this.stopTimer()) this.onComplete();
return this;
},
//取消正在执行的特效
cancel: function() {
//停止计时器,并触发onCancel事件
if (this.stopTimer()) this.onCancel();
return this;
},
//发送onStart事件通知
onStart: function() {
//注意传给事件监听的参数为this.subject
this.fireEvent('onStart', this.subject);
},
//发送onComplete事件通知
onComplete: function() {
//注意传给事件监听的参数为this.subject
this.fireEvent('onComplete', this.subject);
//链式执行
if (!this.callChain()) this.fireEvent('onChainComplete', this.subject);
},
//发送onCancel事件通知
onCancel: function() {
//触发onCancel事件并取消链式执行,注意传给事件监听的参数为this.subject
this.fireEvent('onCancel', this.subject).clearChain();
},
//暂停特效
pause: function() {
//只需要停止计时器
this.stopTimer();
return this;
},
//特效暂停后的恢复
resume: function() {
//重新开始时间,因为this.time已经有进度记录,所以可以直接开始计时就能恢复到暂停前状态
this.startTimer();
return this;
},
//停止计时器
stopTimer: function() {
//如果没有运行或已停止,忽略
if (!this.timer) return false;
//更新this.time,以用于resume的特效恢复
this.time = $time() - this.time;
//停止计时器
this.timer = $clear(this.timer);
return true;
},
//开始计时
startTimer: function() {
//如果已开始计时,忽略
if (this.timer) return false;
//时间差
this.time = $time() - this.time;
//开始计时器,注意要将fps换算,计算出每次执行的时间间隔
this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
return true;
}
});
//目标值的计算算法,不同的算法实现不同的转换效果
Fx.compute = function(from, to, delta) {
return (to - from) * delta + from;
};
//周期的几个命名点
Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
Fx是Effect的简写,顾名思义,是用于产生效果的基类
事实上,Fx的名气更多是在作为Prototype效果插件时被称作Moo.fx的轻量级实现
其实就是用最少的代码,做最好的事
*/
var Fx = new Class({
//链式执行,事件和可选参数的接口实现
Implements: [Chain, Events, Options],
options: {
/*
onStart: $empty, //特效开始时的事件
onCancel: $empty, //特效取消时的事件
onComplete: $empty, //特效完成时的事件
*/
fps: 50, //frame per second,每秒的帧数,用于计时器的时间间隔换算
unit: false, //单位,派生类使用
duration: 500,
//周期,特效完成所花的时间
link: 'ignore', //当新旧两次特效转换冲突时的处理
//转换,其实就是目标数值的变化速度函数,可以根据曲线看出速度的变化规律
transition: function(p) {
return -(Math.cos(Math.PI * p) - 1) / 2;
}
},
//构造函数
initialize: function(options) {
this.subject = this.subject || this;
this.setOptions(options);
//先判断是否使用易记的命名周期,否则再取整
this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
//同下兼容的写法,旧版本使用的是wait参数
var wait = this.options.wait;
//使用绝对等于,避免不传wait参数时的意外
if (wait === false) this.options.link = 'cancel';
},
//每一步执行的操作
step: function() {
//取当前时间
var time = $time();
//如果没到结束时间
if (time < this.time + this.options.duration) {
//计算出转换效果中的变量值
var delta = this.options.transition((time - this.time) / this.options.duration);
//根据变量设置目标值
this.set(this.compute(this.from, this.to, delta));
//执行结束
} else {
//此时变量值为定值1
this.set(this.compute(this.from, this.to, 1));
this.complete();
}
},
//设置目标值,留作派生类实现
set: function(now) {
return now;
},
//根据初始值,结束值和变量求目标值
compute: function(from, to, delta) {
//使用因为有很多效果使用相同的算法,所以使用静态方法
return Fx.compute(from, to, delta);
},
//检查当前特效运行状态
check: function() {
//如果特效没有运行
if (!this.timer) return true;
switch (this.options.link) {
//如果wait为false或link为cancel,不等待正在运行的特效,直接取消并重新开始
case 'cancel': this.cancel(); return true;
//如果link为cancel,等待当前特效运行结束后再继续运行新特效
case 'chain': this.chain(this.start.bind(this, arguments)); return false;
//其它取值是等同于ignore,直接忽略新特效,继续完成当前特效
}
return false;
},
//特效开始,从from变换到to
start: function(from, to) {
//检查当前特效运行状态,决定是否运行新特效
if (!this.check(from, to)) return this;
//因为在其它地方多次用到,所以需要转为属性
this.from = from;
this.to = to;
this.time = 0;
//开始计时
this.startTimer();
//发送onStart事件通知
this.onStart();
return this;
},
//完成特效
complete: function() {
//停止计时器,并触发onComplete事件
if (this.stopTimer()) this.onComplete();
return this;
},
//取消正在执行的特效
cancel: function() {
//停止计时器,并触发onCancel事件
if (this.stopTimer()) this.onCancel();
return this;
},
//发送onStart事件通知
onStart: function() {
//注意传给事件监听的参数为this.subject
this.fireEvent('onStart', this.subject);
},
//发送onComplete事件通知
onComplete: function() {
//注意传给事件监听的参数为this.subject
this.fireEvent('onComplete', this.subject);
//链式执行
if (!this.callChain()) this.fireEvent('onChainComplete', this.subject);
},
//发送onCancel事件通知
onCancel: function() {
//触发onCancel事件并取消链式执行,注意传给事件监听的参数为this.subject
this.fireEvent('onCancel', this.subject).clearChain();
},
//暂停特效
pause: function() {
//只需要停止计时器
this.stopTimer();
return this;
},
//特效暂停后的恢复
resume: function() {
//重新开始时间,因为this.time已经有进度记录,所以可以直接开始计时就能恢复到暂停前状态
this.startTimer();
return this;
},
//停止计时器
stopTimer: function() {
//如果没有运行或已停止,忽略
if (!this.timer) return false;
//更新this.time,以用于resume的特效恢复
this.time = $time() - this.time;
//停止计时器
this.timer = $clear(this.timer);
return true;
},
//开始计时
startTimer: function() {
//如果已开始计时,忽略
if (this.timer) return false;
//时间差
this.time = $time() - this.time;
//开始计时器,注意要将fps换算,计算出每次执行的时间间隔
this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
return true;
}
});
//目标值的计算算法,不同的算法实现不同的转换效果
Fx.compute = function(from, to, delta) {
return (to - from) * delta + from;
};
//周期的几个命名点
Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};