javascript动画实现

html代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>动画组件</title>
    <script type="text/javascript" src="FX.js"></script>
    <style type="text/css">
        #motion{
            background:#ccc;
            width:500px;
            height:500px;
            position:relative;
            overflow:hidden;
            float:left;
        }
        #motion #ball{
            width:40px;
            height:40px;
            background:red;
            position:absolute;
            *font-size:0px;
        }
        #motion #flag{
            background:yellow;
            width:4px;
            height:4px;
            position:absolute;
            *font-size:0px;
        }
        #status{
            float:left;
            margin:0px 10px;
        }
        #status .item{
            margin:1em 0px;
        }
        #chart{
            *zoom:1;
            margin:0px 20px 10px 0px;;
        }
        #chart{
            position:relative;
            width:250px;
            height:250px;
            background:#eaeaea;
        }
        #chart div{
            width:4px;
            height:4px;
            cursor:pointer;
            background:green;
            position:absolute;
            *font-size:0px;
        }
        #chart:selected{
            background:red;
        }
    </style>
</head>
<body>
<div id="container">
    <div id="motion"></div>
    <div id="status">
        <div class="item"> 时长(毫秒): <select id="duration">
            <option value="100">100</option>
            <option value="200">200</option>
            <option value="300" selected="selected">300</option>
            <option value="500">500</option>
            <option value="800">800</option>
            <option value="1000">1000</option>
            <option value="1200">1200</option>
            <option value="1500">1500</option>
            <option value="1800">1800</option>
            <option value="2000">2000</option>
        </select></div>
        <div class="item"> FPS: <select id="fps">
            <option value="5">5</option>
            <option value="10">10</option>
            <option value="20">20</option>
            <option value="24" selected="selected">24</option>
            <option value="35">35</option>
            <option value="50">50</option>
            <option value="80">80</option>
        </select></div>
        <div class="item"> 动画类型: <select id="type">
            <option value="simple">simple</option>
            <option value="regularEaseIn">regularEaseIn</option>
            <option value="regularEaseOut">regularEaseOut</option>
            <option value="regularEaseInOut">regularEaseInOut</option>
            <option value="backEaseIn">backEaseIn</option>
            <option value="backEaseOut">backEaseOut</option>
            <option value="backEaseInOut">backEaseInOut</option>
            <option value="bounceEaseOut">bounceEaseOut</option>
            <option value="bounceEaseIn">bounceEaseIn</option>
            <option value="bounceEaseInOut">bounceEaseInOut</option>
            <option value="strongEaseIn">strongEaseIn</option>
            <option value="strongEaseOut">strongEaseOut</option>
            <option value="strongEaseInOut">strongEaseInOut</option>
            <option value="elasticEaseIn">elasticEaseIn</option>
            <option value="elasticEaseOut">elasticEaseOut</option>
            <option value="elasticEaseInOut">elasticEaseInOut</option>
        </select></div>
        <div class="item">
            <div>运动轨迹:</div>
            <div id="chart"></div>
        </div>
        <div class="item">
            <div id="result"></div>
        </div>
    </div>
