OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 import 'dart:math' as math; | |
6 import 'mechanics.dart'; | |
7 import 'generators.dart'; | |
8 | |
9 const double _kScrollFriction = 0.005; | |
10 const double _kOverscrollFriction = 0.075; | |
11 const double _kBounceSlopeAngle = math.PI / 512.0; // radians | |
12 | |
13 abstract class ScrollBehavior { | |
14 Simulation release(Particle particle) => null; | |
15 | |
16 // Returns the new scroll offset. | |
17 double applyCurve(double scrollOffset, double scrollDelta); | |
18 } | |
19 | |
20 class BoundedScrollBehavior extends ScrollBehavior { | |
21 double minOffset; | |
22 double maxOffset; | |
23 | |
24 BoundedScrollBehavior({this.minOffset: 0.0, this.maxOffset}); | |
25 | |
26 double applyCurve(double scrollOffset, double scrollDelta) { | |
27 double newScrollOffset = scrollOffset + scrollDelta; | |
28 if (minOffset != null) | |
29 newScrollOffset = math.max(minOffset, newScrollOffset); | |
30 if (maxOffset != null) | |
31 newScrollOffset = math.min(maxOffset, newScrollOffset); | |
32 return newScrollOffset; | |
33 } | |
34 } | |
35 | |
36 class OverscrollBehavior extends ScrollBehavior { | |
37 | |
38 double _contentsHeight; | |
39 double get contentsHeight => _contentsHeight; | |
40 void set contentsHeight (double value) { | |
41 if (_contentsHeight != value) { | |
42 _contentsHeight = value; | |
43 // TODO(ianh) now what? what if we have a simulation ongoing? | |
44 } | |
45 } | |
46 | |
47 double _containerHeight; | |
48 double get containerHeight => _containerHeight; | |
49 void set containerHeight (double value) { | |
50 if (_containerHeight != value) { | |
51 _containerHeight = value; | |
52 // TODO(ianh) now what? what if we have a simulation ongoing? | |
53 } | |
54 } | |
55 | |
56 OverscrollBehavior({double contentsHeight: 0.0, double containerHeight: 0.0}) | |
57 : _contentsHeight = contentsHeight, | |
58 _containerHeight = containerHeight; | |
59 | |
60 double get maxScroll => math.max(0.0, _contentsHeight - _containerHeight); | |
61 | |
62 Simulation release(Particle particle) { | |
63 System system; | |
64 if ((particle.position >= 0.0) && (particle.position < maxScroll)) { | |
65 if (particle.velocity == 0.0) | |
66 return null; | |
67 System slowdownSystem = new ParticleInBoxWithFriction( | |
68 particle: particle, | |
69 friction: _kScrollFriction, | |
70 box: new GeofenceBox(min: 0.0, max: maxScroll, onEscape: () { | |
71 (system as Multisystem).transitionToSystem(new ParticleInBoxWithFricti
on( | |
72 particle: particle, | |
73 friction: _kOverscrollFriction, | |
74 box: new ClosedBox(), | |
75 onStop: () => (system as Multisystem).transitionToSystem(getBounceBa
ckSystem(particle)) | |
76 )); | |
77 })); | |
78 system = new Multisystem(particle: particle, system: slowdownSystem); | |
79 } else { | |
80 system = getBounceBackSystem(particle); | |
81 } | |
82 return new Simulation(system, terminationCondition: () => particle.position
== 0.0); | |
83 } | |
84 | |
85 System getBounceBackSystem(Particle particle) { | |
86 if (particle.position < 0.0) | |
87 return new ParticleClimbingRamp( | |
88 particle: particle, | |
89 box: new ClosedBox(max: 0.0), | |
90 theta: _kBounceSlopeAngle, | |
91 targetPosition: 0.0); | |
92 return new ParticleClimbingRamp( | |
93 particle: particle, | |
94 box: new ClosedBox(min: maxScroll), | |
95 theta: _kBounceSlopeAngle, | |
96 targetPosition: maxScroll); | |
97 } | |
98 | |
99 double applyCurve(double scrollOffset, double scrollDelta) { | |
100 double newScrollOffset = scrollOffset + scrollDelta; | |
101 // If we're overscrolling, we want move the scroll offset 2x | |
102 // slower than we would otherwise. Therefore, we "rewind" the | |
103 // newScrollOffset by half the amount that we moved it above. | |
104 // Notice that we clap the "old" value to 0.0 so that we only | |
105 // reduce the portion of scrollDelta that's applied beyond 0.0. We | |
106 // do similar things for overscroll in the other direction. | |
107 if (newScrollOffset < 0.0) { | |
108 newScrollOffset -= (newScrollOffset - math.min(0.0, scrollOffset)) / 2.0; | |
109 } else if (newScrollOffset > maxScroll) { | |
110 newScrollOffset -= (newScrollOffset - math.max(maxScroll, scrollOffset)) /
2.0; | |
111 } | |
112 return newScrollOffset; | |
113 } | |
114 } | |
OLD | NEW |