import Utils from '../../../utils/utils';
|
|
export default function (event) {
|
const swiper = this;
|
const data = swiper.touchEventsData;
|
|
const {
|
params, touches, rtlTranslate: rtl, $wrapperEl, slidesGrid, snapGrid,
|
} = swiper;
|
let e = event;
|
if (e.originalEvent) e = e.originalEvent;
|
if (data.allowTouchCallbacks) {
|
swiper.emit('touchEnd', e);
|
}
|
data.allowTouchCallbacks = false;
|
if (!data.isTouched) {
|
if (data.isMoved && params.grabCursor) {
|
swiper.setGrabCursor(false);
|
}
|
data.isMoved = false;
|
data.startMoving = false;
|
return;
|
}
|
// Return Grab Cursor
|
if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
|
swiper.setGrabCursor(false);
|
}
|
|
// Time diff
|
const touchEndTime = Utils.now();
|
const timeDiff = touchEndTime - data.touchStartTime;
|
|
// Tap, doubleTap, Click
|
if (swiper.allowClick) {
|
swiper.updateClickedSlide(e);
|
swiper.emit('tap click', e);
|
if (timeDiff < 300 && (touchEndTime - data.lastClickTime) < 300) {
|
swiper.emit('doubleTap doubleClick', e);
|
}
|
}
|
|
data.lastClickTime = Utils.now();
|
Utils.nextTick(() => {
|
if (!swiper.destroyed) swiper.allowClick = true;
|
});
|
|
if (!data.isTouched || !data.isMoved || !swiper.swipeDirection || touches.diff === 0 || data.currentTranslate === data.startTranslate) {
|
data.isTouched = false;
|
data.isMoved = false;
|
data.startMoving = false;
|
return;
|
}
|
data.isTouched = false;
|
data.isMoved = false;
|
data.startMoving = false;
|
|
let currentPos;
|
if (params.followFinger) {
|
currentPos = rtl ? swiper.translate : -swiper.translate;
|
} else {
|
currentPos = -data.currentTranslate;
|
}
|
|
if (params.cssMode) {
|
return;
|
}
|
|
if (params.freeMode) {
|
if (currentPos < -swiper.minTranslate()) {
|
swiper.slideTo(swiper.activeIndex);
|
return;
|
}
|
if (currentPos > -swiper.maxTranslate()) {
|
if (swiper.slides.length < snapGrid.length) {
|
swiper.slideTo(snapGrid.length - 1);
|
} else {
|
swiper.slideTo(swiper.slides.length - 1);
|
}
|
return;
|
}
|
|
if (params.freeModeMomentum) {
|
if (data.velocities.length > 1) {
|
const lastMoveEvent = data.velocities.pop();
|
const velocityEvent = data.velocities.pop();
|
|
const distance = lastMoveEvent.position - velocityEvent.position;
|
const time = lastMoveEvent.time - velocityEvent.time;
|
swiper.velocity = distance / time;
|
swiper.velocity /= 2;
|
if (Math.abs(swiper.velocity) < params.freeModeMinimumVelocity) {
|
swiper.velocity = 0;
|
}
|
// this implies that the user stopped moving a finger then released.
|
// There would be no events with distance zero, so the last event is stale.
|
if (time > 150 || (Utils.now() - lastMoveEvent.time) > 300) {
|
swiper.velocity = 0;
|
}
|
} else {
|
swiper.velocity = 0;
|
}
|
swiper.velocity *= params.freeModeMomentumVelocityRatio;
|
|
data.velocities.length = 0;
|
let momentumDuration = 1000 * params.freeModeMomentumRatio;
|
const momentumDistance = swiper.velocity * momentumDuration;
|
|
let newPosition = swiper.translate + momentumDistance;
|
if (rtl) newPosition = -newPosition;
|
|
let doBounce = false;
|
let afterBouncePosition;
|
const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeModeMomentumBounceRatio;
|
let needsLoopFix;
|
if (newPosition < swiper.maxTranslate()) {
|
if (params.freeModeMomentumBounce) {
|
if (newPosition + swiper.maxTranslate() < -bounceAmount) {
|
newPosition = swiper.maxTranslate() - bounceAmount;
|
}
|
afterBouncePosition = swiper.maxTranslate();
|
doBounce = true;
|
data.allowMomentumBounce = true;
|
} else {
|
newPosition = swiper.maxTranslate();
|
}
|
if (params.loop && params.centeredSlides) needsLoopFix = true;
|
} else if (newPosition > swiper.minTranslate()) {
|
if (params.freeModeMomentumBounce) {
|
if (newPosition - swiper.minTranslate() > bounceAmount) {
|
newPosition = swiper.minTranslate() + bounceAmount;
|
}
|
afterBouncePosition = swiper.minTranslate();
|
doBounce = true;
|
data.allowMomentumBounce = true;
|
} else {
|
newPosition = swiper.minTranslate();
|
}
|
if (params.loop && params.centeredSlides) needsLoopFix = true;
|
} else if (params.freeModeSticky) {
|
let nextSlide;
|
for (let j = 0; j < snapGrid.length; j += 1) {
|
if (snapGrid[j] > -newPosition) {
|
nextSlide = j;
|
break;
|
}
|
}
|
|
if (Math.abs(snapGrid[nextSlide] - newPosition) < Math.abs(snapGrid[nextSlide - 1] - newPosition) || swiper.swipeDirection === 'next') {
|
newPosition = snapGrid[nextSlide];
|
} else {
|
newPosition = snapGrid[nextSlide - 1];
|
}
|
newPosition = -newPosition;
|
}
|
if (needsLoopFix) {
|
swiper.once('transitionEnd', () => {
|
swiper.loopFix();
|
});
|
}
|
// Fix duration
|
if (swiper.velocity !== 0) {
|
if (rtl) {
|
momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity);
|
} else {
|
momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity);
|
}
|
if (params.freeModeSticky) {
|
// If freeModeSticky is active and the user ends a swipe with a slow-velocity
|
// event, then durations can be 20+ seconds to slide one (or zero!) slides.
|
// It's easy to see this when simulating touch with mouse events. To fix this,
|
// limit single-slide swipes to the default slide duration. This also has the
|
// nice side effect of matching slide speed if the user stopped moving before
|
// lifting finger or mouse vs. moving slowly before lifting the finger/mouse.
|
// For faster swipes, also apply limits (albeit higher ones).
|
const moveDistance = Math.abs((rtl ? -newPosition : newPosition) - swiper.translate);
|
const currentSlideSize = swiper.slidesSizesGrid[swiper.activeIndex];
|
if (moveDistance < currentSlideSize) {
|
momentumDuration = params.speed;
|
} else if (moveDistance < 2 * currentSlideSize) {
|
momentumDuration = params.speed * 1.5;
|
} else {
|
momentumDuration = params.speed * 2.5;
|
}
|
}
|
} else if (params.freeModeSticky) {
|
swiper.slideToClosest();
|
return;
|
}
|
|
if (params.freeModeMomentumBounce && doBounce) {
|
swiper.updateProgress(afterBouncePosition);
|
swiper.setTransition(momentumDuration);
|
swiper.setTranslate(newPosition);
|
swiper.transitionStart(true, swiper.swipeDirection);
|
swiper.animating = true;
|
$wrapperEl.transitionEnd(() => {
|
if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return;
|
swiper.emit('momentumBounce');
|
swiper.setTransition(params.speed);
|
setTimeout(() => {
|
swiper.setTranslate(afterBouncePosition);
|
$wrapperEl.transitionEnd(() => {
|
if (!swiper || swiper.destroyed) return;
|
swiper.transitionEnd();
|
});
|
}, 0);
|
});
|
} else if (swiper.velocity) {
|
swiper.updateProgress(newPosition);
|
swiper.setTransition(momentumDuration);
|
swiper.setTranslate(newPosition);
|
swiper.transitionStart(true, swiper.swipeDirection);
|
if (!swiper.animating) {
|
swiper.animating = true;
|
$wrapperEl.transitionEnd(() => {
|
if (!swiper || swiper.destroyed) return;
|
swiper.transitionEnd();
|
});
|
}
|
} else {
|
swiper.updateProgress(newPosition);
|
}
|
|
swiper.updateActiveIndex();
|
swiper.updateSlidesClasses();
|
} else if (params.freeModeSticky) {
|
swiper.slideToClosest();
|
return;
|
}
|
|
if (!params.freeModeMomentum || timeDiff >= params.longSwipesMs) {
|
swiper.updateProgress();
|
swiper.updateActiveIndex();
|
swiper.updateSlidesClasses();
|
}
|
return;
|
}
|
|
// Find current slide
|
let stopIndex = 0;
|
let groupSize = swiper.slidesSizesGrid[0];
|
for (let i = 0; i < slidesGrid.length; i += (i < params.slidesPerGroupSkip ? 1 : params.slidesPerGroup)) {
|
const increment = (i < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup);
|
if (typeof slidesGrid[i + increment] !== 'undefined') {
|
if (currentPos >= slidesGrid[i] && currentPos < slidesGrid[i + increment]) {
|
stopIndex = i;
|
groupSize = slidesGrid[i + increment] - slidesGrid[i];
|
}
|
} else if (currentPos >= slidesGrid[i]) {
|
stopIndex = i;
|
groupSize = slidesGrid[slidesGrid.length - 1] - slidesGrid[slidesGrid.length - 2];
|
}
|
}
|
|
// Find current slide size
|
const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
|
const increment = (stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup);
|
|
if (timeDiff > params.longSwipesMs) {
|
// Long touches
|
if (!params.longSwipes) {
|
swiper.slideTo(swiper.activeIndex);
|
return;
|
}
|
if (swiper.swipeDirection === 'next') {
|
if (ratio >= params.longSwipesRatio) swiper.slideTo(stopIndex + increment);
|
else swiper.slideTo(stopIndex);
|
}
|
if (swiper.swipeDirection === 'prev') {
|
if (ratio > (1 - params.longSwipesRatio)) swiper.slideTo(stopIndex + increment);
|
else swiper.slideTo(stopIndex);
|
}
|
} else {
|
// Short swipes
|
if (!params.shortSwipes) {
|
swiper.slideTo(swiper.activeIndex);
|
return;
|
}
|
const isNavButtonTarget = swiper.navigation && (e.target === swiper.navigation.nextEl || e.target === swiper.navigation.prevEl);
|
if (!isNavButtonTarget) {
|
if (swiper.swipeDirection === 'next') {
|
swiper.slideTo(stopIndex + increment);
|
}
|
if (swiper.swipeDirection === 'prev') {
|
swiper.slideTo(stopIndex);
|
}
|
} else if (e.target === swiper.navigation.nextEl) {
|
swiper.slideTo(stopIndex + increment);
|
} else {
|
swiper.slideTo(stopIndex);
|
}
|
}
|
}
|