OLD | NEW |
| (Empty) |
1 | |
2 (function() { | |
3 | |
4 function toNumber(value, allowInfinity) { | |
5 return (allowInfinity && value === 'Infinity') ? Number.POSITIVE_INFINIT
Y : Number(value); | |
6 }; | |
7 | |
8 Polymer('core-animation',{ | |
9 /** | |
10 * Fired when the animation completes. | |
11 * | |
12 * @event core-animation-finish | |
13 */ | |
14 | |
15 /** | |
16 * | |
17 * Fired when the web animation object changes. | |
18 * | |
19 * @event core-animation-change | |
20 */ | |
21 | |
22 publish: { | |
23 | |
24 /** | |
25 * One or more nodes to animate. | |
26 * | |
27 * @property target | |
28 * @type HTMLElement|Node|Array<HTMLElement|Node> | |
29 */ | |
30 target: {value: null, reflect: true}, | |
31 | |
32 /** | |
33 * Animation keyframes specified as an array of dictionaries of | |
34 * <css properties>:<array of values> pairs. For example, | |
35 * | |
36 * @property keyframes | |
37 * @type Object | |
38 */ | |
39 keyframes: {value: null, reflect: true}, | |
40 | |
41 /** | |
42 * A custom animation function. Either provide this or `keyframes`. Th
e signature | |
43 * of the callback is `EffectsCallback(timeFraction, target, animation
)` | |
44 * | |
45 * @property customEffect | |
46 * @type Function(number, Object, Object) | |
47 */ | |
48 customEffect: {value: null, reflect: true}, | |
49 | |
50 /** | |
51 * Controls the composition behavior. If set to "replace", the effect
overrides | |
52 * the underlying value for the target. If set the "add", the effect i
s added to | |
53 * the underlying value for the target. If set to "accumulate", the ef
fect is | |
54 * accumulated to the underlying value for the target. | |
55 * | |
56 * In cases such as numbers or lengths, "add" and "accumulate" produce
the same | |
57 * value. In list values, "add" is appending to the list, while "accum
ulate" is | |
58 * adding the individual components of the list. | |
59 * | |
60 * For example, adding `translateX(10px)` and `translateX(25px)` produ
ces | |
61 * `translateX(10px) translateX(25px)` and accumulating produces `tran
slateX(35px)`. | |
62 * | |
63 * @property composite | |
64 * @type "replace"|"add"|"accumulate" | |
65 * @default "replace" | |
66 */ | |
67 composite: {value: 'replace', reflect: true}, | |
68 | |
69 /** | |
70 * Animation duration in milliseconds, "Infinity", or "auto". "auto" i
s | |
71 * equivalent to 0. | |
72 * | |
73 * @property duration | |
74 * @type number|"Infinity" | |
75 * @default "auto" | |
76 */ | |
77 duration: {value: 'auto', reflect: true}, | |
78 | |
79 /** | |
80 * Controls the effect the animation has on the target when it's not p
laying. | |
81 * The possible values are "none", "forwards", "backwards", "both" or
"auto". | |
82 * | |
83 * "none" means the animation has no effect when it's not playing. | |
84 * | |
85 * "forward" applies the value at the end of the animation after it's
finished. | |
86 * | |
87 * "backwards" applies the value at the start of the animation to the
target | |
88 * before it starts playing and has no effect when the animation finis
hes. | |
89 * | |
90 * "both" means "forwards" and "backwards". "auto" is equivalent to "n
one". | |
91 * | |
92 * @property fill | |
93 * @type "none"|"forwards"|"backwards"|"both"|"auto" | |
94 * @default "auto" | |
95 */ | |
96 fill: {value: 'auto', reflect: true}, | |
97 | |
98 /** | |
99 * A transition timing function. The values are equivalent to the CSS | |
100 * counterparts. | |
101 * | |
102 * @property easing | |
103 * @type string | |
104 * @default "linear" | |
105 */ | |
106 easing: {value: 'linear', reflect: true}, | |
107 | |
108 /** | |
109 * The number of milliseconds to delay before beginning the animation. | |
110 * | |
111 * @property delay | |
112 * @type Number | |
113 * @default 0 | |
114 */ | |
115 delay: {value: 0, reflect: true}, | |
116 | |
117 /** | |
118 * The number of milliseconds to wait after the animation finishes. Th
is is | |
119 * useful, for example, in an animation group to wait for some time be
fore | |
120 * beginning the next item in the animation group. | |
121 * | |
122 * @property endDelay | |
123 * @type number | |
124 * @default 0 | |
125 */ | |
126 endDelay: {value: 0, reflect: true}, | |
127 | |
128 /** | |
129 * The number of iterations this animation should run for. | |
130 * | |
131 * @property iterations | |
132 * @type Number|'Infinity' | |
133 * @default 1 | |
134 */ | |
135 iterations: {value: 1, reflect: true}, | |
136 | |
137 /** | |
138 * Number of iterations into the animation in which to begin the effec
t. | |
139 * For example, setting this property to 0.5 and `iterations` to 2 wil
l | |
140 * cause the animation to begin halfway through the first iteration bu
t still | |
141 * run twice. | |
142 * | |
143 * @property iterationStart | |
144 * @type Number | |
145 * @default 0 | |
146 */ | |
147 iterationStart: {value: 0, reflect: true}, | |
148 | |
149 /** | |
150 * (not working in web animations polyfill---do not use) | |
151 * | |
152 * Controls the iteration composition behavior. If set to "replace", t
he effect for | |
153 * every iteration is independent of each other. If set to "accumulate
", the effect | |
154 * for iterations of the animation will build upon the value in the pr
evious iteration. | |
155 * | |
156 * Example: | |
157 * | |
158 * // Moves the target 50px on the x-axis over 5 iterations. | |
159 * <core-animation iterations="5" iterationComposite="accumulate"> | |
160 * <core-animation-keyframe> | |
161 * <core-animation-prop name="transform" value="translateX(10px
)"></core-animation-prop> | |
162 * </core-animation-keyframe> | |
163 * </core-animation> | |
164 * | |
165 * @property iterationComposite | |
166 * @type "replace"|"accumulate" | |
167 * @default false | |
168 */ | |
169 iterationComposite: {value: 'replace', reflect: true}, | |
170 | |
171 /** | |
172 * The playback direction of the animation. "normal" plays the animati
on in the | |
173 * normal direction. "reverse" plays it in the reverse direction. "alt
ernate" | |
174 * alternates the playback direction every iteration such that even it
erations are | |
175 * played normally and odd iterations are reversed. "alternate-reverse
" plays | |
176 * even iterations in the reverse direction and odd iterations in the
normal | |
177 * direction. | |
178 * | |
179 * @property direction | |
180 * @type "normal"|"reverse"|"alternate"|"alternate-reverse" | |
181 * @default "normal" | |
182 */ | |
183 direction: {value: 'normal', reflect: true}, | |
184 | |
185 /** | |
186 * A multiplier to the playback rate to the animation. | |
187 * | |
188 * @property playbackRate | |
189 * @type number | |
190 * @default 1 | |
191 */ | |
192 playbackRate: {value: 1, reflect: true}, | |
193 | |
194 /** | |
195 * If set to true, play the animation when it is created or a property
is updated. | |
196 * | |
197 * @property autoplay | |
198 * @type boolean | |
199 * @default false | |
200 */ | |
201 autoplay: {value: false, reflect: true} | |
202 | |
203 }, | |
204 | |
205 animation: false, | |
206 | |
207 observe: { | |
208 target: 'apply', | |
209 keyframes: 'apply', | |
210 customEffect: 'apply', | |
211 composite: 'apply', | |
212 duration: 'apply', | |
213 fill: 'apply', | |
214 easing: 'apply', | |
215 iterations: 'apply', | |
216 iterationStart: 'apply', | |
217 iterationComposite: 'apply', | |
218 delay: 'apply', | |
219 endDelay: 'apply', | |
220 direction: 'apply', | |
221 playbackRate: 'apply', | |
222 autoplay: 'apply' | |
223 }, | |
224 | |
225 ready: function() { | |
226 this.apply(); | |
227 }, | |
228 | |
229 /** | |
230 * Plays the animation. If the animation is currently paused, seeks the
animation | |
231 * to the beginning before starting playback. | |
232 * | |
233 * @method play | |
234 * @return AnimationPlayer The animation player. | |
235 */ | |
236 play: function() { | |
237 this.apply(); | |
238 if (this.animation && !this.autoplay) { | |
239 this.player = document.timeline.play(this.animation); | |
240 this.player.onfinish = this.animationFinishHandler.bind(this); | |
241 return this.player; | |
242 } | |
243 }, | |
244 | |
245 /** | |
246 * Stops the animation and clears all effects on the target. | |
247 * | |
248 * @method cancel | |
249 */ | |
250 cancel: function() { | |
251 if (this.player) { | |
252 this.player.cancel(); | |
253 } | |
254 }, | |
255 | |
256 /** | |
257 * Seeks the animation to the end. | |
258 * | |
259 * @method finish | |
260 */ | |
261 finish: function() { | |
262 if (this.player) { | |
263 this.player.finish(); | |
264 } | |
265 }, | |
266 | |
267 /** | |
268 * Pauses the animation. | |
269 * | |
270 * @method pause | |
271 */ | |
272 pause: function() { | |
273 if (this.player) { | |
274 this.player.pause(); | |
275 } | |
276 }, | |
277 | |
278 /** | |
279 * @method hasTarget | |
280 * @return boolean True if `target` is defined. | |
281 */ | |
282 hasTarget: function() { | |
283 return this.target !== null; | |
284 }, | |
285 | |
286 /** | |
287 * Creates a web animations object based on this object's properties, an
d | |
288 * plays it if autoplay is true. | |
289 * | |
290 * @method apply | |
291 * @return Object A web animation. | |
292 */ | |
293 apply: function() { | |
294 this.animation = this.makeAnimation(); | |
295 if (this.autoplay && this.animation) { | |
296 this.play(); | |
297 } | |
298 return this.animation; | |
299 }, | |
300 | |
301 makeSingleAnimation: function(target) { | |
302 // XXX(yvonne): for selecting all the animated elements. | |
303 target.classList.add('core-animation-target'); | |
304 return new Animation(target, this.animationEffect, this.timingProps); | |
305 }, | |
306 | |
307 makeAnimation: function() { | |
308 if (!this.target) { | |
309 return null; | |
310 } | |
311 var animation; | |
312 if (Array.isArray(this.target)) { | |
313 var array = []; | |
314 this.target.forEach(function(t) { | |
315 array.push(this.makeSingleAnimation(t)); | |
316 }.bind(this)); | |
317 animation = new AnimationGroup(array); | |
318 } else { | |
319 animation = this.makeSingleAnimation(this.target); | |
320 } | |
321 return animation; | |
322 }, | |
323 | |
324 animationChanged: function() { | |
325 // Sending 'this' with the event so you can always get the animation o
bject | |
326 // that fired the event, due to event retargetting in shadow DOM. | |
327 this.fire('core-animation-change', this); | |
328 }, | |
329 | |
330 targetChanged: function(old) { | |
331 if (old) { | |
332 old.classList.remove('core-animation-target'); | |
333 } | |
334 }, | |
335 | |
336 get timingProps() { | |
337 var props = {}; | |
338 var timing = { | |
339 delay: {isNumber: true}, | |
340 endDelay: {isNumber: true}, | |
341 fill: {}, | |
342 iterationStart: {isNumber: true}, | |
343 iterations: {isNumber: true, allowInfinity: true}, | |
344 duration: {isNumber: true}, | |
345 playbackRate: {isNumber: true}, | |
346 direction: {}, | |
347 easing: {} | |
348 }; | |
349 for (t in timing) { | |
350 if (this[t] !== null) { | |
351 var name = timing[t].property || t; | |
352 props[name] = timing[t].isNumber && this[t] !== 'auto' ? | |
353 toNumber(this[t], timing[t].allowInfinity) : this[t]; | |
354 } | |
355 } | |
356 return props; | |
357 }, | |
358 | |
359 get animationEffect() { | |
360 var props = {}; | |
361 var frames = []; | |
362 var effect; | |
363 if (this.keyframes) { | |
364 frames = this.keyframes; | |
365 } else if (!this.customEffect) { | |
366 var children = this.querySelectorAll('core-animation-keyframe'); | |
367 if (children.length === 0) { | |
368 children = this.shadowRoot.querySelectorAll('core-animation-keyfra
me'); | |
369 } | |
370 Array.prototype.forEach.call(children, function(c) { | |
371 frames.push(c.properties); | |
372 }); | |
373 } | |
374 if (this.customEffect) { | |
375 effect = this.customEffect; | |
376 } else { | |
377 effect = new KeyframeEffect(frames, this.composite); | |
378 } | |
379 return effect; | |
380 }, | |
381 | |
382 animationFinishHandler: function() { | |
383 this.fire('core-animation-finish'); | |
384 } | |
385 | |
386 }); | |
387 })(); | |
388 ; | |
389 | |
390 Polymer('core-animation-keyframe',{ | |
391 publish: { | |
392 /** | |
393 * An offset from 0 to 1. | |
394 * | |
395 * @property offset | |
396 * @type Number | |
397 */ | |
398 offset: {value: null, reflect: true} | |
399 }, | |
400 get properties() { | |
401 var props = {}; | |
402 var children = this.querySelectorAll('core-animation-prop'); | |
403 Array.prototype.forEach.call(children, function(c) { | |
404 props[c.name] = c.value; | |
405 }); | |
406 if (this.offset !== null) { | |
407 props.offset = this.offset; | |
408 } | |
409 return props; | |
410 } | |
411 }); | |
412 ; | |
413 | |
414 Polymer('core-animation-prop',{ | |
415 publish: { | |
416 /** | |
417 * A CSS property name. | |
418 * | |
419 * @property name | |
420 * @type string | |
421 */ | |
422 name: {value: '', reflect: true}, | |
423 | |
424 /** | |
425 * The value for the CSS property. | |
426 * | |
427 * @property value | |
428 * @type string|number | |
429 */ | |
430 value: {value: '', reflect: true} | |
431 } | |
432 }); | |
433 | |
OLD | NEW |