| 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="shadow.sky" as="shadow" /> | |
| 7 <import src="sky-element.sky" /> | |
| 8 <import src="sky-scrollable.sky" /> | |
| 9 | |
| 10 <sky-element attributes="level:number"> | |
| 11 <template> | |
| 12 <style> | |
| 13 #mask { | |
| 14 background-color: black; | |
| 15 will-change: opacity; | |
| 16 position: absolute; | |
| 17 top: 0; | |
| 18 left: 0; | |
| 19 bottom: 0; | |
| 20 right: 0; | |
| 21 } | |
| 22 #content { | |
| 23 background-color: #FAFAFA; | |
| 24 will-change: transform; | |
| 25 position: absolute; | |
| 26 z-index: 2; | |
| 27 width: 256px; | |
| 28 top: 0; | |
| 29 left: 0; | |
| 30 bottom: 0; | |
| 31 } | |
| 32 </style> | |
| 33 <div id="mask" /> | |
| 34 <div id="content"> | |
| 35 <content/> | |
| 36 </div> | |
| 37 </template> | |
| 38 <script> | |
| 39 import "animation/controller.dart"; | |
| 40 import "animation/curves.dart"; | |
| 41 import "animation/timer.dart"; | |
| 42 import "dart:math" as math; | |
| 43 import "dart:sky"; | |
| 44 | |
| 45 const double _kWidth = 256.0; | |
| 46 const double _kMinFlingVelocity = 0.4; | |
| 47 const double _kMinAnimationDurationMS = 246.0; | |
| 48 const double _kMaxAnimationDurationMS = 600.0; | |
| 49 const Cubic _kAnimationCurve = easeOut; | |
| 50 | |
| 51 @Tagname('sky-drawer') | |
| 52 class SkyDrawer extends SkyElement implements AnimationDelegate { | |
| 53 Element _mask; | |
| 54 Element _content; | |
| 55 double _position = 0.0; | |
| 56 AnimationController _animation; | |
| 57 | |
| 58 SkyDrawer() { | |
| 59 _animation = new AnimationController(this); | |
| 60 | |
| 61 addEventListener('pointerdown', _handlePointerDown); | |
| 62 addEventListener('pointermove', _handlePointerMove); | |
| 63 addEventListener('pointerup', _handlePointerUp); | |
| 64 addEventListener('pointercancel', _handlePointerCancel); | |
| 65 } | |
| 66 | |
| 67 void shadowRootReady() { | |
| 68 shadow.applyTo(shadowRoot); | |
| 69 _mask = shadowRoot.getElementById('mask'); | |
| 70 _mask.addEventListener('gesturetap', _handleMaskTap); | |
| 71 _content = shadowRoot.getElementById('content'); | |
| 72 _content.addEventListener('gestureflingstart', _handleFlingStart); | |
| 73 position = -_kWidth; | |
| 74 } | |
| 75 | |
| 76 void toggle() { | |
| 77 if (isMostlyClosed) | |
| 78 open(); | |
| 79 else | |
| 80 close(); | |
| 81 } | |
| 82 | |
| 83 void open() { | |
| 84 _animateToPosition(0.0); | |
| 85 } | |
| 86 | |
| 87 void close() { | |
| 88 _animateToPosition(-_kWidth); | |
| 89 } | |
| 90 | |
| 91 bool get isClosed => _position <= -_kWidth; | |
| 92 bool get isMostlyClosed => _position <= -_kWidth / 2; | |
| 93 double get position => _position; | |
| 94 | |
| 95 set position(double value) { | |
| 96 double newPosition = math.min(0.0, math.max(value, -_kWidth)); | |
| 97 _position = newPosition; | |
| 98 _content.style['transform'] = 'translateX(${newPosition}px)'; | |
| 99 _mask.style['opacity'] = '${(newPosition / _kWidth + 1) * 0.25}'; | |
| 100 style['display'] = isClosed ? 'none' : ''; | |
| 101 } | |
| 102 | |
| 103 void _settle() { | |
| 104 if (isMostlyClosed) | |
| 105 close(); | |
| 106 else | |
| 107 open(); | |
| 108 } | |
| 109 | |
| 110 void _animateToPosition(double targetPosition) { | |
| 111 double currentPosition = _position; | |
| 112 double distance = (targetPosition - currentPosition).abs(); | |
| 113 double duration = _kMaxAnimationDurationMS * distance / _kWidth; | |
| 114 _animation.start( | |
| 115 begin: currentPosition, | |
| 116 end: targetPosition, | |
| 117 duration: math.max(_kMinAnimationDurationMS, duration), | |
| 118 curve: _kAnimationCurve); | |
| 119 } | |
| 120 | |
| 121 void updateAnimation(double p) { | |
| 122 position = p; | |
| 123 } | |
| 124 | |
| 125 void _handleMaskTap(_) { | |
| 126 close(); | |
| 127 } | |
| 128 | |
| 129 void _handlePointerDown(_) { | |
| 130 _animation.stop(); | |
| 131 } | |
| 132 | |
| 133 void _handlePointerMove(PointerEvent event) { | |
| 134 position += event.dx; | |
| 135 } | |
| 136 | |
| 137 void _handlePointerUp(_) { | |
| 138 if (!_animation.isAnimating) | |
| 139 _settle(); | |
| 140 } | |
| 141 | |
| 142 void _handlePointerCancel(_) { | |
| 143 if (!_animation.isAnimating) | |
| 144 _settle(); | |
| 145 } | |
| 146 | |
| 147 void _handleFlingStart(event) { | |
| 148 double direction = event.velocityX.sign; | |
| 149 double velocityX = event.velocityX.abs() / 1000; | |
| 150 if (velocityX < _kMinFlingVelocity) | |
| 151 return; | |
| 152 double targetPosition = direction < 0.0 ? -kWidth : 0.0; | |
| 153 double currentPosition = _position; | |
| 154 double distance = (targetPosition - currentPosition).abs(); | |
| 155 double duration = distance / velocityX; | |
| 156 _animation.start( | |
| 157 begin: currentPosition, | |
| 158 end: targetPosition, | |
| 159 duration: duration, | |
| 160 curve: linear); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 _init(script) => register(script, SkyDrawer); | |
| 165 </script> | |
| 166 </sky-element> | |
| OLD | NEW |