Blame Raw
· · · 165 lines (5.5 KB)
0 contributors
1/*!
2 * swiped-events.js - v@version@
3 * Pure JavaScript swipe events
4 * https://github.com/john-doherty/swiped-events
5 * @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
6 * @author John Doherty <www.johndoherty.info>
7 * @license MIT
8 */
9(function (window, document) {
10
11 'use strict';
12
13 // patch CustomEvent to allow constructor creation (IE/Chrome)
14 if (typeof window.CustomEvent !== 'function') {
15
16 window.CustomEvent = function (event, params) {
17
18 params = params || { bubbles: false, cancelable: false, detail: undefined };
19
20 var evt = document.createEvent('CustomEvent');
21 evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
22 return evt;
23 };
24
25 window.CustomEvent.prototype = window.Event.prototype;
26 }
27
28 document.addEventListener('touchstart', handleTouchStart, false);
29 document.addEventListener('touchmove', handleTouchMove, false);
30 document.addEventListener('touchend', handleTouchEnd, false);
31
32 var xDown = null;
33 var yDown = null;
34 var xDiff = null;
35 var yDiff = null;
36 var timeDown = null;
37 var startEl = null;
38
39 /**
40 * Fires swiped event if swipe detected on touchend
41 * @param {object} e - browser event object
42 * @returns {void}
43 */
44 function handleTouchEnd(e) {
45
46 // if the user released on a different target, cancel!
47 if (startEl !== e.target) return;
48
49 var swipeThreshold = parseInt(getNearestAttribute(startEl, 'data-swipe-threshold', '20'), 10); // default 20 units
50 var swipeUnit = getNearestAttribute(startEl, 'data-swipe-unit', 'px'); // default px
51 var swipeTimeout = parseInt(getNearestAttribute(startEl, 'data-swipe-timeout', '500'), 10); // default 500ms
52 var timeDiff = Date.now() - timeDown;
53 var eventType = '';
54 var changedTouches = e.changedTouches || e.touches || [];
55
56 if (swipeUnit === 'vh') {
57 swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientHeight); // get percentage of viewport height in pixels
58 }
59 if (swipeUnit === 'vw') {
60 swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientWidth); // get percentage of viewport height in pixels
61 }
62
63 if (Math.abs(xDiff) > Math.abs(yDiff)) { // most significant
64 if (Math.abs(xDiff) > swipeThreshold && timeDiff < swipeTimeout) {
65 if (xDiff > 0) {
66 eventType = 'swiped-left';
67 }
68 else {
69 eventType = 'swiped-right';
70 }
71 }
72 }
73 else if (Math.abs(yDiff) > swipeThreshold && timeDiff < swipeTimeout) {
74 if (yDiff > 0) {
75 eventType = 'swiped-up';
76 }
77 else {
78 eventType = 'swiped-down';
79 }
80 }
81
82 if (eventType !== '') {
83
84 var eventData = {
85 dir: eventType.replace(/swiped-/, ''),
86 touchType: (changedTouches[0] || {}).touchType || 'direct',
87 xStart: parseInt(xDown, 10),
88 xEnd: parseInt((changedTouches[0] || {}).clientX || -1, 10),
89 yStart: parseInt(yDown, 10),
90 yEnd: parseInt((changedTouches[0] || {}).clientY || -1, 10)
91 };
92
93 // fire `swiped` event event on the element that started the swipe
94 startEl.dispatchEvent(new CustomEvent('swiped', { bubbles: true, cancelable: true, detail: eventData }));
95
96 // fire `swiped-dir` event on the element that started the swipe
97 startEl.dispatchEvent(new CustomEvent(eventType, { bubbles: true, cancelable: true, detail: eventData }));
98 }
99
100 // reset values
101 xDown = null;
102 yDown = null;
103 timeDown = null;
104 }
105
106 /**
107 * Records current location on touchstart event
108 * @param {object} e - browser event object
109 * @returns {void}
110 */
111 function handleTouchStart(e) {
112
113 // if the element has data-swipe-ignore="true" we stop listening for swipe events
114 if (e.target.getAttribute('data-swipe-ignore') === 'true') return;
115
116 startEl = e.target;
117
118 timeDown = Date.now();
119 xDown = e.touches[0].clientX;
120 yDown = e.touches[0].clientY;
121 xDiff = 0;
122 yDiff = 0;
123 }
124
125 /**
126 * Records location diff in px on touchmove event
127 * @param {object} e - browser event object
128 * @returns {void}
129 */
130 function handleTouchMove(e) {
131
132 if (!xDown || !yDown) return;
133
134 var xUp = e.touches[0].clientX;
135 var yUp = e.touches[0].clientY;
136
137 xDiff = xDown - xUp;
138 yDiff = yDown - yUp;
139 }
140
141 /**
142 * Gets attribute off HTML element or nearest parent
143 * @param {object} el - HTML element to retrieve attribute from
144 * @param {string} attributeName - name of the attribute
145 * @param {any} defaultValue - default value to return if no match found
146 * @returns {any} attribute value or defaultValue
147 */
148 function getNearestAttribute(el, attributeName, defaultValue) {
149
150 // walk up the dom tree looking for attributeName
151 while (el && el !== document.documentElement) {
152
153 var attributeValue = el.getAttribute(attributeName);
154
155 if (attributeValue) {
156 return attributeValue;
157 }
158
159 el = el.parentNode;
160 }
161
162 return defaultValue;
163 }
164
165}(window, document));