| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 // Copyright 2015 The Chromium Authors. All rights reserved. | 2 // Copyright 2015 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="/sky/framework/sky-element/sky-element.sky" as="SkyElement" /> | 6 <import src="/sky/framework/sky-element/sky-element.sky" as="SkyElement" /> |
| 7 <import src="/sky/framework/fling-curve.sky" as="FlingCurve" /> |
| 7 | 8 |
| 8 <sky-element | 9 <sky-element |
| 9 name="sky-scrollable" | 10 name="sky-scrollable" |
| 10 on-gesturescrollstart="handleScrollStart_" | 11 on-gesturescrollstart="handleScrollStart_" |
| 11 on-gesturescrollend="handleScrollEnd_" | 12 on-gesturescrollend="handleScrollEnd_" |
| 12 on-gesturescrollupdate="handleScrollUpdate_" | 13 on-gesturescrollupdate="handleScrollUpdate_" |
| 13 on-gestureflingstart="handleFlingStart_" | 14 on-gestureflingstart="handleFlingStart_" |
| 14 on-gestureflingcancel="handleFlingCancel_"> | 15 on-gestureflingcancel="handleFlingCancel_"> |
| 15 <template> | 16 <template> |
| 16 <style> | 17 <style> |
| 17 :host { | 18 :host { |
| 18 overflow: hidden; | 19 overflow: hidden; |
| 19 } | 20 } |
| 20 #scrollable { | 21 #scrollable { |
| 21 transform: translateY(0); | 22 transform: translateY(0); |
| 22 } | 23 } |
| 23 </style> | 24 </style> |
| 24 <div id="scrollable"> | 25 <div id="scrollable"> |
| 25 <content /> | 26 <content /> |
| 26 </div> | 27 </div> |
| 27 </template> | 28 </template> |
| 28 <script> | 29 <script> |
| 29 // TODO(abarth): Move the fling curve to a separate module. | |
| 30 var kFlingFriction = 0.9; | |
| 31 var kFlingVelocityMin = 1; | |
| 32 | |
| 33 module.exports = class extends SkyElement { | 30 module.exports = class extends SkyElement { |
| 34 created() { | 31 created() { |
| 35 this.scrollable_ = null; | 32 this.scrollable_ = null; |
| 36 this.scrollOffset_ = 0; | 33 this.scrollOffset_ = 0; |
| 37 this.flingVelocity_ = 0; | 34 this.flingCurve_ = null; |
| 38 this.flingAnimationId_ = null; | 35 this.flingAnimationId_ = null; |
| 39 } | 36 } |
| 40 | 37 |
| 41 shadowRootReady() { | 38 shadowRootReady() { |
| 42 this.scrollable_ = this.shadowRoot.getElementById('scrollable'); | 39 this.scrollable_ = this.shadowRoot.getElementById('scrollable'); |
| 43 } | 40 } |
| 44 | 41 |
| 45 scrollBy(scrollDelta) { | 42 scrollBy(scrollDelta) { |
| 46 var offset = Math.max(0, Math.min(this.scrollable_.offsetHeight, this.scroll
Offset_ + scrollDelta)); | 43 var scrollHeight = this.scrollable_.clientHeight - this.clientHeight; |
| 44 var offset = Math.max(0, Math.min(scrollHeight, this.scrollOffset_ + scrollD
elta)); |
| 47 if (offset == this.scrollOffset_) | 45 if (offset == this.scrollOffset_) |
| 48 return false; | 46 return false; |
| 49 this.scrollOffset_ = offset; | 47 this.scrollOffset_ = offset; |
| 50 this.applyScrollOffset_(); | 48 this.applyScrollOffset_(); |
| 51 return true; | 49 return true; |
| 52 } | 50 } |
| 53 | 51 |
| 54 applyScrollOffset_() { | 52 applyScrollOffset_() { |
| 55 var transform = 'translateY(' + -this.scrollOffset_.toFixed(2) + 'px)'; | 53 var transform = 'translateY(' + -this.scrollOffset_.toFixed(2) + 'px)'; |
| 56 this.scrollable_.style.transform = transform; | 54 this.scrollable_.style.transform = transform; |
| 57 } | 55 } |
| 58 | 56 |
| 59 scheduleFlingTick_() { | 57 scheduleFlingUpdate_() { |
| 60 this.flingAnimationId_ = requestAnimationFrame(this.tickFling_.bind(this)); | 58 this.flingAnimationId_ = requestAnimationFrame(this.updateFling_.bind(this))
; |
| 61 } | 59 } |
| 62 | 60 |
| 63 tickFling_() { | 61 stopFling_() { |
| 62 cancelAnimationFrame(this.flingAnimationId_); |
| 63 this.flingCurve_ = null; |
| 64 this.flingAnimationId_ = null; | 64 this.flingAnimationId_ = null; |
| 65 if (!this.scrollBy(this.flingVelocity_)) { | 65 } |
| 66 this.flingVelocity_ = 0; | 66 |
| 67 return; | 67 updateFling_(timeStamp) { |
| 68 } | 68 var scrollDelta = this.flingCurve_.update(timeStamp); |
| 69 var velocity = this.flingVelocity_ * kFlingFriction; | 69 if (!scrollDelta || !this.scrollBy(scrollDelta)) |
| 70 if (velocity < kFlingVelocityMin) | 70 return this.stopFling_(); |
| 71 velocity = 0; | 71 this.scheduleFlingUpdate_(); |
| 72 this.flingVelocity_ = velocity; | |
| 73 if (velocity) | |
| 74 this.scheduleFlingTick_(); | |
| 75 } | 72 } |
| 76 | 73 |
| 77 handleScrollStart_(event) { | 74 handleScrollStart_(event) { |
| 78 } | 75 } |
| 79 | 76 |
| 80 handleScrollEnd_(event) { | 77 handleScrollEnd_(event) { |
| 81 } | 78 } |
| 82 | 79 |
| 83 handleScrollUpdate_(event) { | 80 handleScrollUpdate_(event) { |
| 84 this.scrollBy(-event.dy); | 81 this.scrollBy(-event.dy); |
| 85 } | 82 } |
| 86 | 83 |
| 87 handleFlingStart_(event) { | 84 handleFlingStart_(event) { |
| 88 this.flingVelocity_ = -event.velocityY; | 85 this.flingCurve_ = new FlingCurve(-event.velocityY, event.timeStamp); |
| 89 this.scheduleFlingTick_(); | 86 this.scheduleFlingUpdate_(); |
| 90 } | 87 } |
| 91 | 88 |
| 92 handleFlingCancel_(event) { | 89 handleFlingCancel_(event) { |
| 93 if (!this.flingAnimationId_) | 90 this.stopFling_(); |
| 94 return; | |
| 95 cancelAnimationFrame(this.flingAnimationId_); | |
| 96 this.flingVelocity_ = 0; | |
| 97 this.flingAnimationId_ = null; | |
| 98 } | 91 } |
| 99 }.register(); | 92 }.register(); |
| 100 </script> | 93 </script> |
| 101 </sky-element> | 94 </sky-element> |
| OLD | NEW |