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 |