source: Dev/branches/rest-dojo-ui/client/dojox/fx/Timeline.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: 6.1 KB
Line 
1define(["dojo/_base/lang","dojo/fx/easing","dojo/_base/fx","dojo/dom","./_base","dojo/_base/connect",
2                "dojo/_base/html", "dojo/_base/array","dojo/_base/Color"],
3 function(lang, easingUtil, baseFx, dom, dojoxFx, connectUtil, htmlUtil, arrayUtil, Color){
4
5dojoxFx.animateTimeline = function(/* Object */options, /* DomNode|String */node){
6        // options: Object
7        //              The paramters passed to the timeline animation. Includes:
8        //                      keys: Array
9        //                              An array of objects, with style properties and values.
10        //                      duration:
11        //                              Duration of the animation in milliseconds.
12        //                              Defaults to 1000.
13        // node: DomNode
14        //              The DomNode or id to be animated.
15        //
16        // summary:
17        //              An add-on to dojo.fx that provides the ability to create
18        //              a complex property animation based on an array of "keyframes".
19        // description:
20        //              The Timeline is a replacement for the default dojo._Line.
21        //              Instead of _Line.getValue returning a float between 0-1,
22        //              _Timeline.getValue returns an object with all properties and
23        //              their current values.
24        //              A property does not have to appear in every keyframe.
25        //              As in the example below, "height" is transitioned from the first
26        //              keyframe to the third. "width" is transitioned from the first
27        //              to the second to the third.
28        //              Each keyframe can accept the following custom properties:
29        //      step: String
30        //              The start, finish or percentage that this keyframe represents.
31        //              Allowed parameters are:
32        //                      0%-100%
33        //                      from (same as 0%, used to conform with the Webkit animation spec)
34        //                      to (same as 100%, used to conform with the Webkit animation spec)
35        //      ease: String
36        //              The string name of a dojo.fx.easing ease. Defaults to "linear". Use
37        //              the suffix name of the ease, like: "quadIn", not: "dojo.fx.quadIn".
38        //
39        // example:
40        //              |       var keys = [
41        //              |       {
42        //              |               step:"0px",
43        //              |               ease:"quadInOut",
44        //              |               width:"50px",
45        //              |               height:"50px",
46        //              |       },{
47        //              |               step:"25%",
48        //              |               width:"190px"
49        //              |       },{
50        //              |               step:"100%",
51        //              |               width:"10px",
52        //              |               height:"200px",
53        //              |       }
54        //              |       ];
55        //              |       ani = dojox.fx.animateTimeline({keys:keys, duration:2000}, "myDiv").play();
56        //
57        var _curve = new Timeline(options.keys);
58        var ani = baseFx.animateProperty({
59                node:dom.byId(node || options.node),
60                duration:options.duration || 1000,
61                properties:_curve._properties,
62                // don't change! This easing is for the timeline,
63                // not individual properties
64                easing:easingUtil.linear,
65                onAnimate: function(v){
66                        //console.log("   ani:", v);
67                }
68        });
69        connectUtil.connect(ani, "onEnd", function(node){
70                // Setting the final style. Hiccups in the browser
71                // can cause the animation to lose track. This ensures
72                // that it finishes in the proper location.
73                var sty = ani.curve.getValue(ani.reversed ? 0 : 1);
74                htmlUtil.style(node, sty);
75        });
76        connectUtil.connect(ani, "beforeBegin", function(){
77                // remove default curve and replace it with Timeline
78                if(ani.curve){ delete ani.curve; }
79                ani.curve = _curve;
80                _curve.ani = ani;
81        })
82        return ani; // dojo.Animation
83}
84
85var Timeline = function(/* Array */keys){
86        // summary:
87        //              The dojox.fx._Timeline object from which an instance
88        //              is created
89        // tags:
90        //              private
91        this.keys = lang.isArray(keys) ? this.flatten(keys) : keys;
92}
93
94Timeline.prototype.flatten = function(keys){
95        // summary:
96        //              An internally used function that converts the keyframes
97        //              as used in the example above into a series of key values
98        //              which is what is used in the animation parsing.
99        var getPercent = function(str, idx){
100                if(str == "from"){ return 0; }
101                if(str == "to"){ return 1; }
102                if(str === undefined){
103                        return idx==0 ? 0 : idx / (keys.length - 1)
104                }
105                return parseInt(str, 10) * .01
106        }
107        var p = {}, o = {};
108        arrayUtil.forEach(keys, function(k, i){
109                var step = getPercent(k.step, i);
110                var ease = easingUtil[k.ease] || easingUtil.linear;
111               
112                for(var nm in k){
113                        if(nm == "step" || nm == "ease" || nm == "from" || nm == "to"){ continue; }
114                        if(!o[nm]){
115                                o[nm] = {
116                                        steps:[],
117                                        values:[],
118                                        eases:[],
119                                        ease:ease
120                                };
121                                p[nm] = {};
122                                if(!/#/.test(k[nm])){
123                                        p[nm].units = o[nm].units = /\D{1,}/.exec(k[nm]).join("");
124                                }else{
125                                        p[nm].units = o[nm].units = "isColor";
126                                }
127                        }
128                       
129                        o[nm].eases.push(easingUtil[k.ease || "linear"]);
130                       
131                        o[nm].steps.push(step);
132                        if(p[nm].units == "isColor"){
133                                o[nm].values.push(new Color(k[nm]));
134                        }else{
135                                o[nm].values.push(parseInt(/\d{1,}/.exec(k[nm]).join("")));
136                        }
137                       
138                        if(p[nm].start === undefined){
139                                p[nm].start = o[nm].values[o[nm].values.length-1];
140                        }else{
141                                p[nm].end = o[nm].values[o[nm].values.length-1]
142                        }
143                }
144        });
145       
146       
147        this._properties = p;
148        return o; // Object
149       
150}
151
152Timeline.prototype.getValue = function(/*float*/ p){
153        // summary:
154        //              Replaces the native getValue in dojo.fx.Animation.
155        //              Returns an object with all propeties used in the animation
156        //              and the property's current value
157        p = this.ani._reversed ? 1-p : p;
158        var o = {}, self = this;
159       
160        var getProp = function(nm, i){
161                return self._properties[nm].units!="isColor" ?
162                        self.keys[nm].values[i] + self._properties[nm].units :
163                        self.keys[nm].values[i].toCss();
164        }
165       
166        for(var nm in this.keys){
167                var k = this.keys[nm];
168                for(var i=0; i<k.steps.length; i++){
169                       
170                        var step = k.steps[i];
171                        var ns = k.steps[i+1];
172                        var next = i < k.steps.length ? true : false;
173                        var ease = k.eases[i] || function(n){return n;};
174                       
175                        if(p == step){
176                                // first or last
177                                o[nm] = getProp(nm, i);
178                                if(!next || (next &&  this.ani._reversed)) break;
179                       
180                        }else if(p > step){
181                               
182                                if(next && p < k.steps[i+1]){
183                                        // inbetween steps
184                                        var end = k.values[i+1];
185                                        var beg = k.values[i];
186                                       
187                                        var seg = (1 / (ns - step)) * (p - step);
188                                        seg = ease(seg);
189                                       
190                                        if(beg instanceof Color){
191                                                o[nm] = Color.blendColors(beg, end, seg).toCss(false);
192                                        }else{
193                                                var df = end - beg;
194                                                o[nm] = beg + seg * df + this._properties[nm].units;
195                                        }
196                                        break;
197                               
198                                }else{
199                                        // completed keys before 100%
200                                        o[nm] = getProp(nm, i);
201                                }
202                               
203                        }else if((next && !this.ani._reversed) || (!next && this.ani._reversed)){
204                                o[nm] = getProp(nm, i);
205                        }
206                }
207        }
208        return o; // Object
209};
210dojoxFx._Timeline = Timeline;
211return dojoxFx;
212});
Note: See TracBrowser for help on using the repository browser.