source: Dev/trunk/src/client/dojox/fx/Timeline.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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