| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- define(function(require, exports, module) {
- "use strict";
- var Util = require('./util');
- var Timer = require('./timer');
- var Easing = require('./easing');
- var Base = require('./base');
- //transform
- var vendorTransform = Util.prefixStyle("transform");
- //transition webkitTransition MozTransition OTransition msTtransition
- var vendorTransition = Util.prefixStyle("transition");
- var vendorTransitionDuration = Util.prefixStyle("transitionDuration");
- var vendorTransformOrigin = Util.prefixStyle("transformOrigin");
- var vendorTransitionEnd = Util.vendor ? Util.prefixStyle("transitionEnd") : "transitionend";
- var vendorTransformStr = Util.vendor ? ["-", Util.vendor, "-transform"].join("") : "transform";
- var translateTpl = 'translateX({translateX}px) translateY({translateY}px) translateZ(0)';
- //limit attrs
- var animAttrs = {
- 'transform': true,
- 'opacity': true,
- 'scrollTop': true,
- 'scrollLeft': true
- };
- function myParse(v) {
- return Math.round(parseFloat(v) * 1e5) / 1e5;
- }
- function defaultDecompose() {
- return {
- translateX: 0,
- translateY: 0,
- rotate: 0,
- skewX: 0,
- skewY: 0,
- scaleX: 1,
- scaleY: 1
- };
- }
- function toMatrixArray(matrix) {
- matrix = matrix.split(/,/);
- matrix = Array.prototype.map.call(matrix, function(v) {
- return myParse(v);
- });
- return matrix;
- }
- function decomposeMatrix(matrix) {
- matrix = toMatrixArray(matrix);
- var scaleX, scaleY, skew,
- A = matrix[0],
- B = matrix[1],
- C = matrix[2],
- D = matrix[3];
- // Make sure matrix is not singular
- if (A * D - B * C) {
- scaleX = Math.sqrt(A * A + B * B);
- skew = (A * C + B * D) / (A * D - C * B);
- scaleY = (A * D - B * C) / scaleX;
- // step (6)
- if (A * D < B * C) {
- skew = -skew;
- scaleX = -scaleX;
- }
- // matrix is singular and cannot be interpolated
- } else {
- // In this case the elem shouldn't be rendered, hence scale == 0
- scaleX = scaleY = skew = 0;
- }
- // The recomposition order is very important
- // see http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp#l971
- return {
- translateX: myParse(matrix[4]),
- translateY: myParse(matrix[5]),
- rotate: myParse(Math.atan2(B, A) * 180 / Math.PI),
- skewX: myParse(Math.atan(skew) * 180 / Math.PI),
- skewY: 0,
- scaleX: myParse(scaleX),
- scaleY: myParse(scaleY)
- };
- }
- function getTransformInfo(transform) {
- transform = transform.split(')');
- var trim = Util.trim,
- i = -1,
- l = transform.length - 1,
- split, prop, val,
- ret = defaultDecompose();
- // Loop through the transform properties, parse and multiply them
- while (++i < l) {
- split = transform[i].split('(');
- prop = trim(split[0]);
- val = split[1];
- switch (prop) {
- case 'translateX':
- case 'translateY':
- case 'scaleX':
- case 'scaleY':
- ret[prop] = myParse(val);
- break;
- case 'translate':
- case 'translate3d':
- val = val.split(',');
- ret.translateX = myParse(val[0]);
- ret.translateY = myParse(val[1] || 0);
- break;
- case 'scale':
- val = val.split(',');
- ret.scaleX = myParse(val[0]);
- ret.scaleY = myParse(val[1] || val[0]);
- break;
- case 'matrix':
- return decomposeMatrix(val);
- }
- }
- return ret;
- }
- /**
- * animate function
- * @constructor
- * @param {HTMLElement} el element to animate
- * @param {Object} config config for animate
- * @param {Object} config.css
- * @param {Number} config.duration
- * @param {String} config.easing
- * @extends {Base}
- */
- function Animate(el, cfg) {
- if (!el || !cfg || !cfg.css) return;
- var self = this;
- self.cfg = cfg;
- self.el = el;
- var duration = cfg.duration || 0,
- easing = cfg.easing || "ease",
- delay = cfg.delay || 0;
- //trigger run
- if (cfg.run) {
- //frame animate
- self.timer = self.timer || new Timer({
- duration: Math.round(duration),
- easing: easing,
- });
- self.timer.on("run", cfg.run);
- }
- self._bindEvt();
- return self;
- }
- function computeTransform(prevTransform, destTransform) {
- var transform = getTransformInfo(prevTransform);
- var dest = getTransformInfo(destTransform);
- var trans = {};
- for (var i in dest) {
- trans[i] = {
- prevVal: transform[i],
- newVal: dest[i]
- }
- }
- return trans;
- }
- //for scroll only
- function setStyle(el, styleName, prevVal, newVal, percent) {
- prevVal = isNaN(Number(prevVal)) ? 0 : Number(prevVal);
- var curVal = ((newVal - prevVal) * percent + prevVal);
- css(el, styleName, curVal);
- }
- function css(el, styleName, val) {
- switch (styleName) {
- case "scrollTop":
- case "scrollLeft":
- el[styleName] = val;
- break;
- case "transform":
- el.style[vendorTransform] = val;
- case "opacity":
- el.style[styleName] = val;
- break;
- }
- }
- Util.extend(Animate, Base, {
- /**
- * to start the animation
- * @memberof Animate
- * @return {Animate}
- */
- run: function() {
- var self = this;
- var cfg = self.cfg,
- el = self.el,
- duration = cfg.duration || 0,
- easing = cfg.easing || "ease",
- delay = cfg.delay || 0;
- self.__isTransitionEnd = false;
- clearTimeout(self.__itv)
- self.timer && self.timer.run();
- if (duration <= Timer.MIN_DURATION) {
- for (var i in cfg.css) {
- css(el, i, cfg.css[i]);
- }
- self.stop()
- self.__handlers.stop.call(self);
- return;
- }
- if(Util.isBadAndroid()){
- //use frame animate on bad android device
- cfg.useTransition = false;
- }
- if (cfg.useTransition) {
- //transition
- el.style[vendorTransition] = Util.substitute('all {duration}ms {easing} {delay}ms', {
- duration: Math.round(duration),
- easing: Easing.format(easing),
- delay: delay
- });
- for (var i in cfg.css) {
- //set css
- css(el, i, cfg.css[i]);
- }
- self.__itv = setTimeout(function() {
- if (!self.__isTransitionEnd) {
- self.__isTransitionEnd = true;
- self.trigger("transitionend");
- }
- }, Number(duration) + 60);
- } else {
- self.computeStyle = self.computeStyle || window.getComputedStyle(el);
- //transform
- if (cfg.css.transform && self.timer) {
- var transmap = self.transmap = computeTransform(self.computeStyle[vendorTransform], cfg.css.transform);
- self.timer.off("run", self.__handlers.transRun);
- self.timer.on("run", self.__handlers.transRun, self);
- self.timer.off("end",self.__handlers.transRun);
- self.timer.on("end", self.__handlers.transRun, self);
- }
- }
- return self;
- },
- _transitionEndHandler: function(e) {
- var self = this;
- self.stop();
- self.__handlers.stop.call(self);
- },
- __handlers: {
- transRun: function(e) {
- var self = this;
- var transmap = self.transmap;
- var el = self.el;
- var newTrans = {};
- for (var i in transmap) {
- newTrans[i] = (transmap[i].newVal - transmap[i].prevVal) * e.percent + transmap[i].prevVal
- }
- var ret = Util.substitute(translateTpl + ' ' +
- 'scale({scaleX},{scaleY})', newTrans);
- el.style[vendorTransform] = ret;
- },
- stop: function(e) {
- var self = this;
- var cfg = self.cfg;
- cfg.end && cfg.end({
- percent: 1
- });
- }
- },
- _bindEvt: function() {
- var self = this;
- var cfg = self.cfg;
- var el = self.el;
- self.el.addEventListener(vendorTransitionEnd, function(e) {
- self.__isTransitionEnd = true;
- if (e.target !== e.currentTarget) return;
- self.trigger("transitionend", e);
- })
- self.on("transitionend", self._transitionEndHandler, self);
- var cssRun = function(e) {
- self.computeStyle = self.computeStyle || window.getComputedStyle(el);
- for (var i in cfg.css) {
- if (!/transform/.test(i)) {
- setStyle(self.el, i, self.computeStyle[i], cfg.css[i], e.percent);
- }
- }
- };
- self.timer && self.timer.on("run", cssRun);
- self.timer && self.timer.on("stop", self.__handlers.stop, self);
- },
- /**
- * to stop the animation
- * @memberof Animate
- * @return {Animate}
- */
- stop: function() {
- var self = this;
- if (self.cfg.useTransition && self.cfg.duration > Timer.MIN_DURATION) {
- var computeStyle = window.getComputedStyle(this.el);
- for (var i in self.cfg.css) {
- if (animAttrs[i]) {
- var value = /transform/.test(i) ? computeStyle[vendorTransform] : computeStyle[i];
- css(self.el, i, Util.substitute(translateTpl + ' ' + 'scale({scaleX},{scaleY})', getTransformInfo(value)));
- }
- }
- self.el.style[vendorTransition] = "none";
- }
- self.timer && self.timer.stop() && self.timer.reset();
- self.computeStyle = null;
- return self;
- },
- /**
- * to reset the animation to a new state
- * @memberof Animate
- * @param {object} cfg cfg for new animation
- * @return {Animate}
- */
- reset: function(cfg) {
- var self = this;
- self.computeStyle = null;
- Util.mix(self.cfg, cfg);
- this.timer && self.timer.reset({
- duration: Math.round(self.cfg.duration),
- easing: self.cfg.easing
- });
- return self;
- }
- });
- if (typeof module == 'object' && module.exports) {
- module.exports = Animate;
- }
- /** ignored by jsdoc **/
- else {
- return Animate;
- }
- });
|