UNPKG

five-bells-visualization

Version:
325 lines (272 loc) 9.88 kB
<!-- 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-transition-pages.html" rel="import"> <core-style id="hero-transition"> /* Hide heroes that are not currently transitioning */ polyfill-next-selector { content: ':host > [animate]:not(.core-selected) [hero]'; } ::content > [animate]:not(.core-selected) /deep/ [hero] { opacity: 0; } polyfill-next-selector { content: ':host > .core-selected[animate] [hero]'; } ::content > .core-selected[animate] /deep/ [hero] { opacity: 1; z-index: 10000; } polyfill-next-selector { content: ':host > * [hero-p]'; } ::content > * /deep/ [hero-p] { -webkit-transition: box-shadow 100ms ease-out; transition: box-shadow 100ms ease-out; } polyfill-next-selector { content: ':host > [animate] [hero-p]'; } ::content > [animate] /deep/ [hero-p] { box-shadow: none !important; } </core-style> <!-- `hero-transition` transforms two elements in different pages such that they appear to be shared across the pages. Example: <core-animated-pages transition="hero-transition"> <section layout horizontal> <div id="div1" flex></div> <div id="div2" flex hero-id="shared" hero></div> </section> <section> <section layout horizontal> <div id="div3" flex hero-id="shared" hero></div> <div id="div4" flex></div> </section> </section> </core-animated-pages> In the above example, the elements `#div2` and `#div3` shares the same `hero-id` attribute and a single element appears to translate and scale smoothly between the two positions during a page transition. Both elements from the source and destination pages must share the same `hero-id` and must both contain the `hero` attribute to trigger the transition. The separate `hero` attribute allows you to use binding to configure the transition: Example: <core-animated-pages transition="hero-transition"> <section layout horizontal> <div id="div1" flex hero-id="shared" hero?="{{selected == 0}}"></div> <div id="div2" flex hero-id="shared" hero?="{{selected == 1}}"></div> </section> <section> <section layout horizontal> <div id="div3" flex hero-id="shared" hero></div> </section> </section> </core-animated-pages> In the above example, either `#div1` or `#div2` scales to `#div3` during a page transition, depending on the value of `selected`. Because it is common to share elements with different `border-radius` values, by default this transition will also animate the `border-radius` property. You can configure the duration of the hero transition with the global variable `CoreStyle.g.transitions.heroDuration`. @class hero-transition @extends core-transition-pages @status beta @homepage github.io --> <polymer-element name="hero-transition" extends="core-transition-pages"> <script> (function() { var webkitStyles = '-webkit-transition' in document.documentElement.style var TRANSITION_CSSNAME = webkitStyles ? '-webkit-transition' : 'transition'; var TRANSFORM_CSSNAME = webkitStyles ? '-webkit-transform' : 'transform'; var TRANSITION_NAME = webkitStyles ? 'webkitTransition' : 'transition'; var TRANSFORM_NAME = webkitStyles ? 'webkitTransform' : 'transform'; var hasShadowDOMPolyfill = window.ShadowDOMPolyfill; Polymer({ go: function(scope, options) { var props = [ 'border-radius', 'width', 'height', TRANSFORM_CSSNAME ]; var duration = options && options.duration || (CoreStyle.g.transitions.heroDuration || CoreStyle.g.transitions.duration); scope._heroes.forEach(function(h) { var d = h.h0.hasAttribute('hero-delayed') ? CoreStyle.g.transitions.heroDelay : ''; var wt = []; props.forEach(function(p) { wt.push(p + ' ' + duration + ' ' + options.easing + ' ' + d); }); h.h1.style[TRANSITION_NAME] = wt.join(', '); h.h1.style.borderRadius = h.r1; h.h1.style[TRANSFORM_NAME] = ''; }); this.super(arguments); if (!scope._heroes.length) { this.completed = true; } }, prepare: function(scope, options) { this.super(arguments); var src = options.src, dst = options.dst; if (scope._heroes && scope._heroes.length) { this.ensureComplete(scope); } else { scope._heroes = []; } // FIXME(yvonne): basic support for nested pages. // Look for heroes in the light DOM and one level of shadow DOM of the src and dst, // and also in src.selectedItem or dst.selectedItem, then transform the dst hero to src var ss = '[hero]'; var h$ = this.findAllInShadows(src, ss); if (src.selectedItem) { hs$ = this.findAllInShadows(src.selectedItem, ss); hsa$ = []; // De-duplicate items Array.prototype.forEach.call(hs$, function(hs) { if (h$.indexOf(hs) === -1) { hsa$.push(hs); } }) h$ = h$.concat(hsa$); } for (var i=0, h0; h0=h$[i]; i++) { var v = h0.getAttribute('hero-id'); var ds = '[hero][hero-id="' + v + '"]'; var h1 = this.findInShadows(dst, ds); if (!h1 && dst.selectedItem) { h1 = this.findInShadows(dst.selectedItem, ds); } // console.log('src', src); // console.log('dst', dst, dst.selectedItem); // console.log(v, h0, h1); if (v && h1) { var c0 = getComputedStyle(h0); var c1 = getComputedStyle(h1); var h = { h0: h0, b0: h0.getBoundingClientRect(), r0: c0.borderRadius, h1: h1, b1: h1.getBoundingClientRect(), r1: c1.borderRadius }; var dl = h.b0.left - h.b1.left; var dt = h.b0.top - h.b1.top; var sw = h.b0.width / h.b1.width; var sh = h.b0.height / h.b1.height; // h.scaley = h.h0.hasAttribute('scaley'); // if (!h.scaley && (sw !== 1 || sh !== 1)) { // sw = sh = 1; // h.h1.style.width = h.b0.width + 'px'; // h.h1.style.height = h.b0.height + 'px'; // } // Also animate the border-radius for the circle-to-square transition if (h.r0 !== h.r1) { h.h1.style.borderRadius = h.r0; } // console.log(h); h.h1.style[TRANSFORM_NAME] = 'translate(' + dl + 'px,' + dt + 'px)' + ' scale(' + sw + ',' + sh + ')'; h.h1.style[TRANSFORM_NAME + 'Origin'] = '0 0'; scope._heroes.push(h); } } }, // carefully look into ::shadow with polyfill specific hack findInShadows: function(node, selector) { return node.querySelector(selector) || (hasShadowDOMPolyfill ? queryAllShadows(node, selector) : node.querySelector('::shadow ' + selector)); }, findAllInShadows: function(node, selector) { if (hasShadowDOMPolyfill) { var nodes = node.querySelectorAll(selector).array(); var shadowNodes = queryAllShadows(node, selector, true); return nodes.concat(shadowNodes); } else { return node.querySelectorAll(selector).array().concat(node.shadowRoot ? node.shadowRoot.querySelectorAll(selector).array() : []); } }, ensureComplete: function(scope) { this.super(arguments); if (scope._heroes) { scope._heroes.forEach(function(h) { h.h1.style[TRANSITION_NAME] = ''; h.h1.style[TRANSFORM_NAME] = ''; }); scope._heroes = []; } }, complete: function(scope, e) { // if (e.propertyName === TRANSFORM_CSSNAME) { var done = false; scope._heroes.forEach(function(h) { if (h.h1 === e.path[0]) { done = true; } }); if (done) { this.super(arguments); } // } } }); // utility method for searching through shadowRoots. function queryShadow(node, selector) { var m, el = node.firstElementChild; var shadows, sr, i; shadows = []; sr = node.shadowRoot; while(sr) { shadows.push(sr); sr = sr.olderShadowRoot; } for(i = shadows.length - 1; i >= 0; i--) { m = shadows[i].querySelector(selector); if (m) { return m; } } while(el) { m = queryShadow(el, selector); if (m) { return m; } el = el.nextElementSibling; } return null; } function _queryAllShadows(node, selector, results) { var el = node.firstElementChild; var temp, sr, shadows, i, j; shadows = []; sr = node.shadowRoot; while(sr) { shadows.push(sr); sr = sr.olderShadowRoot; } for (i = shadows.length - 1; i >= 0; i--) { temp = shadows[i].querySelectorAll(selector); for(j = 0; j < temp.length; j++) { results.push(temp[j]); } } while (el) { _queryAllShadows(el, selector, results); el = el.nextElementSibling; } return results; } queryAllShadows = function(node, selector, all) { if (all) { return _queryAllShadows(node, selector, []); } else { return queryShadow(node, selector); } }; })(); </script> </polymer-element> <hero-transition id="hero-transition"></hero-transition>