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 * "forwards" 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 && this.shadowRoot) { |
| 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 effect = frames; |
| 379 } |
| 380 return effect; |
| 381 }, |
| 382 |
| 383 animationFinishHandler: function() { |
| 384 this.fire('core-animation-finish'); |
| 385 } |
| 386 |
| 387 }); |
| 388 })(); |
| 389 ; |
| 390 |
| 391 Polymer('core-animation-keyframe',{ |
| 392 publish: { |
| 393 /** |
| 394 * An offset from 0 to 1. |
| 395 * |
| 396 * @property offset |
| 397 * @type Number |
| 398 */ |
| 399 offset: {value: null, reflect: true} |
| 400 }, |
| 401 get properties() { |
| 402 var props = {}; |
| 403 var children = this.querySelectorAll('core-animation-prop'); |
| 404 Array.prototype.forEach.call(children, function(c) { |
| 405 props[c.name] = c.value; |
| 406 }); |
| 407 if (this.offset !== null) { |
| 408 props.offset = this.offset; |
| 409 } |
| 410 return props; |
| 411 } |
| 412 }); |
| 413 ; |
| 414 |
| 415 Polymer('core-animation-prop',{ |
| 416 publish: { |
| 417 /** |
| 418 * A CSS property name. |
| 419 * |
| 420 * @property name |
| 421 * @type string |
| 422 */ |
| 423 name: {value: '', reflect: true}, |
| 424 |
| 425 /** |
| 426 * The value for the CSS property. |
| 427 * |
| 428 * @property value |
| 429 * @type string|number |
| 430 */ |
| 431 value: {value: '', reflect: true} |
| 432 } |
| 433 }); |
| 434 |
OLD | NEW |