UNPKG

five-bells-visualization

Version:
460 lines (390 loc) 13.5 kB
<!-- @license 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 href="../core-selector/core-selector.html" rel="import"> <link href="../core-resizable/core-resizable.html" rel="import"> <link href="transitions/hero-transition.html" rel="import"> <link href="transitions/cross-fade.html" rel="import"> <!-- `core-animated-pages` selects one of its children "pages" to show and runs a transition when switching between them. The transitions are designed to be pluggable, and can accept any object that is an instance of a `core-transition-pages`. Transitions to run are specified in the `transitions` attribute as a space-delimited string of `id`s of transition elements. Several transitions are available with `core-animated-pages` by default, including `hero-transition`, `cross-fade`, and `tile-cascade`. Example: <style> #hero1 { position: absolute; top: 0; left: 0; width: 300px; height: 300px; background-color: orange; } #hero2 { position: absolute; top: 200px; left: 300px; width: 300px; height: 300px; background-color: orange; } #bottom1, #bottom2 { position: absolute; bottom: 0; top: 0; left: 0; height: 50px; } #bottom1 { background-color: blue; } #bottom2 { background-color: green; } </style> // hero-transition and cross-fade are declared elsewhere <core-animated-pages transitions="hero-transition cross-fade"> <section id="page1"> <div id="hero1" hero-id="hero" hero></div> <div id="bottom1" cross-fade></div> </section> <section id="page2"> <div id="hero2" hero-id="hero" hero></div> <div id="bottom2" cross-fade></div> </section> </core-animated-pages> In the above example, two transitions (`hero-transition` and `cross-fade`) are run when switching between `page1` and `page2`. `hero-transition` transforms elements with the same `hero-id` such that they appear to be shared across different pages. `cross-fade` fades out the elements marked `cross-fade` in the outgoing page, and fades in those in the incoming page. See the individual transition's documentation for specific details. Finding elements to transition ------------------------------ In general, a transition is applied to elements marked with a certain attribute. For example, `hero-transition` applies the transition on elements with the `hero` and `hero-id` attribute. Among the transitions included with `core-animated-pages`, script-based transitions such as `hero-transition` generally look for elements up to one level of shadowRoot from the `core-animated-pages` element, and CSS-based transitions such as `cross-fade` look for elements within any shadowRoot within the `core-animated-pages` element. This means you can use custom elements as pages and mark elements in their shadowRoots as heroes, or mark elements in deeper shadowRoots with other transitions. Example: <polymer-element name="x-el" noscript> <template> <style> #hero { position: absolute; top: 0; right: 0; width: 50px; height: 300px; background-color: blue; } </style> <div id="hero" hero-id="bar" hero></div> </template> </polymer-element> <polymer-element name="x-page-1" noscript> <template> <style> #hero1 { position: absolute; top: 0; left: 0; width: 300px; height: 300px; background-color: orange; } </style> <div id="hero1" hero-id="foo" hero></div> <div id="hero2" hero-id="bar" hero></div> </template> </polymer-element> <polymer-element name="x-page-2" noscript> <template> <style> #hero1 { position: absolute; top: 200px; left: 300px; width: 300px; height: 300px; background-color: orange; } #hero2 { background-color: blue; height: 150px; width: 400px; } </style> // The below element is one level of shadow from the core-animated-pages and will // be transitioned. <div id="hero1" hero-id="foo" hero></div> // The below element contains a hero inside its shadowRoot making it two levels away // from the core-animated-pages, and will not be transitioned. <x-el></x-el> </template> </polymer-element> <core-animated-pages transitions="hero-transition"> <x-page-1></x-page-1> <x-page-2></x-page-2> </core-animated-pages> Note that the container element of the page does not participate in the transition. // This does not work <core-animated-pages transitions="cross-fade"> <section cross-fade></section> <section cross-fade></section> </core-animated-pages> // This works <core-animated-pages transitions="cross-fade"> <section> <div cross-fade></div> </section> <section> <div cross-fade></div> </section> </core-animated-pages> Dynamically setting up transitions ---------------------------------- An easy way to set up transitions dynamically is to use property binding on the transition attributes. Example: <core-animated-pages selected="{{selected}}"> <section id="page1"> <div hero-id="hero" hero></div> </section> <section id="page2"> <div id="foo" hero-id="hero" hero?="{{selected === 1 || selected === 0}}" cross-fade="{{selected === 2}}"></div> </section> <section id="page3"> </section> </core-animated-pages> In the above example, the "foo" element only behaves as a hero element if transitioning between `#page1` and `#page2`. It gets cross-faded when transition to or from `#page3`. Nesting pages ------------- It is possible to nest core-animated-pages elements for organization. Excessive nesting is not encouraged, however, since it makes setting up the transition more complex. To nest core-animated-pages, the page containing the nested core-animated-pages element should have a `selectedItem` property bound to the `selectedItem` property of the nested element. This will allow the outer core-animated-pages to know which nested page it is actually transitioning to. Example: <polymer-element name="nested-page" attributes="selectedItem"> <template> <core-animated-pages selectedItem="{{selectedItem}}"> ... </core-animated-pages> </template> </polymer-element> <core-animated-pages> <section id="page1"></section> <nested-page id="page2"></nested-page> </core-animated-pages> @element core-animated-pages @extends core-selector @mixins Polymer.CoreResizer https://github.com/polymer/core-resizable @status beta @homepage github.io --> <!-- Fired before a page transition occurs. Both pages involved in the transition are visible when this event fires. This is useful if there is something the client needs to do when a page becomes visible. @event core-animated-pages-transition-prepare --> <!-- Fired when a page transition completes. @event core-animated-pages-transition-end --> <polymer-element name="core-animated-pages" extends="core-selector" notap attributes="transitions"> <template> <link href="core-animated-pages.css" rel="stylesheet"> <shadow></shadow> </template> <script> Polymer(Polymer.mixin({ eventDelegates: { 'core-transitionend': 'transitionEnd' }, /** * A space-delimited string of transitions to use when switching between pages in this element. * The strings are `id`s of `core-transition-pages` elements included elsewhere. See the * individual transition's document for specific details. * * @attribute transitions * @type string * @default '' */ transitions: '', selected: 0, /** * The last page selected. This property is useful to dynamically set transitions based * on incoming and outgoing pages. * * @attribute lastSelected * @type Object * @default null */ lastSelected: null, registerCallback: function() { this.tmeta = document.createElement('core-transition'); }, created: function() { this._transitions = []; this.transitioning = []; }, attached: function() { this.resizerAttachedHandler(); }, detached: function() { this.resizerDetachedHandler(); }, transitionsChanged: function() { this._transitions = this.transitions.split(' '); }, _transitionsChanged: function(old) { if (this._transitionElements) { this._transitionElements.forEach(function(t) { t.teardown(this); }, this); } this._transitionElements = []; this._transitions.forEach(function(transitionId) { var t = this.getTransition(transitionId); if (t) { this._transitionElements.push(t); t.setup(this); } }, this); }, getTransition: function(transitionId) { return this.tmeta.byId(transitionId); }, selectionSelect: function(e, detail) { this.updateSelectedItem(); // Wait to call applySelection when we run the transition }, applyTransition: function(src, dst) { if (this.animating) { this.cancelAsync(this.animating); this.animating = null; } Polymer.flush(); if (this.transitioning.indexOf(src) === -1) { this.transitioning.push(src); } if (this.transitioning.indexOf(dst) === -1) { this.transitioning.push(dst); } // force src, dst to display src.setAttribute('animate', ''); dst.setAttribute('animate', ''); // var options = { src: src, dst: dst, easing: 'cubic-bezier(0.4, 0, 0.2, 1)' }; // fire an event so clients have a chance to do something when the // new page becomes visible but before it draws. this.fire('core-animated-pages-transition-prepare'); // // prepare transition this._transitionElements.forEach(function(transition) { transition.prepare(this, options); }, this); // // force layout! src.offsetTop; // // apply selection this.applySelection(dst, true); this.applySelection(src, false); // // start transition this._transitionElements.forEach(function(transition) { transition.go(this, options); }, this); if (!this._transitionElements.length) { this.complete(); } else { this.animating = this.async(this.complete.bind(this), null, 5000); } }, complete: function() { if (this.animating) { this.cancelAsync(this.animating); this.animating = null; } this.transitioning.forEach(function(t) { t.removeAttribute('animate'); }); this.transitioning = []; this._transitionElements.forEach(function(transition) { transition.ensureComplete(this); }, this); this.fire('core-animated-pages-transition-end'); }, transitionEnd: function(e) { if (this.transitioning.length) { var completed = true; this._transitionElements.forEach(function(transition) { if (!transition.completed) { completed = false; } }); if (completed) { this.job('transitionWatch', function() { this.complete(); }, 100); } } }, selectedChanged: function(old) { this.lastSelected = old; this.super(arguments); }, selectedItemChanged: function(oldItem) { this.super(arguments); if (!oldItem) { this.applySelection(this.selectedItem, true); this.async(this.notifyResize); return; } if (this.hasAttribute('no-transition') || !this._transitionElements || !this._transitionElements.length) { this.applySelection(oldItem, false); this.applySelection(this.selectedItem, true); this.notifyResize(); return; } if (oldItem && this.selectedItem) { // TODO(sorvell): allow bindings to update first? var self = this; Polymer.flush(); Polymer.endOfMicrotask(function() { self.applyTransition(oldItem, self.selectedItem); self.notifyResize(); }); } }, resizerShouldNotify: function(el) { // Only notify descendents of selected item while (el && (el != this)) { if (el == this.selectedItem) { return true; } el = el.parentElement || (el.parentNode && el.parentNode.host); } } }, Polymer.CoreResizer)); </script> </polymer-element>