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