/** * @author zjj */ $.Effect = function () { var effects = [], queues = {}; var interval = null; /* 间隔处理 */ function loopHandler () { var timePos = +new Date; for (var i = 0; i < effects.length; i ++) { var ef = effects[i]; if(timePos >= ef.finishOn) { ef.status = 'finish'; remove(ef, true); return; } if (ef.status == 'idle') { ef.onStart && ef.onStart(); ef.status = 'running'; } var pos = (timePos - ef.startOn) / (ef.finishOn - ef.startOn); var frame = Math.round(pos * ef.totalFrames); if(frame > ef.currentFrame) { pos = ef.transition(pos); pos = ef.from + ((ef.to - ef.from) * pos); ef.render(pos * ef.factor,ef.action); ef.currentFrame = frame; } } } /* 删除效果 */ function remove (effect, toEnd) { var ret = 0, length = effects.length, item; while (length--) { item = effects[length]; if (item == effect || item.guid == effect) { if (toEnd) { item.render( (item.from + ((item.to - item.from) * item.transition(1))) * item.factor ); item.onFinish && item.onFinish(); item.status = 'finish'; } item.onRemove && item.onRemove(); ret ++; effects.splice(length, 1); } } if (effects.length == 0) { clearInterval(interval); interval = false; } return ret; } /* 添加动画 */ function add (effect) { if (effect.onAdd) { effect.onAdd(); delete effect.onAdd; } var timestamp = +new Date; effect = $.extend({ transition: $.Effect.Transitions.linear, duration: 1.0, // 秒 fps: 25.0, // 25fps由Effect.Queue执行 from: 0.0, to: 1.0, delay: 0.0, factor: 1, action: 'linear' }, effect); effect.action = effect.style.action || effect.action; effect.startOn = effect.delay * 1000 + timestamp; effect.finishOn = effect.startOn + effect.duration * 1000; effect.currentFrame = 0; effect.totalFrames = effect.fps * effect.duration; if ($.isString(effect.transition)) effect.transition = $.Effect.Transitions[effect.transition]; effect.status = 'idle'; effects.push(effect); if(!interval) interval = window.setInterval(loopHandler, 40); return effect; } function addToQueue (effect) { var queueId = effect.queue, originOnRemove = effect.onRemove, queue = queues[queueId]; effect.onRemove = function () { if (queues[queueId] && queues[queueId].data.length) { var effect = queues[queueId].data.shift(); queues[queueId].current = effect; add (effect); } else { delete queues[queueId]; } originOnRemove && originOnRemove(); }; if (queue) { queue.data.push(effect); } else { queue = queues[queueId] = {}; queue.data = []; queue.current = effect; add(effect); } } function removeQueue (queueId) { var queue = queues[queueId]; if (queue) { var current = queue.current; delete queues[queueId]; //remove(current, toEnd); } } function status () { $.log('effects:' + effects.length); $.log('queues:' + $.keys(queues).length); } return { add: add, addToQueue: addToQueue, removeQueue: removeQueue, remove: remove, status: status } }(); $.Effect.extend = function (effects) { var toExtend = {}; $.each(effects, function (_sets, name) { if (!_sets.style) _sets = { style : _sets }; toExtend[name] = function (elem) { var sets = $.extend({}, _sets), args = $.toArray(arguments); args.shift(); //elem if (args[0] && typeof args[0] == 'number') { sets.duration = args.shift(); args.shift(); } var onFinish = args.shift(), customSets = args.shift(); if (onFinish) { var originOnFinish = sets.onFinish; sets.onFinish = function () { onFinish.call(elem); originOnFinish && originOnFinish(); }; } if (customSets) $.extend(sets, customSets); return $.elements.effect.call(this, elem, sets); }; }); $.elements.extend(toExtend); }; $.Effect.Transitions = { linear: function (pos) { return pos; } }; function extendElementEffect(sets) { var elem = this, $elem = $(elem); if (!sets.style) return; var styles = sets.style, names = []; if (styles.START) { var originOnStart = sets.onStart; sets.onStart = function () { typeof styles.START == 'function' ? styles.START.call(elem) : $elem.css(styles.START); originOnStart && originOnStart.call(elem); }; } else sets.onStart && (sets.onStart = sets.onStart.bind(elem)); if (styles.END) { var originOnFinish = sets.onFinish; sets.onFinish = function () { typeof styles.END == 'function' ? styles.END.call(elem) : $elem.css(styles.END); originOnFinish && originOnFinish.call(elem); }; } else sets.onFinish && (sets.onFinish = sets.onFinish.bind(elem)); styles.INIT && $elem.css(styles.INIT); $.each(styles, function (val, name) { if (' INIT START END '.indexOf(' ' + name + ' ') >= 0) return; var from = parseFloat($.css(elem, name, true)) || 0, to, takens = val.toString().match(/^([-+]=)?([\d+-.]+)(.*)$/); if (takens) { to = parseFloat(takens[2]), unit = takens[3] || 'px'; if (unit != 'px') { $.css(elem, name, to + unit); from = (to / parseFloat($.css(elem, name, true))) * from; $.css(elem, name, from + unit); } if (takens[1]) to = (takens[1] == '-=' ? -1 : 1) * to + from; names.push({ name : name, color : styles.color , from : from, to : to, unit : takens[3] || '' }); } }); var handle = sets.handle; sets.render = function (pos,effects) { for (var i = 0, n = names.length; i < n; i ++) { style = names[i]; var fn = $effects[effects] == undefined ? $effects['linear'] : $effects[effects]; if (style.unit) pos += style.unit; //$.output('set {0} : {1}; from : {2}, to : {3}'.format(names[i], value, style.from, style.to)); $.css(elem, style.name, fn(pos, style.from, (style.to - style.from) ,1)); } handle && handle.call(elem, pos); }; } $.elements.extend({ effect: function (elem,sets) { if (!sets.style) sets = { style : sets }; if (sets.queue !== false) sets.queue = $.data(elem); sets.guid = $.data(elem); sets.onAdd = extendElementEffect.bind(elem, sets); $.Effect[sets.queue ? 'addToQueue' : 'add'](sets); return this; }, stop: function (elem, clearQueue, toEnd) { var guid = $.data(elem); clearQueue && $.Effect.removeQueue(guid); $.Effect.remove(guid, toEnd); return this; } }); var $effects = { linear: function (t, b, c, d) { return c*t/d + b; }, 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;}, easeBoth: function (t, b, c, d) { if ((t/=d/2) < 1) { return c/2*t*t + b; } return -c/2 * ((--t)*(t-2) - 1) + b; }, easeInStrong: function (t, b, c, d) { return c*(t/=d)*t*t*t + b; }, easeOutStrong: function (t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b; }, easeBothStrong: 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; }, elasticIn: 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; }, elasticOut: 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; }, elasticBoth: function (t, b, c, d, a, p) { if (t === 0) { return b; } if ( (t /= d/2) == 2 ) { return b+c; } if (!p) { p = d*(0.3*1.5); } if ( !a || a < Math.abs(c) ) { 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; }, backIn: function (t, b, c, d, s) { if (typeof s == 'undefined') { s = 1.70158; } return c*(t/=d)*t*((s+1)*t - s) + b;}, backOut: function (t, b, c, d, s) { if (typeof s == 'undefined') { s = 1.70158; } return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, backBoth: function (t, b, c, d, s) { if (typeof s == 'undefined') { 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; }, bounceIn: function (t, b, c, d) { return c - $effects['bounceOut'](d-t, 0, c, d) + b; }, bounceOut: 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; } return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b; }, bounceBoth: function (t, b, c, d) { if (t < d/2) { return $effects['bounceIn'](t*2, 0, c, d) * 0.5 + b; } return $effects['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b; } ///* // easeInQuad: function (t, b, c, d) { return c*(t/=d)*t + b; }, // easeOutQuad: function ( t, b, c, d) { return -c *(t/=d)*(t-2) + b; }, // easeInOutQuad: function ( t, b, c, d) { if ((t/=d/2) < 1){return c/2*t*t + b;} return -c/2 * ((--t)*(t-2) - 1) + b; }, // easeInCubic: function ( t, b, c, d) { return c*(t/=d)*t*t + b; }, // easeOutCubic: function ( t, b, c, d) { return c*((t=t/d-1)*t*t + 1) + b; }, // easeInOutCubic: 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; }, // easeInQuart: function ( t, b, c, d) { return c*(t/=d)*t*t*t + b; }, // easeOutQuart: function ( t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b; }, // easeInOutQuart: 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; }, // easeInQuint: function ( t, b, c, d) { return c*(t/=d)*t*t*t*t + b; }, // easeOutQuint: function ( t, b, c, d) { return c*((t=t/d-1)*t*t*t*t + 1) + b;}, // easeInOutQuint: 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; }, // easeInSine: function ( t, b, c, d) { return -c * Math.cos(t/d * (Math.PI/2)) + c + b; }, // easeOutSine: function ( t, b, c, d) { return c * Math.sin(t/d * (Math.PI/2)) + b; }, // easeInOutSine: function ( t, b, c, d) { return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; }, // easeInExpo: function ( t, b, c, d) { return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; }, // easeOutExpo: function ( t, b, c, d) { return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; }, // easeInOutExpo: 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; // }, // easeInCirc: function ( t, b, c, d) { return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;}, // easeOutCirc: function ( t, b, c, d) { return c * Math.sqrt(1 - (t=t/d-1)*t) + b; }, // easeInOutCirc: 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; // }, // easeInElastic: function ( t, b, c, d) { // var s=1.70158;var p=0;var a=c; // if (t===0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*0.3; // if (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; // }, // easeOutElastic: function ( t, b, c, d) { // var s=1.70158;var p=0;var a=c; // if (t===0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*0.3; // if (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; // }, // easeInOutElastic: function ( t, b, c, d) { // var s=1.70158;var p=0;var a=c; // if (t===0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(0.3*1.5); // if (a < Math.abs(c)) { 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; // }, // easeInBack: function ( t, b, c, d, s) { if (s == undefined){ s = 1.70158;} return c*(t/=d)*t*((s+1)*t - s) + b; }, // easeOutBack: function ( t, b, c, d, s) { if (s == undefined){ s = 1.70158;} return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, // easeInOutBack: function ( t, b, c, d, s) { if (s == undefined) {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; }, // easeInBounce: function ( t, b, c, d) { return c - $effects['easeOutBounce']( d-t, 0, c, d) + b; }, // easeOutBounce: 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; } }, // easeInOutBounce: function ( t, b, c, d) { if (t < d / 2) { return $effects['easeInBounce']( t*2, 0, c, d) * 0.5 + b; } return $effects['easeOutBounce']( t*2-d, 0, c, d) * 0.5 + c*0.5 + b;} };