</div>
<script type="text/javascript">
    var motionContainer = document.getElementById('motion');
    var ball = document.createElement('div');
    var flag = document.createElement('div');
    var chart = document.getElementById('chart');
    var type = document.getElementById('type');
    var duration = document.getElementById('duration');
    var fps = document.getElementById('fps');
    var result = document.getElementById('result');

    type.options.length = 0;
    /*
     * QQ邮箱使用的为Cubic + easeOut/easeIn 200ms(展开收起文件夹)
     * Sine + easeOut/easeIn 300ms 弹出框 from:-30 to 0
     * fast:200ms slow:600ms
     */
    for (var i in Fx.transitions) {
        if (Fx.transitions.hasOwnProperty(i)) {
            var opt = document.createElement("option");
            opt.value = i;
            opt.innerHTML = i;
            type.appendChild(opt);
        }
    }

    function setPosition(el, position) {
        el.style.left = position[0] + 'px';
        el.style.top = position[1] + 'px';
    }
    ;

    ball.id = "ball";
    flag.id = "flag";
    motionContainer.appendChild(ball);
    motionContainer.appendChild(flag);

    var fx = null;

    motionContainer.onclick = function (ev) {
        ev = ev || window.event;

        if (fx) {
            fx.pause();
        }
        var position = {
            'left': {from: parseInt(ball.style.left) || 0, to: ev.clientX || ev.pageX},
            'top': {from: parseInt(ball.style.top) || 0, to: ev.clientY || ev.pageY}
        };
        chart.innerHTML = '';

        setPosition(flag, [position.left.to, position.top.to]);

        // 动画逻辑
        var d = duration.options[duration.selectedIndex || 0].value / 1000;
        var t = type.options[type.selectedIndex || 0].value;

        fx = new Fx(ball, position, d, t);
        //设置帧频
        fx.setFrequency(fps.options[fps.selectedIndex || 0].value);

        fx.onMotionStart = function () {
            var res = [
                '动画类型:' + this._animateType,
                '帧率为::' + this._freq,
                '指定运行:' + this._duration + '秒'
            ];
            result.innerHTML = res.join('<br />');

            Chart.apply(this);
        }

        fx.onMotionStop = function () {

        }

        fx.onMotionChange = function (time) {
            var dot = document.createElement('div');
            var x = position.left, y = position.top;
            var move = {x: this._ease(x.from, x.to, time), y: this._ease(y.from, y.to, time)};
            var dotx = move.x / motionContainer.clientWidth * chart.clientWidth;
            var doty = move.y / motionContainer.clientHeight * chart.clientHeight;
            setPosition(dot, [dotx, doty]);
            chart.appendChild(dot);
        }

        fx.start();
    }

    function Chart() {
        var iChart = 550;

        var a = [];
        for (var i = 0; i < iChart; i++) {
            a.push('<div style="background-color:#f60;font-size:0;width:3px;height:3px;position:absolute;left:' + (i - 1) + 'px;top:' + (Math.ceil(this._func(i, 200, -200, iChart))) + 'px;"><\/div>');
        }
        document.getElementById("idChart").innerHTML = a.join("");
    }
</script>
<div id="idChart"
     style="border:1px solid #000;height:200px; width:550px; margin-top:20px; position:relative; clear:both; margin-top:10px;"></div>
</body>
</html>


FX.js代码:


/**
 * @author ZhangYi
 */

/**
 *
 * @param {HTMLElement|String} el HTMLElement|DOM对象
 * @param {Object|null} attributes 执行动画时需要更新的属性值
 * @param {Number} duration	动画执行时间
 * @param {String|Null} transition 动画算子函数
 */
function Fx(el, attributes, duration, func) {
    this._obj = Fx.DOM.get(el);
    this._attributes = attributes || {};
    this._duration = duration || 10;

    if(!!func && typeof(Fx.transitions[func]) === "function") {
        this._animateType = func;
    } else {
        this._animateType = "simple";
    }

    this._func = Fx.transitions[this._animateType];

    this.isPlayed = false;
    this.isLoop = false;

    this._intervalTimer = null;
    this._startTime = 0;
    this._moveTime = 0;

    //动画执行频率
    this._freq = 24;

    this.units = {};
    this.frame = {};
    this.endAttr = {};
    this.startAttr = {};

    //开始执行动画
    this.onMotionStart = function() {};

    //动画正在执行
    this.onMotionChange = function() {};

    //动画执行结束
    this.onMotionStop = function() {};

    return this;
}

