361 lines
No EOL
9 KiB
JavaScript
361 lines
No EOL
9 KiB
JavaScript
import { getDocument } from 'ssr-window';
|
|
import $ from '../../shared/dom.js';
|
|
import { nextTick } from '../../shared/utils.js';
|
|
import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
|
|
export default function Scrollbar({
|
|
swiper,
|
|
extendParams,
|
|
on,
|
|
emit
|
|
}) {
|
|
const document = getDocument();
|
|
let isTouched = false;
|
|
let timeout = null;
|
|
let dragTimeout = null;
|
|
let dragStartPos;
|
|
let dragSize;
|
|
let trackSize;
|
|
let divider;
|
|
extendParams({
|
|
scrollbar: {
|
|
el: null,
|
|
dragSize: 'auto',
|
|
hide: false,
|
|
draggable: false,
|
|
snapOnRelease: true,
|
|
lockClass: 'swiper-scrollbar-lock',
|
|
dragClass: 'swiper-scrollbar-drag'
|
|
}
|
|
});
|
|
swiper.scrollbar = {
|
|
el: null,
|
|
dragEl: null,
|
|
$el: null,
|
|
$dragEl: null
|
|
};
|
|
|
|
function setTranslate() {
|
|
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
|
|
const {
|
|
scrollbar,
|
|
rtlTranslate: rtl,
|
|
progress
|
|
} = swiper;
|
|
const {
|
|
$dragEl,
|
|
$el
|
|
} = scrollbar;
|
|
const params = swiper.params.scrollbar;
|
|
let newSize = dragSize;
|
|
let newPos = (trackSize - dragSize) * progress;
|
|
|
|
if (rtl) {
|
|
newPos = -newPos;
|
|
|
|
if (newPos > 0) {
|
|
newSize = dragSize - newPos;
|
|
newPos = 0;
|
|
} else if (-newPos + dragSize > trackSize) {
|
|
newSize = trackSize + newPos;
|
|
}
|
|
} else if (newPos < 0) {
|
|
newSize = dragSize + newPos;
|
|
newPos = 0;
|
|
} else if (newPos + dragSize > trackSize) {
|
|
newSize = trackSize - newPos;
|
|
}
|
|
|
|
if (swiper.isHorizontal()) {
|
|
$dragEl.transform(`translate3d(${newPos}px, 0, 0)`);
|
|
$dragEl[0].style.width = `${newSize}px`;
|
|
} else {
|
|
$dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);
|
|
$dragEl[0].style.height = `${newSize}px`;
|
|
}
|
|
|
|
if (params.hide) {
|
|
clearTimeout(timeout);
|
|
$el[0].style.opacity = 1;
|
|
timeout = setTimeout(() => {
|
|
$el[0].style.opacity = 0;
|
|
$el.transition(400);
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
function setTransition(duration) {
|
|
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
|
|
swiper.scrollbar.$dragEl.transition(duration);
|
|
}
|
|
|
|
function updateSize() {
|
|
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
|
|
const {
|
|
scrollbar
|
|
} = swiper;
|
|
const {
|
|
$dragEl,
|
|
$el
|
|
} = scrollbar;
|
|
$dragEl[0].style.width = '';
|
|
$dragEl[0].style.height = '';
|
|
trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;
|
|
divider = swiper.size / (swiper.virtualSize + swiper.params.slidesOffsetBefore - (swiper.params.centeredSlides ? swiper.snapGrid[0] : 0));
|
|
|
|
if (swiper.params.scrollbar.dragSize === 'auto') {
|
|
dragSize = trackSize * divider;
|
|
} else {
|
|
dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
|
|
}
|
|
|
|
if (swiper.isHorizontal()) {
|
|
$dragEl[0].style.width = `${dragSize}px`;
|
|
} else {
|
|
$dragEl[0].style.height = `${dragSize}px`;
|
|
}
|
|
|
|
if (divider >= 1) {
|
|
$el[0].style.display = 'none';
|
|
} else {
|
|
$el[0].style.display = '';
|
|
}
|
|
|
|
if (swiper.params.scrollbar.hide) {
|
|
$el[0].style.opacity = 0;
|
|
}
|
|
|
|
if (swiper.params.watchOverflow && swiper.enabled) {
|
|
scrollbar.$el[swiper.isLocked ? 'addClass' : 'removeClass'](swiper.params.scrollbar.lockClass);
|
|
}
|
|
}
|
|
|
|
function getPointerPosition(e) {
|
|
if (swiper.isHorizontal()) {
|
|
return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientX : e.clientX;
|
|
}
|
|
|
|
return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientY : e.clientY;
|
|
}
|
|
|
|
function setDragPosition(e) {
|
|
const {
|
|
scrollbar,
|
|
rtlTranslate: rtl
|
|
} = swiper;
|
|
const {
|
|
$el
|
|
} = scrollbar;
|
|
let positionRatio;
|
|
positionRatio = (getPointerPosition(e) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top'] - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);
|
|
positionRatio = Math.max(Math.min(positionRatio, 1), 0);
|
|
|
|
if (rtl) {
|
|
positionRatio = 1 - positionRatio;
|
|
}
|
|
|
|
const position = swiper.minTranslate() + (swiper.maxTranslate() - swiper.minTranslate()) * positionRatio;
|
|
swiper.updateProgress(position);
|
|
swiper.setTranslate(position);
|
|
swiper.updateActiveIndex();
|
|
swiper.updateSlidesClasses();
|
|
}
|
|
|
|
function onDragStart(e) {
|
|
const params = swiper.params.scrollbar;
|
|
const {
|
|
scrollbar,
|
|
$wrapperEl
|
|
} = swiper;
|
|
const {
|
|
$el,
|
|
$dragEl
|
|
} = scrollbar;
|
|
isTouched = true;
|
|
dragStartPos = e.target === $dragEl[0] || e.target === $dragEl ? getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
$wrapperEl.transition(100);
|
|
$dragEl.transition(100);
|
|
setDragPosition(e);
|
|
clearTimeout(dragTimeout);
|
|
$el.transition(0);
|
|
|
|
if (params.hide) {
|
|
$el.css('opacity', 1);
|
|
}
|
|
|
|
if (swiper.params.cssMode) {
|
|
swiper.$wrapperEl.css('scroll-snap-type', 'none');
|
|
}
|
|
|
|
emit('scrollbarDragStart', e);
|
|
}
|
|
|
|
function onDragMove(e) {
|
|
const {
|
|
scrollbar,
|
|
$wrapperEl
|
|
} = swiper;
|
|
const {
|
|
$el,
|
|
$dragEl
|
|
} = scrollbar;
|
|
if (!isTouched) return;
|
|
if (e.preventDefault) e.preventDefault();else e.returnValue = false;
|
|
setDragPosition(e);
|
|
$wrapperEl.transition(0);
|
|
$el.transition(0);
|
|
$dragEl.transition(0);
|
|
emit('scrollbarDragMove', e);
|
|
}
|
|
|
|
function onDragEnd(e) {
|
|
const params = swiper.params.scrollbar;
|
|
const {
|
|
scrollbar,
|
|
$wrapperEl
|
|
} = swiper;
|
|
const {
|
|
$el
|
|
} = scrollbar;
|
|
if (!isTouched) return;
|
|
isTouched = false;
|
|
|
|
if (swiper.params.cssMode) {
|
|
swiper.$wrapperEl.css('scroll-snap-type', '');
|
|
$wrapperEl.transition('');
|
|
}
|
|
|
|
if (params.hide) {
|
|
clearTimeout(dragTimeout);
|
|
dragTimeout = nextTick(() => {
|
|
$el.css('opacity', 0);
|
|
$el.transition(400);
|
|
}, 1000);
|
|
}
|
|
|
|
emit('scrollbarDragEnd', e);
|
|
|
|
if (params.snapOnRelease) {
|
|
swiper.slideToClosest();
|
|
}
|
|
}
|
|
|
|
function events(method) {
|
|
const {
|
|
scrollbar,
|
|
touchEventsTouch,
|
|
touchEventsDesktop,
|
|
params,
|
|
support
|
|
} = swiper;
|
|
const $el = scrollbar.$el;
|
|
const target = $el[0];
|
|
const activeListener = support.passiveListener && params.passiveListeners ? {
|
|
passive: false,
|
|
capture: false
|
|
} : false;
|
|
const passiveListener = support.passiveListener && params.passiveListeners ? {
|
|
passive: true,
|
|
capture: false
|
|
} : false;
|
|
if (!target) return;
|
|
const eventMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
|
|
|
|
if (!support.touch) {
|
|
target[eventMethod](touchEventsDesktop.start, onDragStart, activeListener);
|
|
document[eventMethod](touchEventsDesktop.move, onDragMove, activeListener);
|
|
document[eventMethod](touchEventsDesktop.end, onDragEnd, passiveListener);
|
|
} else {
|
|
target[eventMethod](touchEventsTouch.start, onDragStart, activeListener);
|
|
target[eventMethod](touchEventsTouch.move, onDragMove, activeListener);
|
|
target[eventMethod](touchEventsTouch.end, onDragEnd, passiveListener);
|
|
}
|
|
}
|
|
|
|
function enableDraggable() {
|
|
if (!swiper.params.scrollbar.el) return;
|
|
events('on');
|
|
}
|
|
|
|
function disableDraggable() {
|
|
if (!swiper.params.scrollbar.el) return;
|
|
events('off');
|
|
}
|
|
|
|
function init() {
|
|
const {
|
|
scrollbar,
|
|
$el: $swiperEl
|
|
} = swiper;
|
|
swiper.params.scrollbar = createElementIfNotDefined(swiper, swiper.originalParams.scrollbar, swiper.params.scrollbar, {
|
|
el: 'swiper-scrollbar'
|
|
});
|
|
const params = swiper.params.scrollbar;
|
|
if (!params.el) return;
|
|
let $el = $(params.el);
|
|
|
|
if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {
|
|
$el = $swiperEl.find(params.el);
|
|
}
|
|
|
|
let $dragEl = $el.find(`.${swiper.params.scrollbar.dragClass}`);
|
|
|
|
if ($dragEl.length === 0) {
|
|
$dragEl = $(`<div class="${swiper.params.scrollbar.dragClass}"></div>`);
|
|
$el.append($dragEl);
|
|
}
|
|
|
|
Object.assign(scrollbar, {
|
|
$el,
|
|
el: $el[0],
|
|
$dragEl,
|
|
dragEl: $dragEl[0]
|
|
});
|
|
|
|
if (params.draggable) {
|
|
enableDraggable();
|
|
}
|
|
|
|
if ($el) {
|
|
$el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
|
|
}
|
|
}
|
|
|
|
function destroy() {
|
|
disableDraggable();
|
|
}
|
|
|
|
on('init', () => {
|
|
init();
|
|
updateSize();
|
|
setTranslate();
|
|
});
|
|
on('update resize observerUpdate lock unlock', () => {
|
|
updateSize();
|
|
});
|
|
on('setTranslate', () => {
|
|
setTranslate();
|
|
});
|
|
on('setTransition', (_s, duration) => {
|
|
setTransition(duration);
|
|
});
|
|
on('enable disable', () => {
|
|
const {
|
|
$el
|
|
} = swiper.scrollbar;
|
|
|
|
if ($el) {
|
|
$el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
|
|
}
|
|
});
|
|
on('destroy', () => {
|
|
destroy();
|
|
});
|
|
Object.assign(swiper.scrollbar, {
|
|
updateSize,
|
|
setTranslate,
|
|
init,
|
|
destroy
|
|
});
|
|
} |