Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / polymer / components / core-animation / core-animation.html
1 <!--
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 Code distributed by Google as part of the polymer project is also
7 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
8 -->
9
10 <link rel="import" href="../polymer/polymer.html">
11 <link rel="import" href="web-animations.html">
12
13 <!--
14 @group Polymer Core Elements
15
16 `core-animation` is a convenience element to use web animations with Polymer elements. It
17 allows you to create a web animation declaratively. You can extend this class to create
18 new types of animations and combine them with `core-animation-group`.
19
20 Example to create animation to fade out an element over 500ms:
21
22     <core-animation id="fadeout" duration="500">
23       <core-animation-keyframe>
24         <core-animation-prop name="opacity" value="1"></core-animation-prop>
25       </core-animation-keyframe>
26       <core-animation-keyframe>
27         <core-animation-prop name="opacity" value="0"></core-animation-prop>
28       </core-animation-keyframe>
29     </core-animation>
30
31     <div id="el">Fade me out</div>
32
33     <script>
34       var animation = document.getElementById('fadeout');
35       animation.target = document.getElementById('el');
36       animation.play();
37     </script>
38
39 Or do the same imperatively:
40
41     var animation = new CoreAnimation();
42     animation.duration = 500;
43     animation.keyframes = [
44       {opacity: 1},
45       {opacity: 0}
46     ];
47     animation.target = document.getElementById('el');
48     animation.play();
49
50 You can also provide a javascript function instead of keyframes to the animation. This
51 behaves essentially the same as `requestAnimationFrame`:
52
53     var animation = new CoreAnimation();
54     animation.customEffect = function(timeFraction, target, animation) {
55       // do something custom
56     };
57     animation.play();
58
59 Elements that are targets to a `core-animation` are given the `core-animation-target` class.
60
61 @element core-animation
62 @status beta
63 @homepage github.io
64 -->
65 <polymer-element name="core-animation" constructor="CoreAnimation" attributes="target keyframes sample composite duration fill easing iterationStart iterationCount delay direction autoplay targetSelector">
66   <script>
67     (function() {
68
69       function toNumber(value, allowInfinity) {
70         return (allowInfinity && value === 'Infinity') ? Number.POSITIVE_INFINITY : Number(value);
71       };
72
73       Polymer({
74        /**
75         * Fired when the animation completes.
76         *
77         * @event core-animation-finish
78         */
79
80        /**
81         *
82         * Fired when the web animation object changes.
83         * 
84         * @event core-animation-change
85         */
86
87         publish: {
88
89           /**
90            * One or more nodes to animate.
91            *
92            * @property target
93            * @type HTMLElement|Node|Array<HTMLElement|Node>
94            */
95           target: {value: null, reflect: true},
96
97           /**
98            * Animation keyframes specified as an array of dictionaries of
99            * &lt;css properties&gt;:&lt;array of values&gt; pairs. For example,
100            *
101            * @property keyframes
102            * @type Object
103            */
104           keyframes: {value: null, reflect: true},
105
106           /**
107            * A custom animation function. Either provide this or `keyframes`. The signature
108            * of the callback is `EffectsCallback(timeFraction, target, animation)`
109            *
110            * @property customEffect
111            * @type Function(number, Object, Object)
112            */
113           customEffect: {value: null, reflect: true},
114
115           /**
116            * Controls the composition behavior. If set to "replace", the effect overrides
117            * the underlying value for the target. If set the "add", the effect is added to
118            * the underlying value for the target. If set to "accumulate", the effect is
119            * accumulated to the underlying value for the target.
120            *
121            * In cases such as numbers or lengths, "add" and "accumulate" produce the same
122            * value. In list values, "add" is appending to the list, while "accumulate" is
123            * adding the individual components of the list.
124            *
125            * For example, adding `translateX(10px)` and `translateX(25px)` produces
126            * `translateX(10px) translateX(25px)` and accumulating produces `translateX(35px)`.
127            *
128            * @property composite
129            * @type "replace"|"add"|"accumulate"
130            * @default "replace"
131            */
132           composite: {value: 'replace', reflect: true},
133
134           /**
135            * Animation duration in milliseconds, "Infinity", or "auto". "auto" is
136            * equivalent to 0.
137            *
138            * @property duration
139            * @type number|"Infinity"
140            * @default "auto"
141            */
142           duration: {value: 'auto', reflect: true},
143
144           /**
145            * Controls the effect the animation has on the target when it's not playing.
146            * The possible values are "none", "forwards", "backwards", "both" or "auto". 
147            *
148            * "none" means the animation has no effect when it's not playing.
149            *
150            * "forward" applies the value at the end of the animation after it's finished.
151            *
152            * "backwards" applies the value at the start of the animation to the target
153            * before it starts playing and has no effect when the animation finishes.
154            *
155            * "both" means "forwards" and "backwards". "auto" is equivalent to "none".
156            *
157            * @property fill
158            * @type "none"|"forwards"|"backwards"|"both"|"auto"
159            * @default "auto"
160            */
161           fill: {value: 'auto', reflect: true},
162
163           /**
164            * A transition timing function. The values are equivalent to the CSS
165            * counterparts.
166            *
167            * @property easing
168            * @type string
169            * @default "linear"
170            */
171           easing: {value: 'linear', reflect: true},
172
173           /**
174            * The number of milliseconds to delay before beginning the animation.
175            *
176            * @property delay
177            * @type Number
178            * @default 0
179            */
180           delay: {value: 0, reflect: true},
181
182           /**
183            * The number of milliseconds to wait after the animation finishes. This is
184            * useful, for example, in an animation group to wait for some time before
185            * beginning the next item in the animation group.
186            *
187            * @property endDelay
188            * @type number
189            * @default 0
190            */
191           endDelay: {value: 0, reflect: true},
192
193           /**
194            * The number of iterations this animation should run for.
195            *
196            * @property iterations
197            * @type Number|'Infinity'
198            * @default 1
199            */
200           iterations: {value: 1, reflect: true},
201
202           /**
203            * Number of iterations into the animation in which to begin the effect.
204            * For example, setting this property to 0.5 and `iterations` to 2 will
205            * cause the animation to begin halfway through the first iteration but still
206            * run twice.
207            *
208            * @property iterationStart
209            * @type Number
210            * @default 0
211            */
212           iterationStart: {value: 0, reflect: true},
213
214           /**
215            * (not working in web animations polyfill---do not use)
216            *
217            * Controls the iteration composition behavior. If set to "replace", the effect for
218            * every iteration is independent of each other. If set to "accumulate", the effect
219            * for iterations of the animation will build upon the value in the previous iteration.
220            *
221            * Example:
222            *
223            *    // Moves the target 50px on the x-axis over 5 iterations.
224            *    <core-animation iterations="5" iterationComposite="accumulate">
225            *      <core-animation-keyframe>
226            *        <core-animation-prop name="transform" value="translateX(10px)"></core-animation-prop>
227            *      </core-animation-keyframe>
228            *    </core-animation>
229            *
230            * @property iterationComposite
231            * @type "replace"|"accumulate"
232            * @default false
233            */
234           iterationComposite: {value: 'replace', reflect: true},
235
236           /**
237            * The playback direction of the animation. "normal" plays the animation in the
238            * normal direction. "reverse" plays it in the reverse direction. "alternate"
239            * alternates the playback direction every iteration such that even iterations are
240            * played normally and odd iterations are reversed. "alternate-reverse" plays
241            * even iterations in the reverse direction and odd iterations in the normal
242            * direction.
243            *
244            * @property direction
245            * @type "normal"|"reverse"|"alternate"|"alternate-reverse"
246            * @default "normal"
247            */
248           direction: {value: 'normal', reflect: true},
249
250           /**
251            * A multiplier to the playback rate to the animation.
252            *
253            * @property playbackRate
254            * @type number
255            * @default 1
256            */
257           playbackRate: {value: 1, reflect: true},
258
259           /**
260            * If set to true, play the animation when it is created or a property is updated.
261            *
262            * @property autoplay
263            * @type boolean
264            * @default false
265            */
266           autoplay: {value: false, reflect: true}
267
268         },
269
270         animation: false,
271
272         observe: {
273           target: 'apply',
274           keyframes: 'apply',
275           customEffect: 'apply',
276           composite: 'apply',
277           duration: 'apply',
278           fill: 'apply',
279           easing: 'apply',
280           iterations: 'apply',
281           iterationStart: 'apply',
282           iterationComposite: 'apply',
283           delay: 'apply',
284           endDelay: 'apply',
285           direction: 'apply',
286           playbackRate: 'apply',
287           autoplay: 'apply'
288         },
289
290         ready: function() {
291           this.apply();
292         },
293
294         /**
295          * Plays the animation. If the animation is currently paused, seeks the animation
296          * to the beginning before starting playback.
297          *
298          * @method play
299          * @return AnimationPlayer The animation player.
300          */
301         play: function() {
302           this.apply();
303           if (this.animation && !this.autoplay) {
304             this.player = document.timeline.play(this.animation);
305             this.player.onfinish = this.animationFinishHandler.bind(this);
306             return this.player;
307           }
308         },
309
310         /**
311          * Stops the animation and clears all effects on the target.
312          *
313          * @method cancel
314          */
315         cancel: function() {
316           if (this.player) {
317             this.player.cancel();
318           }
319         },
320
321         /**
322          * Seeks the animation to the end.
323          *
324          * @method finish
325          */
326         finish: function() {
327           if (this.player) {
328             this.player.finish();
329           }
330         },
331
332         /**
333          * Pauses the animation.
334          *
335          * @method pause
336          */
337         pause: function() {
338           if (this.player) {
339             this.player.pause();
340           }
341         },
342
343         /**
344          * @method hasTarget
345          * @return boolean True if `target` is defined.
346          */
347         hasTarget: function() {
348           return this.target !== null;
349         },
350
351         /**
352          * Creates a web animations object based on this object's properties, and
353          * plays it if autoplay is true.
354          *
355          * @method apply
356          * @return Object A web animation.
357          */
358         apply: function() {
359           this.animation = this.makeAnimation();
360           if (this.autoplay && this.animation) {
361             this.play();
362           }
363           return this.animation;
364         },
365
366         makeSingleAnimation: function(target) {
367           // XXX(yvonne): for selecting all the animated elements.
368           target.classList.add('core-animation-target');
369           return new Animation(target, this.animationEffect, this.timingProps);
370         },
371
372         makeAnimation: function() {
373           if (!this.target) {
374             return null;
375           }
376           var animation;
377           if (Array.isArray(this.target)) {
378             var array = [];
379             this.target.forEach(function(t) {
380               array.push(this.makeSingleAnimation(t));
381             }.bind(this));
382             animation = new AnimationGroup(array);
383           } else {
384             animation = this.makeSingleAnimation(this.target);
385           }
386           return animation;
387         },
388
389         animationChanged: function() {
390           // Sending 'this' with the event so you can always get the animation object
391           // that fired the event, due to event retargetting in shadow DOM.
392           this.fire('core-animation-change', this);
393         },
394
395         targetChanged: function(old) {
396           if (old) {
397             old.classList.remove('core-animation-target');
398           }
399         },
400
401         get timingProps() {
402           var props = {};
403           var timing = {
404             delay: {isNumber: true},
405             endDelay: {isNumber: true},
406             fill: {},
407             iterationStart: {isNumber: true},
408             iterations: {isNumber: true, allowInfinity: true},
409             duration: {isNumber: true},
410             playbackRate: {isNumber: true},
411             direction: {},
412             easing: {}
413           };
414           for (t in timing) {
415             if (this[t] !== null) {
416               var name = timing[t].property || t;
417               props[name] = timing[t].isNumber && this[t] !== 'auto' ?
418                   toNumber(this[t], timing[t].allowInfinity) : this[t];
419             }
420           }
421           return props;
422         },
423
424         get animationEffect() {
425           var props = {};
426           var frames = [];
427           var effect;
428           if (this.keyframes) {
429             frames = this.keyframes;
430           } else if (!this.customEffect) {
431             var children = this.querySelectorAll('core-animation-keyframe');
432             if (children.length === 0) {
433               children = this.shadowRoot.querySelectorAll('core-animation-keyframe');
434             }
435             Array.prototype.forEach.call(children, function(c) {
436               frames.push(c.properties);
437             });
438           }
439           if (this.customEffect) {
440             effect = this.customEffect;
441           } else {
442             effect = new KeyframeEffect(frames, this.composite);
443           }
444           return effect;
445         },
446
447         animationFinishHandler: function() {
448           this.fire('core-animation-finish');
449         }
450
451       });
452     })();
453   </script>
454 </polymer-element>
455
456 <!--
457 `core-animation-keyframe` represents a keyframe in a `core-animation`. Use them as children of
458 `core-animation` elements to create web animations declaratively. If the `offset` property is
459 unset, the keyframes will be distributed evenly within the animation duration. Use
460 `core-animation-prop` elements as children of this element to specify the CSS properties for
461 the animation.
462
463 @element core-animation-keyframe
464 @status beta
465 @homepage github.io
466 -->
467 <polymer-element name="core-animation-keyframe" attributes="offset">
468   <script>
469     Polymer({
470       publish: {
471         /**
472          * An offset from 0 to 1.
473          *
474          * @property offset
475          * @type Number
476          */
477         offset: {value: null, reflect: true}
478       },
479       get properties() {
480         var props = {};
481         var children = this.querySelectorAll('core-animation-prop');
482         Array.prototype.forEach.call(children, function(c) {
483           props[c.name] = c.value;
484         });
485         if (this.offset !== null) {
486           props.offset = this.offset;
487         }
488         return props;
489       }
490     });
491   </script>
492 </polymer-element>
493
494 <!--
495 `core-animation-prop` represents a CSS property and value pair to use with
496 `core-animation-keyframe`.
497
498 @element core-animation-prop
499 @status beta
500 @homepage github.io
501 -->
502 <polymer-element name="core-animation-prop" attributes="name value">
503   <script>
504     Polymer({
505       publish: {
506         /**
507          * A CSS property name.
508          *
509          * @property name
510          * @type string
511          */
512         name: {value: '', reflect: true},
513
514         /**
515          * The value for the CSS property.
516          *
517          * @property value
518          * @type string|number
519          */
520         value: {value: '', reflect: true}
521       }
522     });
523   </script>
524 </polymer-element>