| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 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 | |
| 4 // found in the LICENSE file. | |
| 5 --> | |
| 6 <import src="sky-element.sky" /> | |
| 7 | |
| 8 <sky-element> | |
| 9 <template> | |
| 10 <style> | |
| 11 :host { | |
| 12 overflow: hidden; | |
| 13 position: relative; | |
| 14 will-change: transform; | |
| 15 } | |
| 16 #scrollable { | |
| 17 will-change: transform; | |
| 18 } | |
| 19 #vbar { | |
| 20 position: absolute; | |
| 21 right: 0; | |
| 22 background-color: lightgray; | |
| 23 pointer-events: none; | |
| 24 top: 0; | |
| 25 height: 0; | |
| 26 will-change: opacity; | |
| 27 opacity: 0; | |
| 28 transition-property: opacity; | |
| 29 transition-function: ease-in-out; | |
| 30 } | |
| 31 </style> | |
| 32 <div id="scrollable"> | |
| 33 <content /> | |
| 34 </div> | |
| 35 <div id="vbar" /> | |
| 36 </template> | |
| 37 <script> | |
| 38 import "dart:math" as math; | |
| 39 import "dart:sky"; | |
| 40 import "animation/fling-curve.dart"; | |
| 41 import "theme/view-configuration.dart" as config; | |
| 42 | |
| 43 @Tagname('sky-scrollable') | |
| 44 class SkyScrollable extends SkyElement { | |
| 45 Element _scrollable; | |
| 46 Element _vbar; | |
| 47 double _scrollOffset = 0.0; | |
| 48 FlingCurve _flingCurve; | |
| 49 int _flingAnimationId; | |
| 50 | |
| 51 SkyScrollable() { | |
| 52 addEventListener('gesturescrollstart', _handleScrollStart); | |
| 53 addEventListener('gesturescrollend', _handleScrollEnd); | |
| 54 addEventListener('gesturescrollupdate', _handleScrollUpdate); | |
| 55 addEventListener('gestureflingstart', _handleFlingStart); | |
| 56 addEventListener('gestureflingcancel', _handleFlingCancel); | |
| 57 addEventListener('wheel', _handleWheel); | |
| 58 } | |
| 59 | |
| 60 void shadowRootReady() { | |
| 61 _scrollable = shadowRoot.getElementById('scrollable'); | |
| 62 _vbar = shadowRoot.getElementById('vbar'); | |
| 63 // This is not documented anywhere, but the scrollbar appears to only paint | |
| 64 // 3px even though it's official width is 10px? | |
| 65 // Chrome appears 3px wide with a 3px outer spacing. | |
| 66 // Contacts appears 3px wide with a 5px runner and 5px outer spacing. | |
| 67 // Settings appears 4px wide with no outer spacing. | |
| 68 const double paintPercent = 0.3; | |
| 69 const double outerGapPercent = 0.3; | |
| 70 const double innerGapPercent = 0.4; | |
| 71 const double paintWidth = paintPercent * config.kScrollbarSize; | |
| 72 _vbar.style['width'] = "${paintWidth}px"; | |
| 73 _vbar.style['margin-right'] = "${outerGapPercent * config.kScrollbarSize}px"
; | |
| 74 _vbar.style['margin-left'] ="${innerGapPercent * config.kScrollbarSize}px"; | |
| 75 // The scroll thumb never quite makes it to the top or bottom in gmail | |
| 76 // or chrome (in chrome more from the bottom than the top). | |
| 77 _vbar.style['margin-top'] = "${config.kScrollbarSize}px"; | |
| 78 _vbar.style['margin-bottom'] = "${config.kScrollbarSize}px"; | |
| 79 | |
| 80 // Some android apps round their scrollbars, some don't, not rounding for no
w. | |
| 81 | |
| 82 const double msToSeconds = 1.0 / 1000.0; | |
| 83 _vbar.style['transition-duration'] = "${msToSeconds * config.kScrollbarFadeD
uration}s"; | |
| 84 _vbar.style['transition-delay'] = "${msToSeconds * config.kScrollbarFadeDela
y}s"; | |
| 85 } | |
| 86 | |
| 87 double get scrollOffset => _scrollOffset; | |
| 88 | |
| 89 set scrollOffset(double value) { | |
| 90 // TODO(abarth): Can we get these values without forcing a synchronous layou
t? | |
| 91 double outerHeight = clientHeight.toDouble(); | |
| 92 double innerHeight = _scrollable.clientHeight.toDouble(); | |
| 93 double scrollRange = innerHeight - outerHeight; | |
| 94 double newScrollOffset = math.max(0.0, math.min(scrollRange, value)); | |
| 95 if (newScrollOffset == _scrollOffset) | |
| 96 return; | |
| 97 // TODO(eseidel): We should scroll in device pixels instead of logical | |
| 98 // pixels, but to do that correctly we need to use a device pixel unit. | |
| 99 _scrollOffset = newScrollOffset; | |
| 100 String transform = 'translateY(${(-_scrollOffset).toInt()}px)'; | |
| 101 _scrollable.style['transform'] = transform; | |
| 102 | |
| 103 double topPercent = newScrollOffset / innerHeight * 100.0; | |
| 104 double heightPercent = outerHeight / innerHeight * 100.0; | |
| 105 _vbar.style['top'] = '${topPercent}%'; | |
| 106 _vbar.style['height'] = '${heightPercent}%'; | |
| 107 } | |
| 108 | |
| 109 bool scrollBy(double scrollDelta) { | |
| 110 double oldScrollOffset = _scrollOffset; | |
| 111 scrollOffset += scrollDelta; | |
| 112 return _scrollOffset != oldScrollOffset; | |
| 113 } | |
| 114 | |
| 115 void _scheduleFlingUpdate() { | |
| 116 _flingAnimationId = window.requestAnimationFrame(_updateFling); | |
| 117 } | |
| 118 | |
| 119 void _stopFling() { | |
| 120 window.cancelAnimationFrame(_flingAnimationId); | |
| 121 _flingCurve = null; | |
| 122 _flingAnimationId = null; | |
| 123 _vbar.style['opacity'] = '0'; | |
| 124 } | |
| 125 | |
| 126 void _updateFling(double timeStamp) { | |
| 127 double scrollDelta = _flingCurve.update(timeStamp); | |
| 128 if (scrollDelta == 0.0 || !scrollBy(scrollDelta)) | |
| 129 _stopFling(); | |
| 130 else | |
| 131 _scheduleFlingUpdate(); | |
| 132 } | |
| 133 | |
| 134 void _handleScrollStart(_) { | |
| 135 _vbar.style['opacity'] = '1'; | |
| 136 } | |
| 137 | |
| 138 void _handleScrollEnd(_) { | |
| 139 _vbar.style['opacity'] = '0'; | |
| 140 } | |
| 141 | |
| 142 void _handleScrollUpdate(GestureEvent event) { | |
| 143 scrollBy(-event.dy); | |
| 144 } | |
| 145 | |
| 146 void _handleFlingStart(GestureEvent event) { | |
| 147 _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); | |
| 148 _scheduleFlingUpdate(); | |
| 149 } | |
| 150 | |
| 151 void _handleFlingCancel(_) { | |
| 152 _stopFling(); | |
| 153 } | |
| 154 | |
| 155 void _handleWheel(WheelEvent event) { | |
| 156 scrollBy(-event.offsetY); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 _init(script) => register(script, SkyScrollable); | |
| 161 </script> | |
| 162 </sky-element> | |
| OLD | NEW |