source: Dev/branches/rest-dojo-ui/client/dojox/css3/transition.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 8.9 KB
Line 
1define(["dojo/_base/kernel",
2                "dojo/_base/lang",
3                "dojo/_base/declare",
4                "dojo/_base/array",
5                "dojo/_base/Deferred",
6                "dojo/DeferredList",
7                "dojo/on",
8                "dojo/_base/sniff"],
9                function(dojo, lang, declare, array, deferred, deferredList, on, has){
10        //TODO create cross platform animation/transition effects
11        var transitionEndEventName = "transitionend";
12        var transitionPrefix = "t"; //by default use "t" prefix and "ransition" to make word "transition"
13        var translateMethodStart = "translate3d(";//Android 2.x does not support translateX in CSS Transition, we need to use translate3d in webkit browsers
14        var translateMethodEnd = ",0,0)";
15        if(has("webkit")){
16                transitionPrefix = "WebkitT";
17                transitionEndEventName = "webkitTransitionEnd";
18        }else if(has("mozilla")){
19                transitionPrefix = "MozT";
20                translateMethodStart = "translateX(";
21                translateMethodEnd = ")";
22        }
23       
24        //TODO find a way to lock the animation and prevent animation conflict
25        declare("dojox.css3.transition", null, {
26               
27
28                constructor: function(args){
29                        //default config should be in animation object itself instead of its prototype
30                        //otherwise, it might be easy for making mistake of modifying prototype
31                        var defaultConfig = {
32                                startState: {},
33                                endState: {},
34                                node: null,
35                                duration: 250,
36                                "in": true,
37                                direction: 1,
38                                autoClear: true
39                        };
40                       
41                        lang.mixin(this, defaultConfig);
42                        lang.mixin(this, args);
43                       
44                        //create the deferred object which will resolve after the animation is finished.
45                        //We can rely on "onAfterEnd" function to notify the end of a single animation,
46                        //but using a deferred object is easier to wait for multiple animations end.
47                        if(!this.deferred){
48                                this.deferred = new deferred();
49                        }
50                },
51               
52                play: function(){
53                        //play the animation using CSS3 Transition
54                        dojox.css3.transition.groupedPlay([this]);
55                },
56               
57                //method to apply the state of the transition
58                _applyState: function(state){
59                        var style = this.node.style;
60                        for(var property in state){
61                                if(state.hasOwnProperty(property)){
62                                        style[property] = state[property];
63                                }
64                        }
65                },
66               
67                //method to initialize state for transition
68                initState: function(){
69                       
70                        //apply the immediate style change for initial state.
71                        this.node.style[transitionPrefix + "ransitionProperty"] = "none";
72                        this.node.style[transitionPrefix + "ransitionDuration"] = "0ms";
73                        this._applyState(this.startState);
74                       
75                },
76               
77                _beforeStart: function(){
78                        if (this.node.style.display === "none"){
79                                this.node.style.display = "";
80                        }
81                        this.beforeStart();
82                },
83               
84                _beforeClear: function(){
85                        this.node.style[transitionPrefix + "ransitionProperty"] = null;
86                        this.node.style[transitionPrefix + "ransitionDuration"] = null;
87                        if(this["in"] !== true){
88                                this.node.style.display = "none";
89                        }                       
90                        this.beforeClear();
91                },
92               
93                _onAfterEnd: function(){
94                        this.deferred.resolve(this.node);
95                        if(this.node.id && dojox.css3.transition.playing[this.node.id]===this.deferred){
96                                delete dojox.css3.transition.playing[this.node.id];
97                        }
98                        this.onAfterEnd();
99                },
100               
101                beforeStart: function(){
102                       
103                },
104               
105                beforeClear: function(){
106                       
107                },
108               
109                onAfterEnd: function(){
110                       
111                },
112               
113                //method to start the transition
114                start: function(){
115                        this._beforeStart();
116                       
117                        var self = this;
118                        //change the transition duration
119                        self.node.style[transitionPrefix + "ransitionProperty"] = "all";
120                        self.node.style[transitionPrefix + "ransitionDuration"] = self.duration + "ms";
121                       
122                        //connect to clear the transition state after the transition end.
123                        //Since the transition is conducted asynchronously, we need to
124                        //connect to transition end event to clear the state
125                        on.once(self.node, transitionEndEventName, function(){
126                                self.clear();
127                        });
128                       
129                        this._applyState(this.endState);
130                },
131               
132                //method to clear state after transition
133                clear: function(){
134                        this._beforeClear();
135                        this._removeState(this.endState);
136                        console.log(this.node.id + " clear.");
137                        this._onAfterEnd();
138                },
139               
140                //create removeState method
141                _removeState: function(state){
142                        var style = this.node.style;
143                        for(var property in state){
144                                if(state.hasOwnProperty(property)){
145                                        style[property] = null;
146                                }
147                        }
148                }
149               
150        });
151       
152        //TODO add the lock mechanism for all of the transition effects
153        //         consider using only one object for one type of transition.
154        //TODO create the first animation, slide.
155        dojox.css3.transition.slide = function(node, config){
156
157                //TODO create the return and set the startState, endState of the return
158                var ret = new dojox.css3.transition(config);
159                ret.node = node;
160               
161                var startX = "0";
162                var endX = "0";
163               
164                if(ret["in"]){
165                        if(ret.direction === 1){
166                                startX = "100%";
167                        }else{
168                                startX = "-100%";
169                        }
170                }else{
171                        if(ret.direction === 1){
172                                endX = "-100%";
173                        }else{
174                                endX = "100%";
175                        }
176                }
177               
178               
179                ret.startState[transitionPrefix + "ransform"]=translateMethodStart+startX+translateMethodEnd;
180               
181                ret.endState[transitionPrefix + "ransform"]=translateMethodStart+endX+translateMethodEnd;
182               
183                return ret;
184        };
185               
186       
187        //fade in/out animation effects
188        dojox.css3.transition.fade = function(node, config){
189               
190                var ret = new dojox.css3.transition(config);
191                ret.node = node;
192               
193                var startOpacity = "0";
194                var endOpacity = "0";
195               
196                if(ret["in"]){
197                        endOpacity = "1";
198                }else{
199                        startOpacity = "1";
200                }
201               
202                lang.mixin(ret, {
203                        startState:{
204                                "opacity": startOpacity
205                        },
206                        endState:{
207                                "opacity": endOpacity
208                        }
209                });
210               
211                return ret;
212        };
213       
214  //fade in/out animation effects
215        dojox.css3.transition.flip = function(node, config){
216               
217                var ret = new dojox.css3.transition(config);
218                ret.node = node;
219           
220                if(ret["in"]){
221                        //Need to set opacity here because Android 2.2 has bug that
222                        //scale(...) in transform does not persist status
223                        lang.mixin(ret,{
224                                startState:{
225                                        "opacity": "0"
226                                },
227                                endState:{
228                                        "opacity": "1"
229                                }
230                        });
231                        ret.startState[transitionPrefix + "ransform"]="scale(0,0.8) skew(0,-30deg)";
232                        ret.endState[transitionPrefix + "ransform"]="scale(1,1) skew(0,0)";
233                }else{
234                        lang.mixin(ret,{
235                                startState:{
236                                        "opacity": "1"
237                                },
238                                endState:{
239                                        "opacity": "0"
240                                }
241                        });                     
242                        ret.startState[transitionPrefix + "ransform"]="scale(1,1) skew(0,0)";
243                        ret.endState[transitionPrefix + "ransform"]="scale(0,0.8) skew(0,30deg)";
244                }
245               
246                return ret;
247        };
248       
249        var getWaitingList = function(/*Array*/ nodes){
250                var defs = [];
251                array.forEach(nodes, function(node){
252                        //check whether the node is under other animation
253                        if(node.id && dojox.css3.transition.playing[node.id]){
254                                //TODO hook on deferred object in dojox.css3.transition.playing
255                                defs.push(dojox.css3.transition.playing[node.id]);
256                        }
257                       
258                });
259                return new deferredList(defs);
260        };
261       
262        dojox.css3.transition.getWaitingList = getWaitingList;
263       
264        //TODO groupedPlay should ensure the UI update happens when
265        //all animations end.
266        //the group player to start multiple animations together
267        dojox.css3.transition.groupedPlay = function(/*Array*/args){
268                //args should be array of dojox.css3.transition
269               
270                var animNodes = array.filter(args, function(item){
271                        return item.node;
272                });
273               
274                var waitingList = getWaitingList(animNodes);
275
276                //update registry with deferred objects in animations of args.
277                array.forEach(args, function(item){
278                        if(item.node.id){
279                                dojox.css3.transition.playing[item.node.id] = item.deferred;
280                        }
281                });
282               
283                //TODO wait for all deferred object in deferred list to resolve
284                dojo.when(waitingList, function(){
285                        array.forEach(args, function(item){
286                                //set the start state
287                                item.initState();
288                        });
289                       
290                        //Assume the fps of the animation should be higher than 30 fps and
291                        //allow the browser to use one frame's time to redraw so that
292                        //the transition can be started
293                        setTimeout(function(){
294                                array.forEach(args, function(item){
295                                        item.start();
296                                });                       
297                        }, 33);
298                });               
299        };
300       
301        //the chain player to start multiple animations one by one
302        dojox.css3.transition.chainedPlay = function(/*Array*/args){
303                //args should be array of dojox.css3.transition
304               
305                var animNodes = array.filter(args, function(item){
306                        return item.node;
307                });
308               
309                var waitingList = getWaitingList(animNodes);
310
311                //update registry with deferred objects in animations of args.
312                array.forEach(args, function(item){
313                        if(item.node.id){
314                                dojox.css3.transition.playing[item.node.id] = item.deferred;
315                        }
316                });
317               
318                dojo.when(waitingList, function(){
319                        array.forEach(args, function(item){
320                                //set the start state
321                                item.initState();
322                        });
323                       
324                        //chain animations together
325                        for (var i=1, len=args.length; i < len; i++){
326                                args[i-1].deferred.then(lang.hitch(args[i], function(){
327                                        this.start();
328                                }));
329                        }
330                       
331                        //Assume the fps of the animation should be higher than 30 fps and
332                        //allow the browser to use one frame's time to redraw so that
333                        //the transition can be started
334                        setTimeout(function(){
335                                args[0].start();
336                        }, 33);
337                });               
338        };
339       
340        //TODO complete the registry mechanism for animation handling and prevent animation conflicts
341        dojox.css3.transition.playing = {};
342       
343        return dojox.css3.transition;
344});
Note: See TracBrowser for help on using the repository browser.