OLD | NEW |
1 <!-- | 1 <!-- |
2 // Copyright 2014 The Chromium Authors. All rights reserved. | 2 // Copyright 2014 The Chromium Authors. All rights reserved. |
3 // Use of this source code is governed by a BSD-style license that can be | 3 // Use of this source code is governed by a BSD-style license that can be |
4 // found in the LICENSE file. | 4 // found in the LICENSE file. |
5 --> | 5 --> |
6 <import src="../../framework/sky-element/sky-element.sky" as="SkyElement" /> | 6 <import src="../../framework/sky-element/sky-element.sky" as="SkyElement" /> |
7 <import src="city-data-service.sky" as="CityDataService" /> | 7 <import src="city-data-service.sky" as="CityDataService" /> |
8 <import src="city-sequence.sky" as="CitySequence" /> | 8 <import src="city-sequence.sky" as="CitySequence" /> |
9 | 9 |
10 <sky-element name="state-header"> | 10 <sky-element name="state-header"> |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 overflow: hidden; | 113 overflow: hidden; |
114 position: absolute; | 114 position: absolute; |
115 top: 0; | 115 top: 0; |
116 right: 0; | 116 right: 0; |
117 bottom: 0; | 117 bottom: 0; |
118 left: 0; | 118 left: 0; |
119 display: block; | 119 display: block; |
120 background-color: #fff; | 120 background-color: #fff; |
121 } | 121 } |
122 | 122 |
123 #scroller { | 123 #contentarea { |
124 overflow-x: hidden; | |
125 overflow-y: auto; | |
126 perspective: 5px; | |
127 position: absolute; | |
128 left: 0; | |
129 right: 0; | |
130 top: 0; | |
131 bottom: 0; | |
132 } | |
133 | |
134 #scroller::-webkit-scrollbar { | |
135 display:none; | |
136 } | |
137 | |
138 #scrollarea { | |
139 will-change: transform; | 124 will-change: transform; |
140 transform-style: preserve-3d; | |
141 } | |
142 | |
143 #contentarea { | |
144 position: absolute; | |
145 will-change: contents; | |
146 width: 100%; | |
147 } | |
148 | |
149 .void { | |
150 display: none; | |
151 } | 125 } |
152 | 126 |
153 .position { | 127 .position { |
154 position: absolute; | 128 position: absolute; |
155 left: 0; | 129 left: 0; |
156 right: 0; | 130 right: 0; |
157 } | 131 } |
158 | 132 |
159 </style> | 133 </style> |
160 <div id="scroller"> | 134 <div id="contentarea"> |
161 <div id="scrollarea"> | |
162 <div id="contentarea"> | |
163 </div> | |
164 </div> | 135 </div> |
165 </div> | |
166 </template> | 136 </template> |
167 <script> | 137 <script> |
168 | 138 |
169 (function(global) { | 139 (function(global) { |
170 "use strict"; | 140 "use strict"; |
171 | 141 |
172 var LOAD_LENGTH = 20; | 142 var LOAD_LENGTH = 20; |
173 var LOAD_BUFFER_PRE = LOAD_LENGTH * 4; | 143 var LOAD_BUFFER_PRE = LOAD_LENGTH * 4; |
174 var LOAD_BUFFER_POST = LOAD_LENGTH * 4; | 144 var LOAD_BUFFER_POST = LOAD_LENGTH * 4; |
175 | 145 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 }).catch(function(ex) { | 240 }).catch(function(ex) { |
271 console.log(ex.stack); | 241 console.log(ex.stack); |
272 }); | 242 }); |
273 } catch (ex) { | 243 } catch (ex) { |
274 console.log(ex.stack); | 244 console.log(ex.stack); |
275 } | 245 } |
276 } | 246 } |
277 | 247 |
278 function Scroller() { | 248 function Scroller() { |
279 this.contentarea = null; | 249 this.contentarea = null; |
280 this.scroller = null; | 250 this.scrollTop = 0; |
281 this.contentTop = 0; // #contentarea's current top | 251 this.scrollHeight = -1; |
282 this.scrollTop = 0; // #scrollarea's current top | |
283 this.scrollHeight = -1; // height of #scroller (the viewport) | |
284 this.lastScrollTop = 0; // last known scrollTop to compute deltas | |
285 } | 252 } |
286 | 253 |
287 Scroller.prototype.setup = function(scroller, scrollarea, contentarea) { | 254 Scroller.prototype.setup = function(scrollHeight, contentarea) { |
| 255 this.scrollHeight = scrollHeight; |
288 this.contentarea = contentarea; | 256 this.contentarea = contentarea; |
289 this.scroller = scroller; | |
290 | |
291 this.scrollHeight = scroller.offsetHeight; | |
292 scrollarea.style.height = (this.scrollHeight) * 4 + 'px'; | |
293 | |
294 this.reset(); | |
295 } | 257 } |
296 | 258 |
297 Scroller.prototype.captureNewFrame = function(event) { | 259 Scroller.prototype.scrollBy = function(amount) { |
298 var scrollTop = event.target.scrollTop; | 260 this.scrollTop += amount; |
299 | 261 this.scrollTo(); |
300 // Protect from re-entry. | |
301 if (this.lastScrollTop == scrollTop) | |
302 return false; | |
303 | |
304 var scrollDown = scrollTop > this.lastScrollTop; | |
305 if (scrollDown) { | |
306 while (scrollTop > this.scrollHeight * 1.5) { | |
307 scrollTop -= this.scrollHeight; | |
308 this.contentTop -= this.scrollHeight; | |
309 } | |
310 } else { | |
311 while(scrollTop < this.scrollHeight * 1.5) { | |
312 scrollTop += this.scrollHeight; | |
313 this.contentTop += this.scrollHeight; | |
314 } | |
315 } | |
316 | |
317 this.lastScrollTop = scrollTop; | |
318 event.target.scrollTop = scrollTop; | |
319 this.contentarea.style.top = this.contentTop + 'px'; | |
320 | |
321 this.scrollTop = scrollTop - this.contentTop; | |
322 | |
323 return true; | |
324 } | 262 } |
325 | 263 |
326 Scroller.prototype.reset = function() { | 264 Scroller.prototype.scrollTo = function() { |
327 if (!this.contentarea) | 265 var transform = 'translateY(' + -this.scrollTop.toFixed(2) + 'px)'; |
328 return; | 266 this.contentarea.style.transform = transform; |
329 | |
330 this.scroller.scrollTop = this.scrollHeight; | |
331 this.lastScrollTop = this.scrollHeight; | |
332 | |
333 this.contentarea.style.top = this.scrollHeight + 'px'; | |
334 this.contentTop = this.scrollHeight; | |
335 this.scrollTop = 0; | |
336 } | 267 } |
337 | 268 |
338 // Current position and height of the scroller, that could | 269 // Current position and height of the scroller, that could |
339 // be used (by Tiler, for example) to reason about where to | 270 // be used (by Tiler, for example) to reason about where to |
340 // place visible things. | 271 // place visible things. |
341 Scroller.prototype.getCurrentFrame = function() { | 272 Scroller.prototype.getCurrentFrame = function() { |
342 return { top: this.scrollTop, height: this.scrollHeight }; | 273 return { top: this.scrollTop, height: this.scrollHeight }; |
343 } | 274 } |
344 | 275 |
345 Scroller.prototype.hasFrame = function() { | 276 Scroller.prototype.hasFrame = function() { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 Tiler.prototype.updateFirstItem = function(offset) { | 460 Tiler.prototype.updateFirstItem = function(offset) { |
530 var tiles = this.tiles; | 461 var tiles = this.tiles; |
531 | 462 |
532 if (!tiles.length) { | 463 if (!tiles.length) { |
533 this.firstItem = 0; | 464 this.firstItem = 0; |
534 } else { | 465 } else { |
535 this.firstItem += offset; | 466 this.firstItem += offset; |
536 } | 467 } |
537 } | 468 } |
538 | 469 |
539 Tiler.prototype.checkinAllTiles = function() { | |
540 var tiles = this.tiles; | |
541 while (tiles.length) { | |
542 this.checkinTile(tiles.pop()); | |
543 } | |
544 } | |
545 | |
546 Tiler.prototype.reset = function() { | |
547 this.checkinAllTiles(); | |
548 this.drawTop = 0; | |
549 this.drawBottom = 0; | |
550 } | |
551 | |
552 module.exports.CityListElement = class extends SkyElement { | 470 module.exports.CityListElement = class extends SkyElement { |
553 | 471 |
554 created() { | 472 created() { |
555 this.loader = null; | 473 this.loader = null; |
556 this.scroller = null; | 474 this.scroller = null; |
557 this.tiler = null; | 475 this.tiler = null; |
558 this.date = null; | 476 this.date = null; |
559 this.month = null; | 477 this.month = null; |
560 this.views = null; | 478 this.views = null; |
561 this.scrollerElement = null; | |
562 } | 479 } |
563 | 480 |
564 attached() { | 481 attached() { |
565 this.views = {}; | 482 this.views = {}; |
566 this.loader = new Loader(this); | 483 this.loader = new Loader(this); |
567 this.scroller = new Scroller(); | 484 this.scroller = new Scroller(); |
568 this.tiler = new Tiler( | 485 this.tiler = new Tiler( |
569 this.shadowRoot.getElementById('contentarea'), this.views, { | 486 this.shadowRoot.getElementById('contentarea'), this.views, { |
570 stateHeader: 27, | 487 stateHeader: 27, |
571 letterHeader: 18, | 488 letterHeader: 18, |
572 cityItem: 30 | 489 cityItem: 30 |
573 }); | 490 }); |
574 | 491 |
575 this.scrollerElement = this.shadowRoot.getElementById('scroller'); | 492 var self = this; |
576 this.scrollerElement.addEventListener('scroll', | 493 this.addEventListener('wheel', function(event) { |
577 this.handleScroll.bind(this)); | 494 self.scrollBy(-event.offsetY) |
| 495 }); |
578 | 496 |
579 var self = this; | |
580 setTimeout(function() { | 497 setTimeout(function() { |
581 self.domReady(); | 498 self.domReady(); |
582 self.loader.maybeLoadMoreData(self.dataLoaded.bind(self)); | 499 self.loader.maybeLoadMoreData(self.dataLoaded.bind(self)); |
583 }); | 500 }); |
584 } | 501 } |
585 | 502 |
586 domReady() { | 503 domReady() { |
587 this.scroller.setup(this.shadowRoot.getElementById('scroller'), | 504 this.scroller.setup(this.clientHeight, |
588 this.shadowRoot.getElementById('scrollarea'), | |
589 this.shadowRoot.getElementById('contentarea')); | 505 this.shadowRoot.getElementById('contentarea')); |
590 var scrollFrame = this.scroller.getCurrentFrame(); | 506 var scrollFrame = this.scroller.getCurrentFrame(); |
591 this.tiler.setupViews(scrollFrame); | 507 this.tiler.setupViews(scrollFrame); |
592 } | 508 } |
593 | 509 |
594 updateView(data, scrollChanged) { | 510 updateView(data, scrollChanged) { |
595 var scrollFrame = this.scroller.getCurrentFrame(); | 511 var scrollFrame = this.scroller.getCurrentFrame(); |
596 this.tiler.drawTiles(scrollFrame, data); | 512 this.tiler.drawTiles(scrollFrame, data); |
597 var datum = scrollChanged ? | 513 var datum = scrollChanged ? |
598 this.tiler.getFirstVisibleDatum(scrollFrame) : null; | 514 this.tiler.getFirstVisibleDatum(scrollFrame) : null; |
599 this.loader.maybeLoadMoreData(this.dataLoaded.bind(this), datum); | 515 this.loader.maybeLoadMoreData(this.dataLoaded.bind(this), datum); |
600 } | 516 } |
601 | 517 |
602 dataLoaded(data, indexOffset) { | 518 dataLoaded(data, indexOffset) { |
603 var scrollFrame = this.scroller.getCurrentFrame(); | 519 var scrollFrame = this.scroller.getCurrentFrame(); |
604 this.tiler.updateFirstItem(indexOffset); | 520 this.tiler.updateFirstItem(indexOffset); |
605 this.updateView(data.items, false); | 521 this.updateView(data.items, false); |
606 } | 522 } |
607 | 523 |
608 handleScroll(event) { | 524 scrollBy(amount) { |
609 if (!this.scroller.captureNewFrame(event)) | 525 this.scroller.scrollBy(amount); |
610 return; | |
611 | |
612 this.updateView(this.loader.getItems(), true); | 526 this.updateView(this.loader.getItems(), true); |
613 } | 527 } |
614 | |
615 scrollBy(amount) { | |
616 this.scrollerElement.scrollTop += amount; | |
617 this.handleScroll({ target: this.scrollerElement }); | |
618 } | |
619 }.register(); | 528 }.register(); |
620 | 529 |
621 })(this); | 530 })(this); |
622 </script> | 531 </script> |
623 </sky-element> | 532 </sky-element> |
OLD | NEW |