Fx.prototype = {
    //启动定时器执行动画
    _runTime : function() {
        clearInterval(this._intervalTimer);

        if (this.isPlayed) {
            this._moveTime = new Date().getTime() - this._startTime;

            this._playTime( (this._moveTime) / 1000 );

            var $pointer = this;
            var delay = Math.floor(1000 / this._freq);

            this._intervalTimer = setInterval(function() {$pointer._runTime.apply($pointer);}, delay);
        }
    },
    /**
     * 定时器启动时执行的动画
     * @param {Number} time
     */
    _playTime : function(time) {
        var _isEnd = false;
        if (time > this._duration) {
            time = this._duration;
            _isEnd = true;
            this.frame = Fx.objectClone(this.endAttr);
        } else {
            for(attr in this.startAttr){
                if( '[object Array]' === Object.prototype.toString.apply(this.startAttr[attr]) ){
                    this.frame[attr] = [];
                    for(var i=0; i < this.startAttr[attr].length; i++){
                        this.frame[attr][i] = this._ease(this.startAttr[attr][i], this.endAttr[attr][i], time);
                    }
                } else {
                    this.frame[attr] = this._ease(this.startAttr[attr], this.endAttr[attr], time);
                }
            }
        }

        this.setAttributes();
        this.onMotionChange.apply(this, arguments);

        // 判断是否播放结束
        if (_isEnd) {
            this.isPlayed = false;

            this.onMotionStop.apply(this);

            // 循环播放
            if (this.isLoop) {
                this.isPlayed = true;
                this.frame = Fx.objectClone(this.startAttr);
                this._reloadTimer();
            }

            if (window.CollectGarbage) {
                CollectGarbage();
            }
        }
    },
    //重新计算动画开始时间
    _reloadTimer : function() {
        this._startTime = +new Date();
    },
    /**
     * 调用动画算子函数,返回执行结果
     *
     * @param {Number} start
     * @param {Number} end
     * @param {Number} time
     */
    _ease : function(start, end, time) {
        return this._func(time, start, end - start, this._duration);
    },
    /**
     * 设置动画执行的频率 1秒执行多少次
     */
    setFrequency : function(freq) {
        this._freq = freq;
    },
    /**
     * 开始播放动画
     * @param {Boolean} loop
     */
    start : function(loop) {
        this.getAttributes();
        this._reloadTimer();

        this._start.apply(this, arguments);
    },
    /**
     * 共用的开始执行动画函数
     * @param {Boolean} loop
     */
    _start : function(loop) {
        this.isPlayed = true;
        this.isLoop = loop ? true : false;
        this._runTime();
        this.onMotionStart.apply(this);
    },
    /**
     * 继续播放
     * @param {Boolean} loop
     */
    play : function(loop) {
        this._startTime = +new Date() - this._moveTime;

        this._start.apply(this, arguments);
    },
    /**
     * 重新播放
     * @param {Boolean} loop 是否循环播放动画
     */
    rePlay : function(loop) {
        this._reloadTimer();

        this._start.apply(this, arguments);
    },
    /**
     * 暂停播放动画
     */
    pause : function() {
        this.isPlayed = false;
        this.isLoop = false;
    },
    /**
     * 停止播放动画
     */
    stop : function() {
        this.pause();

        this._playTime(this._duration + 0.1);
    },
    getAttributes : function() {
        for(var attr in this._attributes) {

            if(!this._attributes.hasOwnProperty(attr)) {
                continue;
            }

            switch(attr){
                case 'color':
                case 'borderColor':
                case 'border-color':
                case 'backgroundColor':
                case 'background-color':
                    this.startAttr[attr] = Fx.parseColor(this._attributes[attr].from || Fx.DOM.getStyle(this._obj, attr));
                    this.endAttr[attr] = Fx.parseColor(this._attributes[attr].to);
                    break;
                case 'scrollTop':
                case 'scrollLeft':
                    var el = (this._obj === document.body) ? (/AppleWebKit/i.test(navigator.userAgent) ? document.body : document.documentElement) : this._obj;

                    var start = this._attributes[attr].from || el[attr];
                    var end = this._attributes[attr].to;
                    if(end && /^([+-])(\d+)$/.test(this._attributes[attr].to)) {
                        if("+" === RegExp['$1']) {
                            end = start + RegExp['$2']*1;
                        } else {
                            end = start - RegExp['$2']*1;
                        }
                    }

                    this.startAttr[attr] = start;
                    this.endAttr[attr] = end;

                    break;
                default:
                    var start = parseFloat(this._attributes[attr].from);
                    var end = parseFloat(this._attributes[attr].to);
                    var units = this._attributes[attr].units || "";

                    if(attr !== "opacity" && !units) {
                        units = "px";
                    }

                    if(!start) {
                        start = parseFloat(Fx.DOM.getStyle(this._obj, attr)) || 0;//会转换成px

                        if(units != "px" && document.defaultView){
                            Fx.DOM.setStyle(this._obj, attr, start + units);
                        }
                    }

                    if(end && /^([+-])(\d+)$/.test(this._attributes[attr].to)) {
                        if("+" === RegExp['$1']) {
                            end = start + RegExp['$2']*1;
                        } else {
                            end = start - RegExp['$2']*1;
                        }
                    }

                    this.units[attr] = units;
                    this.endAttr[attr] = end;
                    this.startAttr[attr] = start;

                    break;
            }
        }
    },
    setAttributes : function() {
        for(var attr in this.frame){
            switch(attr) {
                case 'opacity':
                    Fx.DOM.setStyle(this._obj, attr, this.frame[attr]);
                    break;
                case 'scrollLeft':
                case 'scrollTop':
                    var el = (this._obj === document.body) ? (/AppleWebKit/i.test(navigator.userAgent) ? document.body : document.documentElement) : this._obj;
                    el[attr] = this.frame[attr];
                    break;
                case 'color':
                case 'borderColor':
                case 'border-color':
                case 'backgroundColor':
                case 'background-color':
                    var rgb = 'rgb('+Math.floor(this.frame[attr][0])+','+Math.floor(this.frame[attr][1])+','+Math.floor(this.frame[attr][2])+')';
                    Fx.DOM.setStyle(this._obj, attr, rgb);
                    break;
                default:
                    Fx.DOM.setStyle(this._obj, attr, this.frame[attr] + this.units[attr]);
                    break;
            }
        }
    },
    //获取当前动画已经执行的百分比
    getPercent : function() {
        var percent = this._moveTime/(this._duration*1000);
        percent = Math.min(percent, 1);

        return Math.floor(percent*100) + "%";
    }
}

