OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
8 --> | |
9 | |
10 <link href="core-transition-pages.html" rel="import"> | |
11 | |
12 <core-style id="hero-transition"> | |
13 /* Hide heroes that are not currently transitioning */ | |
14 polyfill-next-selector { content: ':host > [animate]:not(.core-selected) [hero
]'; } | |
15 ::content > [animate]:not(.core-selected) /deep/ [hero] { | |
16 opacity: 0; | |
17 } | |
18 | |
19 polyfill-next-selector { content: ':host > .core-selected[animate] [hero]'; } | |
20 ::content > .core-selected[animate] /deep/ [hero] { | |
21 opacity: 1; | |
22 z-index: 10000; | |
23 } | |
24 | |
25 polyfill-next-selector { content: ':host > * [hero-p]'; } | |
26 ::content > * /deep/ [hero-p] { | |
27 -webkit-transition: box-shadow 100ms ease-out; | |
28 transition: box-shadow 100ms ease-out; | |
29 } | |
30 | |
31 polyfill-next-selector { content: ':host > [animate] [hero-p]'; } | |
32 ::content > [animate] /deep/ [hero-p] { | |
33 box-shadow: none !important; | |
34 } | |
35 </core-style> | |
36 | |
37 | |
38 <!-- | |
39 | |
40 `hero-transition` transforms two elements in different pages such that they appe
ar | |
41 to be shared across the pages. | |
42 | |
43 Example: | |
44 | |
45 <core-animated-pages transition="hero-transition"> | |
46 <section layout horizontal> | |
47 <div id="div1" flex></div> | |
48 <div id="div2" flex hero-id="shared" hero></div> | |
49 </section> | |
50 <section> | |
51 <section layout horizontal> | |
52 <div id="div3" flex hero-id="shared" hero></div> | |
53 <div id="div4" flex></div> | |
54 </section> | |
55 </section> | |
56 </core-animated-pages> | |
57 | |
58 In the above example, the elements `#div2` and `#div3` shares the same `hero-id` | |
59 attribute and a single element appears to translate and scale smoothly between | |
60 the two positions during a page transition. | |
61 | |
62 Both elements from the source and destination pages must share the same `hero-id
` | |
63 and must both contain the `hero` attribute to trigger the transition. The separa
te | |
64 `hero` attribute allows you to use binding to configure the transition: | |
65 | |
66 Example: | |
67 | |
68 <core-animated-pages transition="hero-transition"> | |
69 <section layout horizontal> | |
70 <div id="div1" flex hero-id="shared" hero?="{{selected == 0}}"></div> | |
71 <div id="div2" flex hero-id="shared" hero?="{{selected == 1}}"></div> | |
72 </section> | |
73 <section> | |
74 <section layout horizontal> | |
75 <div id="div3" flex hero-id="shared" hero></div> | |
76 </section> | |
77 </section> | |
78 </core-animated-pages> | |
79 | |
80 In the above example, either `#div1` or `#div2` scales to `#div3` during a page
transition, | |
81 depending on the value of `selected`. | |
82 | |
83 Because it is common to share elements with different `border-radius` values, by
default | |
84 this transition will also animate the `border-radius` property. | |
85 | |
86 You can configure the duration of the hero transition with the global variable | |
87 `CoreStyle.g.transitions.heroDuration`. | |
88 | |
89 @class hero-transition | |
90 @extends core-transition-pages | |
91 @status beta | |
92 @homepage github.io | |
93 --> | |
94 <polymer-element name="hero-transition" extends="core-transition-pages"> | |
95 <script> | |
96 (function() { | |
97 | |
98 var webkitStyles = '-webkit-transition' in document.documentElement.style | |
99 var TRANSITION_CSSNAME = webkitStyles ? '-webkit-transition' : 'transition'; | |
100 var TRANSFORM_CSSNAME = webkitStyles ? '-webkit-transform' : 'transform'; | |
101 var TRANSITION_NAME = webkitStyles ? 'webkitTransition' : 'transition'; | |
102 var TRANSFORM_NAME = webkitStyles ? 'webkitTransform' : 'transform'; | |
103 | |
104 var hasShadowDOMPolyfill = window.ShadowDOMPolyfill; | |
105 | |
106 Polymer({ | |
107 | |
108 go: function(scope, options) { | |
109 var props = [ | |
110 'border-radius', | |
111 'width', | |
112 'height', | |
113 TRANSFORM_CSSNAME | |
114 ]; | |
115 | |
116 var duration = options && options.duration || | |
117 (CoreStyle.g.transitions.heroDuration || | |
118 CoreStyle.g.transitions.duration); | |
119 | |
120 scope._heroes.forEach(function(h) { | |
121 var d = h.h0.hasAttribute('hero-delayed') ? CoreStyle.g.transitions.hero
Delay : ''; | |
122 var wt = []; | |
123 props.forEach(function(p) { | |
124 wt.push(p + ' ' + duration + ' ' + options.easing + ' ' + d); | |
125 }); | |
126 | |
127 h.h1.style[TRANSITION_NAME] = wt.join(', '); | |
128 h.h1.style.borderRadius = h.r1; | |
129 h.h1.style[TRANSFORM_NAME] = ''; | |
130 }); | |
131 | |
132 this.super(arguments); | |
133 | |
134 if (!scope._heroes.length) { | |
135 this.completed = true; | |
136 } | |
137 }, | |
138 | |
139 prepare: function(scope, options) { | |
140 this.super(arguments); | |
141 var src = options.src, dst = options.dst; | |
142 | |
143 if (scope._heroes && scope._heroes.length) { | |
144 this.ensureComplete(scope); | |
145 } else { | |
146 scope._heroes = []; | |
147 } | |
148 | |
149 // FIXME(yvonne): basic support for nested pages. | |
150 // Look for heroes in the light DOM and one level of shadow DOM of the src
and dst, | |
151 // and also in src.selectedItem or dst.selectedItem, then transform the ds
t hero to src | |
152 var ss = '[hero]'; | |
153 var h$ = this.findAllInShadows(src, ss); | |
154 if (src.selectedItem) { | |
155 hs$ = this.findAllInShadows(src.selectedItem, ss); | |
156 hsa$ = []; | |
157 // De-duplicate items | |
158 Array.prototype.forEach.call(hs$, function(hs) { | |
159 if (h$.indexOf(hs) === -1) { | |
160 hsa$.push(hs); | |
161 } | |
162 }) | |
163 h$ = h$.concat(hsa$); | |
164 } | |
165 | |
166 for (var i=0, h0; h0=h$[i]; i++) { | |
167 var v = h0.getAttribute('hero-id'); | |
168 var ds = '[hero][hero-id="' + v + '"]'; | |
169 var h1 = this.findInShadows(dst, ds); | |
170 | |
171 if (!h1 && dst.selectedItem) { | |
172 h1 = this.findInShadows(dst.selectedItem, ds); | |
173 } | |
174 | |
175 // console.log('src', src); | |
176 // console.log('dst', dst, dst.selectedItem); | |
177 // console.log(v, h0, h1); | |
178 if (v && h1) { | |
179 var c0 = getComputedStyle(h0); | |
180 var c1 = getComputedStyle(h1); | |
181 var h = { | |
182 h0: h0, | |
183 b0: h0.getBoundingClientRect(), | |
184 r0: c0.borderRadius, | |
185 h1: h1, | |
186 b1: h1.getBoundingClientRect(), | |
187 r1: c1.borderRadius | |
188 }; | |
189 | |
190 var dl = h.b0.left - h.b1.left; | |
191 var dt = h.b0.top - h.b1.top; | |
192 var sw = h.b0.width / h.b1.width; | |
193 var sh = h.b0.height / h.b1.height; | |
194 | |
195 // h.scaley = h.h0.hasAttribute('scaley'); | |
196 // if (!h.scaley && (sw !== 1 || sh !== 1)) { | |
197 // sw = sh = 1; | |
198 // h.h1.style.width = h.b0.width + 'px'; | |
199 // h.h1.style.height = h.b0.height + 'px'; | |
200 // } | |
201 | |
202 // Also animate the border-radius for the circle-to-square transition | |
203 if (h.r0 !== h.r1) { | |
204 h.h1.style.borderRadius = h.r0; | |
205 } | |
206 | |
207 // console.log(h); | |
208 | |
209 h.h1.style[TRANSFORM_NAME] = 'translate(' + dl + 'px,' + dt + 'px)' +
' scale(' + sw + ',' + sh + ')'; | |
210 h.h1.style[TRANSFORM_NAME + 'Origin'] = '0 0'; | |
211 | |
212 scope._heroes.push(h); | |
213 } | |
214 } | |
215 | |
216 }, | |
217 | |
218 // carefully look into ::shadow with polyfill specific hack | |
219 findInShadows: function(node, selector) { | |
220 return node.querySelector(selector) || (hasShadowDOMPolyfill ? | |
221 Platform.queryAllShadows(node, selector) : | |
222 node.querySelector('::shadow ' + selector)); | |
223 }, | |
224 | |
225 findAllInShadows: function(node, selector) { | |
226 if (hasShadowDOMPolyfill) { | |
227 var nodes = node.querySelectorAll(selector).array(); | |
228 var shadowNodes = Platform.queryAllShadows(node, selector, true); | |
229 return nodes.concat(shadowNodes); | |
230 } else { | |
231 return node.querySelectorAll(selector).array().concat(node.shadowRoot ?
node.shadowRoot.querySelectorAll(selector).array() : []); | |
232 } | |
233 }, | |
234 | |
235 ensureComplete: function(scope) { | |
236 this.super(arguments); | |
237 if (scope._heroes) { | |
238 scope._heroes.forEach(function(h) { | |
239 h.h1.style[TRANSITION_NAME] = ''; | |
240 h.h1.style[TRANSFORM_NAME] = ''; | |
241 }); | |
242 scope._heroes = []; | |
243 } | |
244 }, | |
245 | |
246 complete: function(scope, e) { | |
247 // if (e.propertyName === TRANSFORM_CSSNAME) { | |
248 var done = false; | |
249 scope._heroes.forEach(function(h) { | |
250 if (h.h1 === e.path[0]) { | |
251 done = true; | |
252 } | |
253 }); | |
254 | |
255 if (done) { | |
256 this.super(arguments); | |
257 } | |
258 // } | |
259 } | |
260 | |
261 }); | |
262 | |
263 })(); | |
264 </script> | |
265 </polymer-element> | |
266 | |
267 <hero-transition id="hero-transition"></hero-transition> | |
OLD | NEW |