'use strict'; var _ = require('../../lib/helper'); var instances = require('../instances'); var updateGeometry = require('../update-geometry'); var updateScroll = require('../update-scroll'); function bindTouchHandler(element, i, supportsTouch, supportsIePointer) { function shouldPreventDefault(deltaX, deltaY) { var scrollTop = element.scrollTop; var scrollLeft = element.scrollLeft; var magnitudeX = Math.abs(deltaX); var magnitudeY = Math.abs(deltaY); if (magnitudeY > magnitudeX) { // user is perhaps trying to swipe up/down the page if (((deltaY < 0) && (scrollTop === i.contentHeight - i.containerHeight)) || ((deltaY > 0) && (scrollTop === 0))) { return !i.settings.swipePropagation; } } else if (magnitudeX > magnitudeY) { // user is perhaps trying to swipe left/right across the page if (((deltaX < 0) && (scrollLeft === i.contentWidth - i.containerWidth)) || ((deltaX > 0) && (scrollLeft === 0))) { return !i.settings.swipePropagation; } } return true; } function applyTouchMove(differenceX, differenceY) { updateScroll(element, 'top', element.scrollTop - differenceY); updateScroll(element, 'left', element.scrollLeft - differenceX); updateGeometry(element); } var startOffset = {}; var startTime = 0; var speed = {}; var easingLoop = null; var inGlobalTouch = false; var inLocalTouch = false; function globalTouchStart() { inGlobalTouch = true; } function globalTouchEnd() { inGlobalTouch = false; } function getTouch(e) { if (e.targetTouches) { return e.targetTouches[0]; } else { // Maybe IE pointer return e; } } function shouldHandle(e) { if (e.targetTouches && e.targetTouches.length === 1) { return true; } if (e.pointerType && e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) { return true; } return false; } function touchStart(e) { if (shouldHandle(e)) { inLocalTouch = true; var touch = getTouch(e); startOffset.pageX = touch.pageX; startOffset.pageY = touch.pageY; startTime = (new Date()).getTime(); if (easingLoop !== null) { clearInterval(easingLoop); } e.stopPropagation(); } } function touchMove(e) { if (!inLocalTouch && i.settings.swipePropagation) { touchStart(e); } if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) { var touch = getTouch(e); var currentOffset = {pageX: touch.pageX, pageY: touch.pageY}; var differenceX = currentOffset.pageX - startOffset.pageX; var differenceY = currentOffset.pageY - startOffset.pageY; applyTouchMove(differenceX, differenceY); startOffset = currentOffset; var currentTime = (new Date()).getTime(); var timeGap = currentTime - startTime; if (timeGap > 0) { speed.x = differenceX / timeGap; speed.y = differenceY / timeGap; startTime = currentTime; } if (shouldPreventDefault(differenceX, differenceY)) { e.stopPropagation(); e.preventDefault(); } } } function touchEnd() { if (!inGlobalTouch && inLocalTouch) { inLocalTouch = false; clearInterval(easingLoop); easingLoop = setInterval(function () { if (!instances.get(element)) { clearInterval(easingLoop); return; } if (!speed.x && !speed.y) { clearInterval(easingLoop); return; } if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) { clearInterval(easingLoop); return; } applyTouchMove(speed.x * 30, speed.y * 30); speed.x *= 0.8; speed.y *= 0.8; }, 10); } } if (supportsTouch) { i.event.bind(window, 'touchstart', globalTouchStart); i.event.bind(window, 'touchend', globalTouchEnd); i.event.bind(element, 'touchstart', touchStart); i.event.bind(element, 'touchmove', touchMove); i.event.bind(element, 'touchend', touchEnd); } else if (supportsIePointer) { if (window.PointerEvent) { i.event.bind(window, 'pointerdown', globalTouchStart); i.event.bind(window, 'pointerup', globalTouchEnd); i.event.bind(element, 'pointerdown', touchStart); i.event.bind(element, 'pointermove', touchMove); i.event.bind(element, 'pointerup', touchEnd); } else if (window.MSPointerEvent) { i.event.bind(window, 'MSPointerDown', globalTouchStart); i.event.bind(window, 'MSPointerUp', globalTouchEnd); i.event.bind(element, 'MSPointerDown', touchStart); i.event.bind(element, 'MSPointerMove', touchMove); i.event.bind(element, 'MSPointerUp', touchEnd); } } } module.exports = function (element) { if (!_.env.supportsTouch && !_.env.supportsIePointer) { return; } var i = instances.get(element); bindTouchHandler(element, i, _.env.supportsTouch, _.env.supportsIePointer); };