|
| 1 | +export default function swipe(el, sett) { |
| 2 | + |
| 3 | + // настройки по умолчанию |
| 4 | + var settings = Object.assign({}, { |
| 5 | + minDist: 60, // минимальная дистанция, которую должен пройти указатель, чтобы жест считался как свайп (px) |
| 6 | + maxDist: 120, // максимальная дистанция, не превышая которую может пройти указатель, чтобы жест считался как свайп (px) |
| 7 | + maxTime: 700, // максимальное время, за которое должен быть совершен свайп (ms) |
| 8 | + minTime: 50 // минимальное время, за которое должен быть совершен свайп (ms) |
| 9 | + }, sett); |
| 10 | + |
| 11 | + // коррекция времени при ошибочных значениях |
| 12 | + if (settings.maxTime < settings.minTime) settings.maxTime = settings.minTime + 500; |
| 13 | + if (settings.maxTime < 100 || settings.minTime < 50) { |
| 14 | + settings.maxTime = 700; |
| 15 | + settings.minTime = 50; |
| 16 | + } |
| 17 | + |
| 18 | + var dir, // направление свайпа (horizontal, vertical) |
| 19 | + swipeType, // тип свайпа (up, down, left, right) |
| 20 | + dist, // дистанция, пройденная указателем |
| 21 | + isMouse = false, // поддержка мыши (не используется для тач-событий) |
| 22 | + isMouseDown = false, // указание на активное нажатие мыши (не используется для тач-событий) |
| 23 | + startX = 0, // начало координат по оси X (pageX) |
| 24 | + distX = 0, // дистанция, пройденная указателем по оси X |
| 25 | + startY = 0, // начало координат по оси Y (pageY) |
| 26 | + distY = 0, // дистанция, пройденная указателем по оси Y |
| 27 | + startTime = 0, // время начала касания |
| 28 | + support = { // поддерживаемые браузером типы событий |
| 29 | + pointer: !!("PointerEvent" in window || ("msPointerEnabled" in window.navigator)), |
| 30 | + touch: !!(typeof window.orientation !== "undefined" || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.msMaxTouchPoints || "maxTouchPoints" in window.navigator > 1 || "msMaxTouchPoints" in window.navigator > 1) |
| 31 | + }; |
| 32 | + |
| 33 | + |
| 34 | + var getSupportedEvents = function() { |
| 35 | + switch (true) { |
| 36 | + case support.pointer: |
| 37 | + events = { |
| 38 | + type: "pointer", |
| 39 | + start: "PointerDown", |
| 40 | + move: "PointerMove", |
| 41 | + end: "PointerUp", |
| 42 | + cancel: "PointerCancel", |
| 43 | + leave: "PointerLeave" |
| 44 | + }; |
| 45 | + // добавление префиксов для IE10 |
| 46 | + var ie10 = (window.navigator.msPointerEnabled && Function('/*@cc_on return document.documentMode===10@*/')()); |
| 47 | + for (var value in events) { |
| 48 | + if (value === "type") continue; |
| 49 | + events[value] = (ie10) ? "MS" + events[value] : events[value].toLowerCase(); |
| 50 | + } |
| 51 | + break; |
| 52 | + case support.touch: |
| 53 | + events = { |
| 54 | + type: "touch", |
| 55 | + start: "touchstart", |
| 56 | + move: "touchmove", |
| 57 | + end: "touchend", |
| 58 | + cancel: "touchcancel" |
| 59 | + }; |
| 60 | + break; |
| 61 | + default: |
| 62 | + events = { |
| 63 | + type: "mouse", |
| 64 | + start: "mousedown", |
| 65 | + move: "mousemove", |
| 66 | + end: "mouseup", |
| 67 | + leave: "mouseleave" |
| 68 | + }; |
| 69 | + break; |
| 70 | + } |
| 71 | + return events; |
| 72 | + }; |
| 73 | + |
| 74 | + |
| 75 | + var eventsUnify = function(e) { |
| 76 | + return e.changedTouches ? e.changedTouches[0] : e; |
| 77 | + }; |
| 78 | + |
| 79 | + var checkStart = function(e) { |
| 80 | + var event = eventsUnify(e); |
| 81 | + if (support.touch && typeof e.touches !== "undefined" && e.touches.length !== 1) return; // игнорирование касания несколькими пальцами |
| 82 | + dir = "none"; |
| 83 | + swipeType = "none"; |
| 84 | + dist = 0; |
| 85 | + startX = event.pageX; |
| 86 | + startY = event.pageY; |
| 87 | + startTime = new Date().getTime(); |
| 88 | + if (isMouse) isMouseDown = true; // поддержка мыши |
| 89 | + }; |
| 90 | + |
| 91 | + var checkMove = function(e) { |
| 92 | + if (isMouse && !isMouseDown) return; // выход из функции, если мышь перестала быть активна во время движения |
| 93 | + var event = eventsUnify(e); |
| 94 | + distX = event.pageX - startX; |
| 95 | + distY = event.pageY - startY; |
| 96 | + if (Math.abs(distX) > Math.abs(distY)) dir = (distX < 0) ? "left" : "right"; |
| 97 | + else dir = (distY < 0) ? "up" : "down"; |
| 98 | + }; |
| 99 | + |
| 100 | + var checkEnd = function(e) { |
| 101 | + if (isMouse && !isMouseDown) { // выход из функции и сброс проверки нажатия мыши |
| 102 | + isMouseDown = false; |
| 103 | + return; |
| 104 | + } |
| 105 | + var endTime = new Date().getTime(); |
| 106 | + var time = endTime - startTime; |
| 107 | + if (time >= settings.minTime && time <= settings.maxTime) { // проверка времени жеста |
| 108 | + if (Math.abs(distX) >= settings.minDist && Math.abs(distY) <= settings.maxDist) { |
| 109 | + swipeType = dir; // опредление типа свайпа как "left" или "right" |
| 110 | + } else if (Math.abs(distY) >= settings.minDist && Math.abs(distX) <= settings.maxDist) { |
| 111 | + swipeType = dir; // опредление типа свайпа как "top" или "down" |
| 112 | + } |
| 113 | + } |
| 114 | + dist = (dir === "left" || dir === "right") ? Math.abs(distX) : Math.abs(distY); // опредление пройденной указателем дистанции |
| 115 | + |
| 116 | + // генерация кастомного события swipe |
| 117 | + if (swipeType !== "none" && dist >= settings.minDist) { |
| 118 | + var swipeEvent = new CustomEvent("swipe", { |
| 119 | + bubbles: true, |
| 120 | + cancelable: true, |
| 121 | + detail: { |
| 122 | + full: e, // полное событие Event |
| 123 | + dir: swipeType, // направление свайпа |
| 124 | + dist: dist, // дистанция свайпа |
| 125 | + time: time // время, потраченное на свайп |
| 126 | + } |
| 127 | + }); |
| 128 | + el.dispatchEvent(swipeEvent); |
| 129 | + } |
| 130 | + }; |
| 131 | + |
| 132 | + // добавление поддерживаемых событий |
| 133 | + var events = getSupportedEvents(); |
| 134 | + |
| 135 | + // проверка наличия мыши |
| 136 | + if ((support.pointer && !support.touch) || events.type === "mouse") isMouse = true; |
| 137 | + |
| 138 | + // добавление обработчиков на элемент |
| 139 | + el.addEventListener(events.start, checkStart); |
| 140 | + el.addEventListener(events.move, checkMove); |
| 141 | + el.addEventListener(events.end, checkEnd); |
| 142 | + if(support.pointer && support.touch) { |
| 143 | + el.addEventListener('lostpointercapture', checkEnd); |
| 144 | + } |
| 145 | +} |
0 commit comments