/**
* animation using js timer
* @author yiminghe@gmail.com
* @ignore
*/
KISSY.add('anim/timer', function (S, Dom, AnimBase, Easing, AM, Fx, SHORT_HANDS) {
var camelCase = Dom._camelCase,
NUMBER_REG = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i;
function Anim() {
var self = this,
to;
Anim.superclass.constructor.apply(self, arguments);
// camel case uniformity
S.each(to = self.to, function (v, prop) {
var camelProp = camelCase(prop);
if (prop != camelProp) {
to[camelProp] = to[prop];
delete to[prop];
}
});
}
S.extend(Anim, AnimBase, {
prepareFx: function () {
var self = this,
node = self.node,
_propsData = self._propsData;
S.each(_propsData, function (_propData) {
// ms
_propData.duration *= 1000;
_propData.delay *= 1000;
if (typeof _propData.easing == 'string') {
_propData.easing = Easing.toFn(_propData.easing);
}
});
// 扩展分属性
S.each(SHORT_HANDS, function (shortHands, p) {
var origin,
_propData = _propsData[p],
val;
if (_propData) {
val = _propData.value;
origin = {};
S.each(shortHands, function (sh) {
// 得到原始分属性之前值
origin[sh] = Dom.css(node, sh);
});
Dom.css(node, p, val);
S.each(origin, function (val, sh) {
// 如果分属性没有显式设置过,得到期待的分属性最后值
if (!(sh in _propsData)) {
_propsData[sh] = S.merge(_propData, {
value: Dom.css(node, sh)
});
}
// 还原
Dom.css(node, sh, val);
});
// 删除复合属性
delete _propsData[p];
}
});
var prop,
_propData,
val,
to,
from,
propCfg,
fx,
isCustomFx = 0,
unit,
parts;
if (S.isPlainObject(node)) {
isCustomFx = 1;
}
// 取得单位,并对单个属性构建 Fx 对象
for (prop in _propsData) {
_propData = _propsData[prop];
val = _propData.value;
propCfg = {
isCustomFx: isCustomFx,
prop: prop,
anim: self,
propData: _propData
};
fx = Fx.getFx(propCfg);
to = val;
from = fx.cur();
val += '';
unit = '';
parts = val.match(NUMBER_REG);
if (parts) {
to = parseFloat(parts[2]);
unit = parts[3];
// 有单位但单位不是 px
if (unit && unit !== 'px' && from) {
var tmpCur = 0,
to2 = to;
do {
++to2;
Dom.css(node, prop, to2 + unit);
// in case tmpCur==0
tmpCur = fx.cur();
} while (tmpCur == 0);
from = (to2 / tmpCur) * from;
Dom.css(node, prop, from + unit);
}
// 相对
if (parts[1]) {
to = ( (parts[ 1 ] === '-=' ? -1 : 1) * to ) + from;
}
}
propCfg.from = from;
propCfg.to = to;
propCfg.unit = unit;
fx.load(propCfg);
_propData.fx = fx;
}
},
// frame of animation
frame: function () {
var self = this,
prop,
end = 1,
fx,
_propData,
_propsData = self._propsData;
for (prop in _propsData) {
_propData = _propsData[prop];
fx = _propData.fx;
fx.frame();
// in case call stop in frame
if (self.isRejected() || self.isResolved()) {
return;
}
end &= fx.pos == 1;
}
var currentTime = S.now(),
duration = self.config.duration * 1000,
remaining = Math.max(0,
self.startTime + duration - currentTime),
temp = remaining / duration || 0,
percent = 1 - temp;
self.defer.notify([self, percent, remaining]);
if (end) {
// complete 事件只在动画到达最后一帧时才触发
self['stop'](end);
}
},
doStop: function (finish) {
var self = this,
prop,
fx,
_propData,
_propsData = self._propsData;
AM.stop(self);
if (finish) {
for (prop in _propsData) {
_propData = _propsData[prop];
fx = _propData.fx;
// fadeIn() -> call stop
if (fx) {
fx.frame(1);
}
}
}
},
doStart: function () {
AM.start(this);
}
});
Anim.Easing = Easing;
Anim.Fx = Fx;
return Anim;
}, {
requires: [
'dom', './base',
'./timer/easing', './timer/manager',
'./timer/fx', './timer/short-hand'
, './timer/color' , './timer/transform'
]
});
/*
2013-09
- support custom anim object
2013-01 yiminghe@gmail.com
- 分属性细粒度控制 {'width':{value:,easing:,fx: }}
- 重构,merge css3 transition and js animation
2011-11 yiminghe@gmail.com
- 重构,抛弃 emile,优化性能,只对需要的属性进行动画
- 添加 stop/stopQueue/isRunning,支持队列管理
2011-04 yiminghe@gmail.com
- 借鉴 yui3 ,中央定时器,否则 ie6 内存泄露?
- 支持配置 scrollTop/scrollLeft
- 效率需要提升,当使用 nativeSupport 时仍做了过多动作
- opera nativeSupport 存在 bug ,浏览器自身 bug ?
- 实现 jQuery Effects 的 queue / specialEasing / += / 等特性
NOTES:
- 与 emile 相比,增加了 borderStyle, 使得 border: 5px solid #ccc 能从无到有,正确显示
- api 借鉴了 YUI, jQuery 以及 http://www.w3.org/TR/css3-transitions/
- 代码实现了借鉴了 Emile.js: http://github.com/madrobby/emile *
*/