Chromium Code Reviews| 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 { | |
| 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; | |
| 140 transform-style: preserve-3d; | |
| 141 } | |
| 142 | |
| 143 #contentarea { | 123 #contentarea { |
| 144 position: absolute; | 124 transform: translateY(0); |
|
esprehn
2015/01/29 00:33:54
You don't need this anymore. A 0 transform has no
| |
| 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 |