OLD | NEW |
| (Empty) |
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.g
ithub.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/CONTRI
BUTORS.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/PATEN
TS.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 ele
ments. 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-ta
rget` class. | |
60 | |
61 @element core-animation | |
62 @status beta | |
63 @homepage github.io | |
64 --> | |
65 <polymer-element name="core-animation" constructor="CoreAnimation" attributes="t
arget keyframes sample composite duration fill easing iterationStart iterationCo
unt delay direction autoplay targetSelector"> | |
66 <script> | |
67 (function() { | |
68 | |
69 function toNumber(value, allowInfinity) { | |
70 return (allowInfinity && value === 'Infinity') ? Number.POSITIVE_INFINIT
Y : 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 * <css properties>:<array of values> 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`. Th
e 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 i
s added to | |
118 * the underlying value for the target. If set to "accumulate", the ef
fect 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 "accum
ulate" is | |
123 * adding the individual components of the list. | |
124 * | |
125 * For example, adding `translateX(10px)` and `translateX(25px)` produ
ces | |
126 * `translateX(10px) translateX(25px)` and accumulating produces `tran
slateX(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" i
s | |
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 p
laying. | |
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 finis
hes. | |
154 * | |
155 * "both" means "forwards" and "backwards". "auto" is equivalent to "n
one". | |
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. Th
is is | |
184 * useful, for example, in an animation group to wait for some time be
fore | |
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 effec
t. | |
204 * For example, setting this property to 0.5 and `iterations` to 2 wil
l | |
205 * cause the animation to begin halfway through the first iteration bu
t 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", t
he 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 pr
evious 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 animati
on in the | |
238 * normal direction. "reverse" plays it in the reverse direction. "alt
ernate" | |
239 * alternates the playback direction every iteration such that even it
erations 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, an
d | |
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 o
bject | |
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-keyfra
me'); | |
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. U
se | |
460 `core-animation-prop` elements as children of this element to specify the CSS pr
operties 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> | |
OLD | NEW |