1
|
/*
|
2
|
Based on:
|
3
|
Copyright (c) 2010-2016 Thomas Fuchs
|
4
|
http://zeptojs.com/
|
5
|
*/
|
6
|
|
7
|
import { $, on, pointerCancel, pointerDown, pointerMove, pointerUp, ready } from './index';
|
8
|
|
9
|
var touch = {}, touchTimeout, tapTimeout, swipeTimeout, gesture, clicked;
|
10
|
|
11
|
function swipeDirection(x1, x2, y1, y2) {
|
12
|
return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down');
|
13
|
}
|
14
|
|
15
|
function cancelAll() {
|
16
|
if (touchTimeout) clearTimeout(touchTimeout);
|
17
|
if (tapTimeout) clearTimeout(tapTimeout);
|
18
|
if (swipeTimeout) clearTimeout(swipeTimeout);
|
19
|
touchTimeout = tapTimeout = swipeTimeout = null;
|
20
|
touch = {};
|
21
|
}
|
22
|
|
23
|
ready(function () {
|
24
|
|
25
|
var now, delta, deltaX = 0, deltaY = 0, firstTouch;
|
26
|
|
27
|
if ('MSGesture' in window) {
|
28
|
gesture = new MSGesture();
|
29
|
gesture.target = document.body;
|
30
|
}
|
31
|
|
32
|
on(document, 'click', () => clicked = true, true);
|
33
|
|
34
|
var gestureHandler = function (e) {
|
35
|
|
36
|
var swipeDirectionFromVelocity = e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null;
|
37
|
|
38
|
if (swipeDirectionFromVelocity && touch.el !== undefined) {
|
39
|
touch.el.trigger('swipe');
|
40
|
touch.el.trigger(`swipe${swipeDirectionFromVelocity}`);
|
41
|
}
|
42
|
};
|
43
|
|
44
|
on(document, 'MSGestureEnd', gestureHandler);
|
45
|
on(document, 'gestureend', gestureHandler);
|
46
|
|
47
|
on(document, pointerDown, function (e) {
|
48
|
|
49
|
firstTouch = e.touches ? e.touches[0] : e;
|
50
|
|
51
|
now = Date.now();
|
52
|
delta = now - (touch.last || now);
|
53
|
touch.el = $('tagName' in firstTouch.target ? firstTouch.target : firstTouch.target.parentNode);
|
54
|
|
55
|
if (touchTimeout) clearTimeout(touchTimeout);
|
56
|
|
57
|
touch.x1 = firstTouch.pageX;
|
58
|
touch.y1 = firstTouch.pageY;
|
59
|
|
60
|
if (delta > 0 && delta <= 250) touch.isDoubleTap = true;
|
61
|
|
62
|
touch.last = now;
|
63
|
|
64
|
// adds the current touch contact for IE gesture recognition
|
65
|
if (gesture && (e.type === 'pointerdown' || e.type === 'touchstart')) {
|
66
|
gesture.addPointer(e.pointerId);
|
67
|
}
|
68
|
|
69
|
clicked = e.button > 0;
|
70
|
|
71
|
});
|
72
|
|
73
|
on(document, pointerMove, function (e) {
|
74
|
|
75
|
firstTouch = e.touches ? e.touches[0] : e;
|
76
|
|
77
|
touch.x2 = firstTouch.pageX;
|
78
|
touch.y2 = firstTouch.pageY;
|
79
|
|
80
|
deltaX += Math.abs(touch.x1 - touch.x2);
|
81
|
deltaY += Math.abs(touch.y1 - touch.y2);
|
82
|
});
|
83
|
|
84
|
on(document, pointerUp, function () {
|
85
|
|
86
|
// swipe
|
87
|
if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) {
|
88
|
|
89
|
swipeTimeout = setTimeout(function () {
|
90
|
if (touch.el !== undefined) {
|
91
|
touch.el.trigger('swipe');
|
92
|
touch.el.trigger(`swipe${swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)}`);
|
93
|
}
|
94
|
touch = {};
|
95
|
}, 0);
|
96
|
|
97
|
// normal tap
|
98
|
} else if ('last' in touch) {
|
99
|
|
100
|
// don't fire tap when delta position changed by more than 30 pixels,
|
101
|
// for instance when moving to a point and back to origin
|
102
|
if (isNaN(deltaX) || (deltaX < 30 && deltaY < 30)) {
|
103
|
// delay by one tick so we can cancel the 'tap' event if 'scroll' fires
|
104
|
// ('tap' fires before 'scroll')
|
105
|
tapTimeout = setTimeout(function () {
|
106
|
|
107
|
// trigger universal 'tap' with the option to cancelTouch()
|
108
|
// (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
|
109
|
var event = $.Event('tap');
|
110
|
event.cancelTouch = cancelAll;
|
111
|
|
112
|
if (touch.el !== undefined) {
|
113
|
touch.el.trigger(event);
|
114
|
}
|
115
|
|
116
|
// trigger double tap immediately
|
117
|
if (touch.isDoubleTap) {
|
118
|
if (touch.el !== undefined) touch.el.trigger('doubleTap');
|
119
|
touch = {};
|
120
|
}
|
121
|
|
122
|
// trigger single tap after 300ms of inactivity
|
123
|
else {
|
124
|
touchTimeout = setTimeout(function () {
|
125
|
touchTimeout = null;
|
126
|
if (touch.el !== undefined) {
|
127
|
touch.el.trigger('singleTap');
|
128
|
|
129
|
if (!clicked) {
|
130
|
touch.el.trigger('click');
|
131
|
}
|
132
|
|
133
|
}
|
134
|
touch = {};
|
135
|
}, 300);
|
136
|
}
|
137
|
});
|
138
|
} else {
|
139
|
touch = {};
|
140
|
}
|
141
|
deltaX = deltaY = 0;
|
142
|
}
|
143
|
});
|
144
|
|
145
|
// when the browser window loses focus,
|
146
|
// for example when a modal dialog is shown,
|
147
|
// cancel all ongoing events
|
148
|
on(document, pointerCancel, cancelAll);
|
149
|
|
150
|
// scrolling the window indicates intention of the user
|
151
|
// to scroll, not tap or swipe, so cancel all ongoing events
|
152
|
on(window, 'scroll', cancelAll);
|
153
|
});
|
154
|
|
155
|
var touching = false;
|
156
|
on(document, 'touchstart', () => touching = true, true);
|
157
|
on(document, 'click', () => {touching = false});
|
158
|
on(document, 'touchcancel', () => touching = false, true);
|
159
|
|
160
|
export function isTouch(e) {
|
161
|
return touching || (e.originalEvent || e).pointerType === 'touch';
|
162
|
}
|