Index: third_party/polymer/components/core-animation/core-animation.html |
diff --git a/third_party/polymer/components/core-animation/core-animation.html b/third_party/polymer/components/core-animation/core-animation.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9a958c9eafadd6dd204e9ca4f62f5862b2727330 |
--- /dev/null |
+++ b/third_party/polymer/components/core-animation/core-animation.html |
@@ -0,0 +1,525 @@ |
+<!-- |
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
+Code distributed by Google as part of the polymer project is also |
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
+--> |
+ |
+<link rel="import" href="../polymer/polymer.html"> |
+<link rel="import" href="web-animations.html"> |
+ |
+<!-- |
+@group Polymer Core Elements |
+ |
+`core-animation` is a convenience element to use web animations with Polymer elements. It |
+allows you to create a web animation declaratively. You can extend this class to create |
+new types of animations and combine them with `core-animation-group`. |
+ |
+Example to create animation to fade out an element over 500ms: |
+ |
+ <core-animation id="fadeout" duration="500"> |
+ <core-animation-keyframe> |
+ <core-animation-prop name="opacity" value="1"></core-animation-prop> |
+ </core-animation-keyframe> |
+ <core-animation-keyframe> |
+ <core-animation-prop name="opacity" value="0"></core-animation-prop> |
+ </core-animation-keyframe> |
+ </core-animation> |
+ |
+ <div id="el">Fade me out</div> |
+ |
+ <script> |
+ var animation = document.getElementById('fadeout'); |
+ animation.target = document.getElementById('el'); |
+ animation.play(); |
+ </script> |
+ |
+Or do the same imperatively: |
+ |
+ var animation = new CoreAnimation(); |
+ animation.duration = 500; |
+ animation.keyframes = [ |
+ {opacity: 1}, |
+ {opacity: 0} |
+ ]; |
+ animation.target = document.getElementById('el'); |
+ animation.play(); |
+ |
+You can also provide a javascript function instead of keyframes to the animation. This |
+behaves essentially the same as `requestAnimationFrame`: |
+ |
+ var animation = new CoreAnimation(); |
+ animation.customEffect = function(timeFraction, target, animation) { |
+ // do something custom |
+ }; |
+ animation.play(); |
+ |
+Elements that are targets to a `core-animation` are given the `core-animation-target` class. |
+ |
+@element core-animation |
+@status beta |
+@homepage github.io |
+--> |
+<polymer-element name="core-animation" constructor="CoreAnimation" attributes="target keyframes customEffect composite duration fill easing iterationStart iterationCount delay direction autoplay targetSelector"> |
+ <script> |
+ (function() { |
+ |
+ function toNumber(value, allowInfinity) { |
+ return (allowInfinity && value === 'Infinity') ? Number.POSITIVE_INFINITY : Number(value); |
+ }; |
+ |
+ Polymer({ |
+ /** |
+ * Fired when the animation completes. |
+ * |
+ * @event core-animation-finish |
+ */ |
+ |
+ /** |
+ * |
+ * Fired when the web animation object changes. |
+ * |
+ * @event core-animation-change |
+ */ |
+ |
+ publish: { |
+ |
+ /** |
+ * One or more nodes to animate. |
+ * |
+ * @property target |
+ * @type HTMLElement|Node|Array<HTMLElement|Node> |
+ */ |
+ target: {value: null, reflect: true}, |
+ |
+ /** |
+ * Animation keyframes specified as an array of dictionaries of |
+ * <css properties>:<array of values> pairs. For example, |
+ * |
+ * @property keyframes |
+ * @type Object |
+ */ |
+ keyframes: {value: null, reflect: true}, |
+ |
+ /** |
+ * A custom animation function. Either provide this or `keyframes`. The signature |
+ * of the callback is `EffectsCallback(timeFraction, target, animation)` |
+ * |
+ * @property customEffect |
+ * @type Function(number, Object, Object) |
+ */ |
+ customEffect: {value: null, reflect: true}, |
+ |
+ /** |
+ * Controls the composition behavior. If set to "replace", the effect overrides |
+ * the underlying value for the target. If set the "add", the effect is added to |
+ * the underlying value for the target. If set to "accumulate", the effect is |
+ * accumulated to the underlying value for the target. |
+ * |
+ * In cases such as numbers or lengths, "add" and "accumulate" produce the same |
+ * value. In list values, "add" is appending to the list, while "accumulate" is |
+ * adding the individual components of the list. |
+ * |
+ * For example, adding `translateX(10px)` and `translateX(25px)` produces |
+ * `translateX(10px) translateX(25px)` and accumulating produces `translateX(35px)`. |
+ * |
+ * @property composite |
+ * @type "replace"|"add"|"accumulate" |
+ * @default "replace" |
+ */ |
+ composite: {value: 'replace', reflect: true}, |
+ |
+ /** |
+ * Animation duration in milliseconds, "Infinity", or "auto". "auto" is |
+ * equivalent to 0. |
+ * |
+ * @property duration |
+ * @type number|"Infinity" |
+ * @default "auto" |
+ */ |
+ duration: {value: 'auto', reflect: true}, |
+ |
+ /** |
+ * Controls the effect the animation has on the target when it's not playing. |
+ * The possible values are "none", "forwards", "backwards", "both" or "auto". |
+ * |
+ * "none" means the animation has no effect when it's not playing. |
+ * |
+ * "forwards" applies the value at the end of the animation after it's finished. |
+ * |
+ * "backwards" applies the value at the start of the animation to the target |
+ * before it starts playing and has no effect when the animation finishes. |
+ * |
+ * "both" means "forwards" and "backwards". "auto" is equivalent to "none". |
+ * |
+ * @property fill |
+ * @type "none"|"forwards"|"backwards"|"both"|"auto" |
+ * @default "auto" |
+ */ |
+ fill: {value: 'auto', reflect: true}, |
+ |
+ /** |
+ * A transition timing function. The values are equivalent to the CSS |
+ * counterparts. |
+ * |
+ * @property easing |
+ * @type string |
+ * @default "linear" |
+ */ |
+ easing: {value: 'linear', reflect: true}, |
+ |
+ /** |
+ * The number of milliseconds to delay before beginning the animation. |
+ * |
+ * @property delay |
+ * @type Number |
+ * @default 0 |
+ */ |
+ delay: {value: 0, reflect: true}, |
+ |
+ /** |
+ * The number of milliseconds to wait after the animation finishes. This is |
+ * useful, for example, in an animation group to wait for some time before |
+ * beginning the next item in the animation group. |
+ * |
+ * @property endDelay |
+ * @type number |
+ * @default 0 |
+ */ |
+ endDelay: {value: 0, reflect: true}, |
+ |
+ /** |
+ * The number of iterations this animation should run for. |
+ * |
+ * @property iterations |
+ * @type Number|'Infinity' |
+ * @default 1 |
+ */ |
+ iterations: {value: 1, reflect: true}, |
+ |
+ /** |
+ * Number of iterations into the animation in which to begin the effect. |
+ * For example, setting this property to 0.5 and `iterations` to 2 will |
+ * cause the animation to begin halfway through the first iteration but still |
+ * run twice. |
+ * |
+ * @property iterationStart |
+ * @type Number |
+ * @default 0 |
+ */ |
+ iterationStart: {value: 0, reflect: true}, |
+ |
+ /** |
+ * (not working in web animations polyfill---do not use) |
+ * |
+ * Controls the iteration composition behavior. If set to "replace", the effect for |
+ * every iteration is independent of each other. If set to "accumulate", the effect |
+ * for iterations of the animation will build upon the value in the previous iteration. |
+ * |
+ * Example: |
+ * |
+ * // Moves the target 50px on the x-axis over 5 iterations. |
+ * <core-animation iterations="5" iterationComposite="accumulate"> |
+ * <core-animation-keyframe> |
+ * <core-animation-prop name="transform" value="translateX(10px)"></core-animation-prop> |
+ * </core-animation-keyframe> |
+ * </core-animation> |
+ * |
+ * @property iterationComposite |
+ * @type "replace"|"accumulate" |
+ * @default false |
+ */ |
+ iterationComposite: {value: 'replace', reflect: true}, |
+ |
+ /** |
+ * The playback direction of the animation. "normal" plays the animation in the |
+ * normal direction. "reverse" plays it in the reverse direction. "alternate" |
+ * alternates the playback direction every iteration such that even iterations are |
+ * played normally and odd iterations are reversed. "alternate-reverse" plays |
+ * even iterations in the reverse direction and odd iterations in the normal |
+ * direction. |
+ * |
+ * @property direction |
+ * @type "normal"|"reverse"|"alternate"|"alternate-reverse" |
+ * @default "normal" |
+ */ |
+ direction: {value: 'normal', reflect: true}, |
+ |
+ /** |
+ * A multiplier to the playback rate to the animation. |
+ * |
+ * @property playbackRate |
+ * @type number |
+ * @default 1 |
+ */ |
+ playbackRate: {value: 1, reflect: true}, |
+ |
+ /** |
+ * If set to true, play the animation when it is created or a property is updated. |
+ * |
+ * @property autoplay |
+ * @type boolean |
+ * @default false |
+ */ |
+ autoplay: {value: false, reflect: true} |
+ |
+ }, |
+ |
+ animation: false, |
+ |
+ observe: { |
+ target: 'apply', |
+ keyframes: 'apply', |
+ customEffect: 'apply', |
+ composite: 'apply', |
+ duration: 'apply', |
+ fill: 'apply', |
+ easing: 'apply', |
+ iterations: 'apply', |
+ iterationStart: 'apply', |
+ iterationComposite: 'apply', |
+ delay: 'apply', |
+ endDelay: 'apply', |
+ direction: 'apply', |
+ playbackRate: 'apply', |
+ autoplay: 'apply' |
+ }, |
+ |
+ ready: function() { |
+ this.apply(); |
+ }, |
+ |
+ /** |
+ * Plays the animation. If the animation is currently paused, seeks the animation |
+ * to the beginning before starting playback. |
+ * |
+ * @method play |
+ * @return AnimationPlayer The animation player. |
+ */ |
+ play: function() { |
+ this.apply(); |
+ if (this.animation && !this.autoplay) { |
+ this.player = document.timeline.play(this.animation); |
+ this.player.onfinish = this.animationFinishHandler.bind(this); |
+ return this.player; |
+ } |
+ }, |
+ |
+ /** |
+ * Stops the animation and clears all effects on the target. |
+ * |
+ * @method cancel |
+ */ |
+ cancel: function() { |
+ if (this.player) { |
+ this.player.cancel(); |
+ } |
+ }, |
+ |
+ /** |
+ * Seeks the animation to the end. |
+ * |
+ * @method finish |
+ */ |
+ finish: function() { |
+ if (this.player) { |
+ this.player.finish(); |
+ } |
+ }, |
+ |
+ /** |
+ * Pauses the animation. |
+ * |
+ * @method pause |
+ */ |
+ pause: function() { |
+ if (this.player) { |
+ this.player.pause(); |
+ } |
+ }, |
+ |
+ /** |
+ * @method hasTarget |
+ * @return boolean True if `target` is defined. |
+ */ |
+ hasTarget: function() { |
+ return this.target !== null; |
+ }, |
+ |
+ /** |
+ * Creates a web animations object based on this object's properties, and |
+ * plays it if autoplay is true. |
+ * |
+ * @method apply |
+ * @return Object A web animation. |
+ */ |
+ apply: function() { |
+ this.animation = this.makeAnimation(); |
+ if (this.autoplay && this.animation) { |
+ this.play(); |
+ } |
+ return this.animation; |
+ }, |
+ |
+ makeSingleAnimation: function(target) { |
+ // XXX(yvonne): for selecting all the animated elements. |
+ target.classList.add('core-animation-target'); |
+ return new Animation(target, this.animationEffect, this.timingProps); |
+ }, |
+ |
+ makeAnimation: function() { |
+ if (!this.target) { |
+ return null; |
+ } |
+ var animation; |
+ if (Array.isArray(this.target)) { |
+ var array = []; |
+ this.target.forEach(function(t) { |
+ array.push(this.makeSingleAnimation(t)); |
+ }.bind(this)); |
+ animation = new AnimationGroup(array); |
+ } else { |
+ animation = this.makeSingleAnimation(this.target); |
+ } |
+ return animation; |
+ }, |
+ |
+ animationChanged: function() { |
+ // Sending 'this' with the event so you can always get the animation object |
+ // that fired the event, due to event retargetting in shadow DOM. |
+ this.fire('core-animation-change', this); |
+ }, |
+ |
+ targetChanged: function(old) { |
+ if (old) { |
+ old.classList.remove('core-animation-target'); |
+ } |
+ }, |
+ |
+ get timingProps() { |
+ var props = {}; |
+ var timing = { |
+ delay: {isNumber: true}, |
+ endDelay: {isNumber: true}, |
+ fill: {}, |
+ iterationStart: {isNumber: true}, |
+ iterations: {isNumber: true, allowInfinity: true}, |
+ duration: {isNumber: true}, |
+ playbackRate: {isNumber: true}, |
+ direction: {}, |
+ easing: {} |
+ }; |
+ for (t in timing) { |
+ if (this[t] !== null) { |
+ var name = timing[t].property || t; |
+ props[name] = timing[t].isNumber && this[t] !== 'auto' ? |
+ toNumber(this[t], timing[t].allowInfinity) : this[t]; |
+ } |
+ } |
+ return props; |
+ }, |
+ |
+ get animationEffect() { |
+ var props = {}; |
+ var frames = []; |
+ var effect; |
+ if (this.keyframes) { |
+ frames = this.keyframes; |
+ } else if (!this.customEffect) { |
+ var children = this.querySelectorAll('core-animation-keyframe'); |
+ if (children.length === 0 && this.shadowRoot) { |
+ children = this.shadowRoot.querySelectorAll('core-animation-keyframe'); |
+ } |
+ Array.prototype.forEach.call(children, function(c) { |
+ frames.push(c.properties); |
+ }); |
+ } |
+ if (this.customEffect) { |
+ effect = this.customEffect; |
+ } else { |
+ // effect = new KeyframeEffect(frames, this.composite); |
+ effect = frames; |
+ } |
+ return effect; |
+ }, |
+ |
+ animationFinishHandler: function() { |
+ this.fire('core-animation-finish'); |
+ } |
+ |
+ }); |
+ })(); |
+ </script> |
+</polymer-element> |
+ |
+<!-- |
+`core-animation-keyframe` represents a keyframe in a `core-animation`. Use them as children of |
+`core-animation` elements to create web animations declaratively. If the `offset` property is |
+unset, the keyframes will be distributed evenly within the animation duration. Use |
+`core-animation-prop` elements as children of this element to specify the CSS properties for |
+the animation. |
+ |
+@element core-animation-keyframe |
+@status beta |
+@homepage github.io |
+--> |
+<polymer-element name="core-animation-keyframe" attributes="offset"> |
+ <script> |
+ Polymer({ |
+ publish: { |
+ /** |
+ * An offset from 0 to 1. |
+ * |
+ * @property offset |
+ * @type Number |
+ */ |
+ offset: {value: null, reflect: true} |
+ }, |
+ get properties() { |
+ var props = {}; |
+ var children = this.querySelectorAll('core-animation-prop'); |
+ Array.prototype.forEach.call(children, function(c) { |
+ props[c.name] = c.value; |
+ }); |
+ if (this.offset !== null) { |
+ props.offset = this.offset; |
+ } |
+ return props; |
+ } |
+ }); |
+ </script> |
+</polymer-element> |
+ |
+<!-- |
+`core-animation-prop` represents a CSS property and value pair to use with |
+`core-animation-keyframe`. |
+ |
+@element core-animation-prop |
+@status beta |
+@homepage github.io |
+--> |
+<polymer-element name="core-animation-prop" attributes="name value"> |
+ <script> |
+ Polymer({ |
+ publish: { |
+ /** |
+ * A CSS property name. |
+ * |
+ * @property name |
+ * @type string |
+ */ |
+ name: {value: '', reflect: true}, |
+ |
+ /** |
+ * The value for the CSS property. |
+ * |
+ * @property value |
+ * @type string|number |
+ */ |
+ value: {value: '', reflect: true} |
+ } |
+ }); |
+ </script> |
+</polymer-element> |