UNPKG

9.26 kBJavaScriptView Raw
1import { getDocument } from 'ssr-window';
2import $ from '../../shared/dom.js';
3import { nextTick } from '../../shared/utils.js';
4import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
5export default function Scrollbar(_ref) {
6 let {
7 swiper,
8 extendParams,
9 on,
10 emit
11 } = _ref;
12 const document = getDocument();
13 let isTouched = false;
14 let timeout = null;
15 let dragTimeout = null;
16 let dragStartPos;
17 let dragSize;
18 let trackSize;
19 let divider;
20 extendParams({
21 scrollbar: {
22 el: null,
23 dragSize: 'auto',
24 hide: false,
25 draggable: false,
26 snapOnRelease: true,
27 lockClass: 'swiper-scrollbar-lock',
28 dragClass: 'swiper-scrollbar-drag'
29 }
30 });
31 swiper.scrollbar = {
32 el: null,
33 dragEl: null,
34 $el: null,
35 $dragEl: null
36 };
37
38 function setTranslate() {
39 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
40 const {
41 scrollbar,
42 rtlTranslate: rtl,
43 progress
44 } = swiper;
45 const {
46 $dragEl,
47 $el
48 } = scrollbar;
49 const params = swiper.params.scrollbar;
50 let newSize = dragSize;
51 let newPos = (trackSize - dragSize) * progress;
52
53 if (rtl) {
54 newPos = -newPos;
55
56 if (newPos > 0) {
57 newSize = dragSize - newPos;
58 newPos = 0;
59 } else if (-newPos + dragSize > trackSize) {
60 newSize = trackSize + newPos;
61 }
62 } else if (newPos < 0) {
63 newSize = dragSize + newPos;
64 newPos = 0;
65 } else if (newPos + dragSize > trackSize) {
66 newSize = trackSize - newPos;
67 }
68
69 if (swiper.isHorizontal()) {
70 $dragEl.transform(`translate3d(${newPos}px, 0, 0)`);
71 $dragEl[0].style.width = `${newSize}px`;
72 } else {
73 $dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);
74 $dragEl[0].style.height = `${newSize}px`;
75 }
76
77 if (params.hide) {
78 clearTimeout(timeout);
79 $el[0].style.opacity = 1;
80 timeout = setTimeout(() => {
81 $el[0].style.opacity = 0;
82 $el.transition(400);
83 }, 1000);
84 }
85 }
86
87 function setTransition(duration) {
88 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
89 swiper.scrollbar.$dragEl.transition(duration);
90 }
91
92 function updateSize() {
93 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
94 const {
95 scrollbar
96 } = swiper;
97 const {
98 $dragEl,
99 $el
100 } = scrollbar;
101 $dragEl[0].style.width = '';
102 $dragEl[0].style.height = '';
103 trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;
104 divider = swiper.size / (swiper.virtualSize + swiper.params.slidesOffsetBefore - (swiper.params.centeredSlides ? swiper.snapGrid[0] : 0));
105
106 if (swiper.params.scrollbar.dragSize === 'auto') {
107 dragSize = trackSize * divider;
108 } else {
109 dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
110 }
111
112 if (swiper.isHorizontal()) {
113 $dragEl[0].style.width = `${dragSize}px`;
114 } else {
115 $dragEl[0].style.height = `${dragSize}px`;
116 }
117
118 if (divider >= 1) {
119 $el[0].style.display = 'none';
120 } else {
121 $el[0].style.display = '';
122 }
123
124 if (swiper.params.scrollbar.hide) {
125 $el[0].style.opacity = 0;
126 }
127
128 if (swiper.params.watchOverflow && swiper.enabled) {
129 scrollbar.$el[swiper.isLocked ? 'addClass' : 'removeClass'](swiper.params.scrollbar.lockClass);
130 }
131 }
132
133 function getPointerPosition(e) {
134 if (swiper.isHorizontal()) {
135 return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientX : e.clientX;
136 }
137
138 return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientY : e.clientY;
139 }
140
141 function setDragPosition(e) {
142 const {
143 scrollbar,
144 rtlTranslate: rtl
145 } = swiper;
146 const {
147 $el
148 } = scrollbar;
149 let positionRatio;
150 positionRatio = (getPointerPosition(e) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top'] - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);
151 positionRatio = Math.max(Math.min(positionRatio, 1), 0);
152
153 if (rtl) {
154 positionRatio = 1 - positionRatio;
155 }
156
157 const position = swiper.minTranslate() + (swiper.maxTranslate() - swiper.minTranslate()) * positionRatio;
158 swiper.updateProgress(position);
159 swiper.setTranslate(position);
160 swiper.updateActiveIndex();
161 swiper.updateSlidesClasses();
162 }
163
164 function onDragStart(e) {
165 const params = swiper.params.scrollbar;
166 const {
167 scrollbar,
168 $wrapperEl
169 } = swiper;
170 const {
171 $el,
172 $dragEl
173 } = scrollbar;
174 isTouched = true;
175 dragStartPos = e.target === $dragEl[0] || e.target === $dragEl ? getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;
176 e.preventDefault();
177 e.stopPropagation();
178 $wrapperEl.transition(100);
179 $dragEl.transition(100);
180 setDragPosition(e);
181 clearTimeout(dragTimeout);
182 $el.transition(0);
183
184 if (params.hide) {
185 $el.css('opacity', 1);
186 }
187
188 if (swiper.params.cssMode) {
189 swiper.$wrapperEl.css('scroll-snap-type', 'none');
190 }
191
192 emit('scrollbarDragStart', e);
193 }
194
195 function onDragMove(e) {
196 const {
197 scrollbar,
198 $wrapperEl
199 } = swiper;
200 const {
201 $el,
202 $dragEl
203 } = scrollbar;
204 if (!isTouched) return;
205 if (e.preventDefault) e.preventDefault();else e.returnValue = false;
206 setDragPosition(e);
207 $wrapperEl.transition(0);
208 $el.transition(0);
209 $dragEl.transition(0);
210 emit('scrollbarDragMove', e);
211 }
212
213 function onDragEnd(e) {
214 const params = swiper.params.scrollbar;
215 const {
216 scrollbar,
217 $wrapperEl
218 } = swiper;
219 const {
220 $el
221 } = scrollbar;
222 if (!isTouched) return;
223 isTouched = false;
224
225 if (swiper.params.cssMode) {
226 swiper.$wrapperEl.css('scroll-snap-type', '');
227 $wrapperEl.transition('');
228 }
229
230 if (params.hide) {
231 clearTimeout(dragTimeout);
232 dragTimeout = nextTick(() => {
233 $el.css('opacity', 0);
234 $el.transition(400);
235 }, 1000);
236 }
237
238 emit('scrollbarDragEnd', e);
239
240 if (params.snapOnRelease) {
241 swiper.slideToClosest();
242 }
243 }
244
245 function events(method) {
246 const {
247 scrollbar,
248 touchEventsTouch,
249 touchEventsDesktop,
250 params,
251 support
252 } = swiper;
253 const $el = scrollbar.$el;
254 const target = $el[0];
255 const activeListener = support.passiveListener && params.passiveListeners ? {
256 passive: false,
257 capture: false
258 } : false;
259 const passiveListener = support.passiveListener && params.passiveListeners ? {
260 passive: true,
261 capture: false
262 } : false;
263 if (!target) return;
264 const eventMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
265
266 if (!support.touch) {
267 target[eventMethod](touchEventsDesktop.start, onDragStart, activeListener);
268 document[eventMethod](touchEventsDesktop.move, onDragMove, activeListener);
269 document[eventMethod](touchEventsDesktop.end, onDragEnd, passiveListener);
270 } else {
271 target[eventMethod](touchEventsTouch.start, onDragStart, activeListener);
272 target[eventMethod](touchEventsTouch.move, onDragMove, activeListener);
273 target[eventMethod](touchEventsTouch.end, onDragEnd, passiveListener);
274 }
275 }
276
277 function enableDraggable() {
278 if (!swiper.params.scrollbar.el) return;
279 events('on');
280 }
281
282 function disableDraggable() {
283 if (!swiper.params.scrollbar.el) return;
284 events('off');
285 }
286
287 function init() {
288 const {
289 scrollbar,
290 $el: $swiperEl
291 } = swiper;
292 swiper.params.scrollbar = createElementIfNotDefined(swiper, swiper.originalParams.scrollbar, swiper.params.scrollbar, {
293 el: 'swiper-scrollbar'
294 });
295 const params = swiper.params.scrollbar;
296 if (!params.el) return;
297 let $el = $(params.el);
298
299 if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {
300 $el = $swiperEl.find(params.el);
301 }
302
303 let $dragEl = $el.find(`.${swiper.params.scrollbar.dragClass}`);
304
305 if ($dragEl.length === 0) {
306 $dragEl = $(`<div class="${swiper.params.scrollbar.dragClass}"></div>`);
307 $el.append($dragEl);
308 }
309
310 Object.assign(scrollbar, {
311 $el,
312 el: $el[0],
313 $dragEl,
314 dragEl: $dragEl[0]
315 });
316
317 if (params.draggable) {
318 enableDraggable();
319 }
320
321 if ($el) {
322 $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
323 }
324 }
325
326 function destroy() {
327 disableDraggable();
328 }
329
330 on('init', () => {
331 init();
332 updateSize();
333 setTranslate();
334 });
335 on('update resize observerUpdate lock unlock', () => {
336 updateSize();
337 });
338 on('setTranslate', () => {
339 setTranslate();
340 });
341 on('setTransition', (_s, duration) => {
342 setTransition(duration);
343 });
344 on('enable disable', () => {
345 const {
346 $el
347 } = swiper.scrollbar;
348
349 if ($el) {
350 $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
351 }
352 });
353 on('destroy', () => {
354 destroy();
355 });
356 Object.assign(swiper.scrollbar, {
357 updateSize,
358 setTranslate,
359 init,
360 destroy
361 });
362}
\No newline at end of file