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(_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 |