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