Fx.DOM = {
    /**
     * 获取DOM节点
     * @param {String} 需要查找的元素的ID
     * @return {Element} 返回DOM对象
     */
    get: function(id){
        return (typeof id === "string") ? document.getElementById(id) : id;
    },
    /**
     * 获取元素的指定样式的属性
     * @param {Element} el 目标元素
     * @param {String} prop 属性名
     * @return {Number} 该元素的指定属性的属性值
     */
    getStyle: function(el, prop){
        prop = this.toCamelCase(prop);
        var view = document.defaultView;
        if(view && view.getComputedStyle){
            return view.getComputedStyle(el, "")[prop] || null;
        }else{
            if(prop == 'opacity'){
                var opacity = el.filters['alpha'] ? el.filters['alpha']['opacity'] : NaN;
                return isNaN(opacity) ? 1 : (opacity ? opacity / 100 : 0);
            }
            return el.currentStyle[prop] || null;
        }
    },
    /**
     * 设置元素的样式属性
     * @param {Element} el 目标元素
     * @param {String} prop  属性名
     * @param {String} value 属性值
     */
    setStyle: function(el, prop, value){
        if(prop == 'opacity'){
            el.style.filter = "alpha(opacity=" + value * 100 + ")";
            el.style.opacity = value;
        } else {
            prop = this.toCamelCase(prop);
            if(prop === "height" || prop === "width") {//避免出现负值
                value = Math.max(0, parseInt(value, 10));
            }
            el.style[prop] = value;
        }
    },
    /**
     * 将一个CSS属性转换为驼峰形式,例如(font-size --> fontSize)
     * @param {String} 需要转换的CSS属性
     * @return {String} 转换为驼峰式后的字符串
     */
    toCamelCase : (function(){
        var cache = {};

        return function(str){
            if(!cache[str]){
                var parts = str.split('-'), camel = parts[0];
                if(parts.length > 1){
                    for(var i=1, len=parts.length; i < len; i++){
                        camel += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
                    }
                }
                return cache[str] = camel;
            } else {
                return cache[str];
            }
        }
    })()
}
/**
 * 解析颜色值, 支持16进制与RGB颜色值(#FFFFFF, #FFF, rgb(255, 0, 0))
 * @param {String} 颜色值字符串
 * @return {Array} RGB的颜色数组,默认返白色
 */
