[转帖]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};

 

posted @ 2009-11-24 16:15  webgis松鼠  阅读(177)  评论(0编辑  收藏  举报