1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.googlecode.mgwt.dom.client.recognizer.swipe;
15
16 import com.google.gwt.core.client.GWT;
17 import com.google.gwt.event.shared.HasHandlers;
18 import com.googlecode.mgwt.dom.client.event.touch.Touch;
19 import com.googlecode.mgwt.dom.client.event.touch.TouchCancelEvent;
20 import com.googlecode.mgwt.dom.client.event.touch.TouchEndEvent;
21 import com.googlecode.mgwt.dom.client.event.touch.TouchHandler;
22 import com.googlecode.mgwt.dom.client.event.touch.TouchMoveEvent;
23 import com.googlecode.mgwt.dom.client.event.touch.TouchStartEvent;
24 import com.googlecode.mgwt.dom.client.recognizer.EventPropagator;
25 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeEvent.DIRECTION;
26
27 public class SwipeRecognizer implements TouchHandler {
28
29 private static EventPropagator DEFAULT_EVENT_PROPAGATOR;
30
31 private final HasHandlers source;
32
33 private EventPropagator eventPropagator;
34
35 private final int minDistance;
36
37 private final int threshold;
38
39 private int touchCount;
40
41 private enum State {
42 INVALID, READY, FINDER_DOWN, FOUND_DIRECTION
43 }
44
45 private State state;
46
47 private DIRECTION direction;
48
49 private int lastDistance;
50
51 private int x;
52
53 private int y;
54
55
56
57
58
59
60 public SwipeRecognizer(HasHandlers source) {
61 this(source, 40);
62 }
63
64
65
66
67
68
69
70 public SwipeRecognizer(HasHandlers source, int minDistance) {
71 this(source, minDistance, 10);
72 }
73
74
75
76
77
78
79
80
81 public SwipeRecognizer(HasHandlers source, int minDistance, int threshold) {
82 if (source == null)
83 throw new IllegalArgumentException("source can not be null");
84
85 if (minDistance <= 0 || minDistance < threshold) {
86 throw new IllegalArgumentException("minDistance > 0 and minDistance > threshold");
87 }
88
89 if (threshold <= 0) {
90 throw new IllegalArgumentException("threshold > 0");
91 }
92
93 this.source = source;
94 this.minDistance = minDistance;
95 this.threshold = threshold;
96 this.touchCount = 0;
97 state = State.READY;
98 }
99
100
101
102
103
104
105
106
107 @Override
108 public void onTouchStart(TouchStartEvent event) {
109 touchCount++;
110
111 switch (state) {
112 case INVALID:
113 break;
114
115 case READY:
116 state = State.FINDER_DOWN;
117
118 x = event.getTouches().get(0).getPageX();
119 y = event.getTouches().get(0).getPageY();
120 break;
121
122 case FINDER_DOWN:
123 default:
124 state = State.INVALID;
125 break;
126 }
127
128 }
129
130
131
132
133
134
135
136
137 @Override
138 public void onTouchMove(TouchMoveEvent event) {
139 Touch touch = event.getTouches().get(0);
140
141 switch (state) {
142 case INVALID:
143
144 break;
145 case READY:
146
147 state = State.INVALID;
148 break;
149 case FINDER_DOWN:
150
151
152
153 if (Math.abs(touch.getPageX() - x) >= threshold) {
154 state = State.FOUND_DIRECTION;
155
156 direction = touch.getPageX() - x > 0 ? DIRECTION.LEFT_TO_RIGHT : DIRECTION.RIGHT_TO_LEFT;
157
158 SwipeStartEvent swipeStartEvent = new SwipeStartEvent(touch, touch.getPageX() - x, direction);
159
160 getEventPropagator().fireEvent(source, swipeStartEvent);
161
162 } else {
163 if (Math.abs(touch.getPageY() - y) >= threshold) {
164 state = State.FOUND_DIRECTION;
165
166 direction = touch.getPageY() - y > 0 ? DIRECTION.TOP_TO_BOTTOM : DIRECTION.BOTTOM_TO_TOP;
167
168 SwipeStartEvent swipeStartEvent = new SwipeStartEvent(touch, touch.getPageY() - y, direction);
169
170 getEventPropagator().fireEvent(source, swipeStartEvent);
171
172 }
173
174 }
175 break;
176
177 case FOUND_DIRECTION:
178
179 switch (direction) {
180 case TOP_TO_BOTTOM:
181 case BOTTOM_TO_TOP:
182 lastDistance = Math.abs(touch.getPageY() - y);
183 getEventPropagator().fireEvent(source, new SwipeMoveEvent(touch, lastDistance > minDistance, lastDistance, direction));
184 break;
185
186 case LEFT_TO_RIGHT:
187 case RIGHT_TO_LEFT:
188 lastDistance = Math.abs(touch.getPageX() - x);
189 getEventPropagator().fireEvent(source, new SwipeMoveEvent(touch, lastDistance > minDistance, lastDistance, direction));
190
191 break;
192
193 default:
194 break;
195 }
196
197 break;
198
199 default:
200 break;
201 }
202
203 }
204
205 public native void log(String l)
206
207 ;
208
209
210
211
212
213
214
215
216 @Override
217 public void onTouchEnd(TouchEndEvent event) {
218 touchCount--;
219
220 switch (state) {
221 case FOUND_DIRECTION:
222 getEventPropagator().fireEvent(source, new SwipeEndEvent(lastDistance > minDistance, lastDistance, direction));
223 reset();
224 break;
225
226 default:
227 reset();
228 break;
229 }
230
231 }
232
233
234
235
236
237
238
239
240 @Override
241 public void onTouchCanceled(TouchCancelEvent event) {
242 touchCount--;
243 if (touchCount <= 0)
244 reset();
245
246 }
247
248
249
250
251
252
253 public int getThreshold() {
254 return threshold;
255 }
256
257
258
259
260
261
262 public int getMinDistance() {
263 return minDistance;
264 }
265
266 protected EventPropagator getEventPropagator() {
267 if (eventPropagator == null) {
268 if (DEFAULT_EVENT_PROPAGATOR == null) {
269 DEFAULT_EVENT_PROPAGATOR = GWT.create(EventPropagator.class);
270 }
271 eventPropagator = DEFAULT_EVENT_PROPAGATOR;
272 }
273 return eventPropagator;
274 }
275
276 protected void setEventPropagator(EventPropagator eventPropagator) {
277 this.eventPropagator = eventPropagator;
278
279 }
280
281 private void reset() {
282 state = State.READY;
283 touchCount = 0;
284
285 }
286
287 }