Fx.parseColor = (function(){
    var hex6 = (/^#?(\w{2})(\w{2})(\w{2})$/);
    var hex3 = (/^#?(\w{1})(\w{1})(\w{1})$/);
    var rgb = (/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/);

    return function(str){
        var color = str.match(hex6);
        if(color && color.length == 4){
            return [parseInt(color[1], 16), parseInt(color[2], 16), parseInt(color[3], 16)];
        }

        color = str.match(rgb);
        if(color && color.length == 4){
            return [parseInt(color[1], 10), parseInt(color[2], 10), parseInt(color[3], 10)];
        }

        color = str.match(hex3);
        if(color && color.length == 4){
            return [parseInt(color[1] + color[1], 16), parseInt(color[2] + color[2], 16), parseInt(color[3] + color[3], 16)];
        }

        return [255, 255, 255];
    }
})();

/**
 * 动画的算子函数
 */
Fx.transitions = {
    //linear
    linearEase : function(t, b, c, d) {
        return c*t/d + b;
    },
    simple : function(time, startValue, changeValue, duration) {
        return changeValue * time / duration + startValue;
    },
    //circ
    circEaseIn : function(t, b, c, d) {
        return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
    },
    circEaseOut : function(t, b, c, d) {
        return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
    },
    circEaseInOut : function(t, b, c, d) {
        if ((t/=d/2) < 1) {
            return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
        }

        return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
    },
    //cubic
    cubicEaseIn : function(t, b, c, d) {
        return c*(t/=d)*t*t + b;
    },
    cubicEaseOut : function(t, b, c, d) {
        return c*((t=t/d-1)*t*t + 1) + b;
    },
    cubicEaseInOut : function(t, b, c, d) {
        if ((t/=d/2) < 1) {
            return c/2*t*t*t + b;
        }
        return c/2*((t-=2)*t*t + 2) + b;
    },
    //expo
    expoEaseIn : function(t, b, c, d) {
        return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
    },
    expoEaseOut : function(t, b, c, d) {
        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
    },
    expoEaseInOut : function(t, b, c, d) {
        if (t==0) return b;
        if (t==d) return b+c;
        if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
        return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
    },
    //quad
    quadEaseIn : function(t, b, c, d) {
        return c*(t/=d)*t + b;
    },
    quadEaseOut : function(t, b, c, d) {
        return -c *(t/=d)*(t-2) + b;
    },
    quadEaseInOut : function(t, b, c, d) {
        if ((t/=d/2) < 1) return c/2*t*t + b;
        return -c/2 * ((--t)*(t-2) - 1) + b;
    },
    //quart
    quartEaseIn : function(t, b, c, d) {
        return c*(t/=d)*t*t*t + b;
    },
    quartEaseOut : function(t, b, c, d) {
        return -c * ((t=t/d-1)*t*t*t - 1) + b;
    },
    quartEaseInOut : function(t, b, c, d) {
        if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
        return -c/2 * ((t-=2)*t*t*t - 2) + b;
    },
    //quint
    quintEaseIn : function(t, b, c, d) {
        return c*(t/=d)*t*t*t*t + b;
    },
    quintEaseOut : function(t, b, c, d) {
        return c*((t=t/d-1)*t*t*t*t + 1) + b;
    },
    quintEaseInOut : function(t, b, c, d) {
        if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
        return c/2*((t-=2)*t*t*t*t + 2) + b;
    },
    //sine
    sineEaseIn : function(t, b, c, d) {
        return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
    },
    sineEaseOut : function(t, b, c, d) {
        return c * Math.sin(t/d * (Math.PI/2)) + b;
    },
    sineEaseInOut : function(t, b, c, d) {
        return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
    },
    //regular
    regularEaseIn : function(t, b, c, d) {
        return c * (t /= d) * t + b;
    },
    regularEaseOut : function(t, b, c, d) {
        return -c * (t /= d) * (t - 2) + b;
    },
    regularEaseInOut : function(t, b, c, d) {
        if ((t /= d / 2) < 1) {
            return c / 2 * t * t + b;
        }
        return -c / 2 * ((--t) * (t - 2) - 1) + b;
    },
    //back
    backEaseIn : function(t, b, c, d) {
        var s = 1.70158;
        return c * (t /= d) * t * ((s + 1) * t - s) + b;
    },

    backEaseOut : function(t, b, c, d, a, p) {
        var s = 1.70158;
        return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
    },

    backEaseInOut : function(t, b, c, d, a, p) {
        var s = 1.70158;
        if ((t /= d / 2) < 1) {
            return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
        }
        return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
    },
    //bounce
    bounceEaseOut : function(t, b, c, d) {
        if ((t /= d) < (1 / 2.75)) {
            return c * (7.5625 * t * t) + b;
        } else if (t < (2 / 2.75)) {
            return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
        } else if (t < (2.5 / 2.75)) {
            return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
        } else {
            return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
        }
    },

    bounceEaseIn : function(t, b, c, d) {
        return c - Fx.transitions.bounceEaseOut(d - t, 0, c, d) + b;
    },

    bounceEaseInOut : function(t, b, c, d) {
        if (t < d / 2) {
            return Fx.transitions.bounceEaseIn(t * 2, 0, c, d) * 0.5 + b;
        } else
            return Fx.transitions.bounceEaseOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
    },
    //strong
    strongEaseIn : function(t, b, c, d) {
        return c * (t /= d) * t * t * t * t + b;
    },

    strongEaseOut : function(t, b, c, d) {
        return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
    },
    strongEaseInOut : function(t, b, c, d) {
        if ((t /= d / 2) < 1) {
            return c / 2 * t * t * t * t * t + b;
        }
        return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
    },
    //elastic
    elasticEaseIn : function(t, b, c, d, a, p) {
        if (t == 0)
            return b;
        if ((t /= d) == 1)
            return b + c;
        if (!p)
            p = d * 0.3;
        if (!a || a < Math.abs(c)) {
            a = c;
            var s = p / 4;
        } else {
            var s = p / (2 * Math.PI) * Math.asin(c / a);
        }
        return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
    },
    elasticEaseOut : function(t, b, c, d, a, p) {
        if (t == 0)
            return b;
        if ((t /= d) == 1)
            return b + c;
        if (!p)
            p = d * 0.3;
        if (!a || a < Math.abs(c)) {
            a = c;
            var s = p / 4;
        } else {
            var s = p / (2 * Math.PI) * Math.asin(c / a);
        }
        return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
    },
    elasticEaseInOut : function(t, b, c, d, a, p) {
        if (t == 0) {
            return b;
        }

        if ((t /= d / 2) == 2) {
            return b + c;
        }

        if (!p) {
            var p = d * (0.3 * 1.5);
        }

        if (!a || a < Math.abs(c)) {
            var a = c;
            var s = p / 4;
        } else {
            var s = p / (2 * Math.PI) * Math.asin(c / a);
        }
        if (t < 1) {
            return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
        }
        return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
    }
}
/**
 * 深度复制对象
 *
 * @param {Object} obj	复制对象
 * @param {Property} preventName 不需要进行复制的对象属性
 */
Fx.objectClone = function(obj, preventName) {
    if ((typeof obj) == 'object') {
        var res = '[object Array]' === Object.prototype.toString.apply(obj) ? [] : {};
        for (var i in obj) {
            if (i != preventName) res[i] = arguments.callee(obj[i], preventName);
        }
        return res;
    } else if ((typeof obj) == 'function') {
        return (new obj()).constructor;
    }
    return obj;
}

记录动画进度html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>动画测试</title>
    <script type="text/javascript" src="FX.js"></script>
    <style type="text/css">
        button {margin-left:20px;}
    </style>
</head>
<body>

<button οnclick="clearTimer();animate()">开建执行动画</button>
<button οnclick="clearTimer(); fx.pause();" disabled=true>暂停</button>
<button οnclick="clearTimer(); fx.play()" disabled=true>继续播放</button>
<button οnclick="clearTimer(); fx.rePlay();" disabled=true>重新播放</button>

<div style="margin-top:10px;">当前动画的执行的百分比:<span id="animatePercent"></span></div>

<div id="bar" style="width:10em; height:30%; position:absolute; border:1px solid red; margin-top:50px; left:50px;"></div>
<div style="height:2800px;"></div>
<script type="text/javascript">
    function rand(min,max){
        return Math.round(min+(Math.random()*(max-min)));
    }

    var easing = ['simple', 'regularEaseIn', 'regularEaseOut', 'regularEaseInOut', 'backEaseIn', 'backEaseOut', 'backEaseInOut',
        'bounceEaseOut', 'bounceEaseIn', 'bounceEaseInOut', 'strongEaseIn', 'strongEaseOut', 'strongEaseInOut',
        'elasticEaseIn', 'elasticEaseOut', 'elasticEaseInOut'
    ];

    var fx = null;

    function addEvent(el, fn, handler) {
        if(el.attachEvent) {
            el.attachEvent("on" + fn, handler);
        } else {
            el.addEventListener(fn, handler, false);
        }
    }

    if (/firefox/i.test(navigator.userAgent)) {
        document.addEventListener('DOMMouseScroll', wheel, false);
    } else {
        document.onmousewheel = wheel;
    }

    function wheel(ev) {
        return ;
        ev = ev || window.event;

        var delta = 0;

        if(ev.wheelDelta) {//非FF
            delta = ev.wheelDelta;// /120;
        } else if(ev.detail) {//FF
            delta = ev.detail;  // /3;
        }

        if(ev.preventDefault) {
            ev.preventDefault();
        } else {
            ev.returnValue = false;
        }

        var val = ev.wheelDelta || ev.detail;

        if(fx) {
            fx.stop();
        }

        fx = new Fx("abcdefg", {
            'scrollTop' : {to:val>0?"-" + val : "+" + Math.abs(val)}
        }, .3, "easeInOut");

        setTimeout(function() {
            fx.start(true);
        }, 0)

        alert(ev.wheelDelta + "\n" + ev.detail);
        if(delta) {
            if(delta < 0) {
                document.title = "向下滚动的";
            } else {
                document.title = "向上滚动的";
            }
        }
    }

    function animate() {
        if(fx) {
            fx.pause();
        } else {
            var btns = document.getElementsByTagName("button");
            for(var i=1, len=btns.length; i<len; i++) {
                btns[i].disabled = false;
            }
        }

        fx = new Fx('bar', {
            top: {to: rand(10, 30)},
            left: {to: rand(20, 40), units: 'ex'},
            width: {to: rand(10, 40), units: 'em'},
            height: {to: rand(10, 260), units: '%'},
            opacity : {from:rand(0, 1), to:(Math.min(rand(0, 1))+0.1, 1)},
            backgroundColor: {to: "rgb("+rand(0, 255)+", "+rand(0, 255)+", "+rand(0, 255)+")"}
        }, 1, easing[rand(0, easing.length - 1)]);

        fx.onMotionChange = function() {
            document.getElementById('animatePercent').innerHTML = this.getPercent();
        }

        fx.start();

        fx.onMotionStop = function() {
            animateTimer = setTimeout(function() {
                animate();
            }, 500);
        }
    }

    var animateTimer = null;

    function clearTimer() {
        if(animateTimer) {
            clearTimeout(animateTimer);
        }
    }
</script>

</body>
</html>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值