1 |
|
2 | import { getWindow } from 'ssr-window';
|
3 | import $ from '../../shared/dom.js';
|
4 | import { now, nextTick } from '../../shared/utils.js';
|
5 | export default function Mousewheel({
|
6 | swiper,
|
7 | extendParams,
|
8 | on,
|
9 | emit
|
10 | }) {
|
11 | const window = getWindow();
|
12 | extendParams({
|
13 | mousewheel: {
|
14 | enabled: false,
|
15 | releaseOnEdges: false,
|
16 | invert: false,
|
17 | forceToAxis: false,
|
18 | sensitivity: 1,
|
19 | eventsTarget: 'container',
|
20 | thresholdDelta: null,
|
21 | thresholdTime: null
|
22 | }
|
23 | });
|
24 | swiper.mousewheel = {
|
25 | enabled: false
|
26 | };
|
27 | let timeout;
|
28 | let lastScrollTime = now();
|
29 | let lastEventBeforeSnap;
|
30 | const recentWheelEvents = [];
|
31 |
|
32 | function normalize(e) {
|
33 |
|
34 | const PIXEL_STEP = 10;
|
35 | const LINE_HEIGHT = 40;
|
36 | const PAGE_HEIGHT = 800;
|
37 | let sX = 0;
|
38 | let sY = 0;
|
39 |
|
40 | let pX = 0;
|
41 | let pY = 0;
|
42 |
|
43 |
|
44 | if ('detail' in e) {
|
45 | sY = e.detail;
|
46 | }
|
47 |
|
48 | if ('wheelDelta' in e) {
|
49 | sY = -e.wheelDelta / 120;
|
50 | }
|
51 |
|
52 | if ('wheelDeltaY' in e) {
|
53 | sY = -e.wheelDeltaY / 120;
|
54 | }
|
55 |
|
56 | if ('wheelDeltaX' in e) {
|
57 | sX = -e.wheelDeltaX / 120;
|
58 | }
|
59 |
|
60 |
|
61 | if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) {
|
62 | sX = sY;
|
63 | sY = 0;
|
64 | }
|
65 |
|
66 | pX = sX * PIXEL_STEP;
|
67 | pY = sY * PIXEL_STEP;
|
68 |
|
69 | if ('deltaY' in e) {
|
70 | pY = e.deltaY;
|
71 | }
|
72 |
|
73 | if ('deltaX' in e) {
|
74 | pX = e.deltaX;
|
75 | }
|
76 |
|
77 | if (e.shiftKey && !pX) {
|
78 |
|
79 | pX = pY;
|
80 | pY = 0;
|
81 | }
|
82 |
|
83 | if ((pX || pY) && e.deltaMode) {
|
84 | if (e.deltaMode === 1) {
|
85 |
|
86 | pX *= LINE_HEIGHT;
|
87 | pY *= LINE_HEIGHT;
|
88 | } else {
|
89 |
|
90 | pX *= PAGE_HEIGHT;
|
91 | pY *= PAGE_HEIGHT;
|
92 | }
|
93 | }
|
94 |
|
95 |
|
96 | if (pX && !sX) {
|
97 | sX = pX < 1 ? -1 : 1;
|
98 | }
|
99 |
|
100 | if (pY && !sY) {
|
101 | sY = pY < 1 ? -1 : 1;
|
102 | }
|
103 |
|
104 | return {
|
105 | spinX: sX,
|
106 | spinY: sY,
|
107 | pixelX: pX,
|
108 | pixelY: pY
|
109 | };
|
110 | }
|
111 |
|
112 | function handleMouseEnter() {
|
113 | if (!swiper.enabled) return;
|
114 | swiper.mouseEntered = true;
|
115 | }
|
116 |
|
117 | function handleMouseLeave() {
|
118 | if (!swiper.enabled) return;
|
119 | swiper.mouseEntered = false;
|
120 | }
|
121 |
|
122 | function animateSlider(newEvent) {
|
123 | if (swiper.params.mousewheel.thresholdDelta && newEvent.delta < swiper.params.mousewheel.thresholdDelta) {
|
124 |
|
125 | return false;
|
126 | }
|
127 |
|
128 | if (swiper.params.mousewheel.thresholdTime && now() - lastScrollTime < swiper.params.mousewheel.thresholdTime) {
|
129 |
|
130 | return false;
|
131 | }
|
132 |
|
133 |
|
134 |
|
135 |
|
136 | if (newEvent.delta >= 6 && now() - lastScrollTime < 60) {
|
137 |
|
138 | return true;
|
139 | }
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | if (newEvent.direction < 0) {
|
154 | if ((!swiper.isEnd || swiper.params.loop) && !swiper.animating) {
|
155 | swiper.slideNext();
|
156 | emit('scroll', newEvent.raw);
|
157 | }
|
158 | } else if ((!swiper.isBeginning || swiper.params.loop) && !swiper.animating) {
|
159 | swiper.slidePrev();
|
160 | emit('scroll', newEvent.raw);
|
161 | }
|
162 |
|
163 |
|
164 | lastScrollTime = new window.Date().getTime();
|
165 |
|
166 | return false;
|
167 | }
|
168 |
|
169 | function releaseScroll(newEvent) {
|
170 | const params = swiper.params.mousewheel;
|
171 |
|
172 | if (newEvent.direction < 0) {
|
173 | if (swiper.isEnd && !swiper.params.loop && params.releaseOnEdges) {
|
174 |
|
175 | return true;
|
176 | }
|
177 | } else if (swiper.isBeginning && !swiper.params.loop && params.releaseOnEdges) {
|
178 |
|
179 | return true;
|
180 | }
|
181 |
|
182 | return false;
|
183 | }
|
184 |
|
185 | function handle(event) {
|
186 | let e = event;
|
187 | let disableParentSwiper = true;
|
188 | if (!swiper.enabled) return;
|
189 | const params = swiper.params.mousewheel;
|
190 |
|
191 | if (swiper.params.cssMode) {
|
192 | e.preventDefault();
|
193 | }
|
194 |
|
195 | let target = swiper.$el;
|
196 |
|
197 | if (swiper.params.mousewheel.eventsTarget !== 'container') {
|
198 | target = $(swiper.params.mousewheel.eventsTarget);
|
199 | }
|
200 |
|
201 | if (!swiper.mouseEntered && !target[0].contains(e.target) && !params.releaseOnEdges) return true;
|
202 | if (e.originalEvent) e = e.originalEvent;
|
203 |
|
204 | let delta = 0;
|
205 | const rtlFactor = swiper.rtlTranslate ? -1 : 1;
|
206 | const data = normalize(e);
|
207 |
|
208 | if (params.forceToAxis) {
|
209 | if (swiper.isHorizontal()) {
|
210 | if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = -data.pixelX * rtlFactor;else return true;
|
211 | } else if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = -data.pixelY;else return true;
|
212 | } else {
|
213 | delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? -data.pixelX * rtlFactor : -data.pixelY;
|
214 | }
|
215 |
|
216 | if (delta === 0) return true;
|
217 | if (params.invert) delta = -delta;
|
218 |
|
219 | let positions = swiper.getTranslate() + delta * params.sensitivity;
|
220 | if (positions >= swiper.minTranslate()) positions = swiper.minTranslate();
|
221 | if (positions <= swiper.maxTranslate()) positions = swiper.maxTranslate();
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 | disableParentSwiper = swiper.params.loop ? true : !(positions === swiper.minTranslate() || positions === swiper.maxTranslate());
|
230 | if (disableParentSwiper && swiper.params.nested) e.stopPropagation();
|
231 |
|
232 | if (!swiper.params.freeMode || !swiper.params.freeMode.enabled) {
|
233 |
|
234 | const newEvent = {
|
235 | time: now(),
|
236 | delta: Math.abs(delta),
|
237 | direction: Math.sign(delta),
|
238 | raw: event
|
239 | };
|
240 |
|
241 | if (recentWheelEvents.length >= 2) {
|
242 | recentWheelEvents.shift();
|
243 | }
|
244 |
|
245 | const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;
|
246 | recentWheelEvents.push(newEvent);
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | if (prevEvent) {
|
254 | if (newEvent.direction !== prevEvent.direction || newEvent.delta > prevEvent.delta || newEvent.time > prevEvent.time + 150) {
|
255 | animateSlider(newEvent);
|
256 | }
|
257 | } else {
|
258 | animateSlider(newEvent);
|
259 | }
|
260 |
|
261 |
|
262 |
|
263 | if (releaseScroll(newEvent)) {
|
264 | return true;
|
265 | }
|
266 | } else {
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | const newEvent = {
|
273 | time: now(),
|
274 | delta: Math.abs(delta),
|
275 | direction: Math.sign(delta)
|
276 | };
|
277 | const ignoreWheelEvents = lastEventBeforeSnap && newEvent.time < lastEventBeforeSnap.time + 500 && newEvent.delta <= lastEventBeforeSnap.delta && newEvent.direction === lastEventBeforeSnap.direction;
|
278 |
|
279 | if (!ignoreWheelEvents) {
|
280 | lastEventBeforeSnap = undefined;
|
281 |
|
282 | if (swiper.params.loop) {
|
283 | swiper.loopFix();
|
284 | }
|
285 |
|
286 | let position = swiper.getTranslate() + delta * params.sensitivity;
|
287 | const wasBeginning = swiper.isBeginning;
|
288 | const wasEnd = swiper.isEnd;
|
289 | if (position >= swiper.minTranslate()) position = swiper.minTranslate();
|
290 | if (position <= swiper.maxTranslate()) position = swiper.maxTranslate();
|
291 | swiper.setTransition(0);
|
292 | swiper.setTranslate(position);
|
293 | swiper.updateProgress();
|
294 | swiper.updateActiveIndex();
|
295 | swiper.updateSlidesClasses();
|
296 |
|
297 | if (!wasBeginning && swiper.isBeginning || !wasEnd && swiper.isEnd) {
|
298 | swiper.updateSlidesClasses();
|
299 | }
|
300 |
|
301 | if (swiper.params.freeMode.sticky) {
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 | clearTimeout(timeout);
|
314 | timeout = undefined;
|
315 |
|
316 | if (recentWheelEvents.length >= 15) {
|
317 | recentWheelEvents.shift();
|
318 | }
|
319 |
|
320 | const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;
|
321 | const firstEvent = recentWheelEvents[0];
|
322 | recentWheelEvents.push(newEvent);
|
323 |
|
324 | if (prevEvent && (newEvent.delta > prevEvent.delta || newEvent.direction !== prevEvent.direction)) {
|
325 |
|
326 | recentWheelEvents.splice(0);
|
327 | } else if (recentWheelEvents.length >= 15 && newEvent.time - firstEvent.time < 500 && firstEvent.delta - newEvent.delta >= 1 && newEvent.delta <= 6) {
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | const snapToThreshold = delta > 0 ? 0.8 : 0.2;
|
335 | lastEventBeforeSnap = newEvent;
|
336 | recentWheelEvents.splice(0);
|
337 | timeout = nextTick(() => {
|
338 | swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);
|
339 | }, 0);
|
340 | }
|
341 |
|
342 | if (!timeout) {
|
343 |
|
344 |
|
345 |
|
346 | timeout = nextTick(() => {
|
347 | const snapToThreshold = 0.5;
|
348 | lastEventBeforeSnap = newEvent;
|
349 | recentWheelEvents.splice(0);
|
350 | swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);
|
351 | }, 500);
|
352 | }
|
353 | }
|
354 |
|
355 |
|
356 | if (!ignoreWheelEvents) emit('scroll', e);
|
357 |
|
358 | if (swiper.params.autoplay && swiper.params.autoplayDisableOnInteraction) swiper.autoplay.stop();
|
359 |
|
360 | if (position === swiper.minTranslate() || position === swiper.maxTranslate()) return true;
|
361 | }
|
362 | }
|
363 |
|
364 | if (e.preventDefault) e.preventDefault();else e.returnValue = false;
|
365 | return false;
|
366 | }
|
367 |
|
368 | function events(method) {
|
369 | let target = swiper.$el;
|
370 |
|
371 | if (swiper.params.mousewheel.eventsTarget !== 'container') {
|
372 | target = $(swiper.params.mousewheel.eventsTarget);
|
373 | }
|
374 |
|
375 | target[method]('mouseenter', handleMouseEnter);
|
376 | target[method]('mouseleave', handleMouseLeave);
|
377 | target[method]('wheel', handle);
|
378 | }
|
379 |
|
380 | function enable() {
|
381 | if (swiper.params.cssMode) {
|
382 | swiper.wrapperEl.removeEventListener('wheel', handle);
|
383 | return true;
|
384 | }
|
385 |
|
386 | if (swiper.mousewheel.enabled) return false;
|
387 | events('on');
|
388 | swiper.mousewheel.enabled = true;
|
389 | return true;
|
390 | }
|
391 |
|
392 | function disable() {
|
393 | if (swiper.params.cssMode) {
|
394 | swiper.wrapperEl.addEventListener(event, handle);
|
395 | return true;
|
396 | }
|
397 |
|
398 | if (!swiper.mousewheel.enabled) return false;
|
399 | events('off');
|
400 | swiper.mousewheel.enabled = false;
|
401 | return true;
|
402 | }
|
403 |
|
404 | on('init', () => {
|
405 | if (!swiper.params.mousewheel.enabled && swiper.params.cssMode) {
|
406 | disable();
|
407 | }
|
408 |
|
409 | if (swiper.params.mousewheel.enabled) enable();
|
410 | });
|
411 | on('destroy', () => {
|
412 | if (swiper.params.cssMode) {
|
413 | enable();
|
414 | }
|
415 |
|
416 | if (swiper.mousewheel.enabled) disable();
|
417 | });
|
418 | Object.assign(swiper.mousewheel, {
|
419 | enable,
|
420 | disable
|
421 | });
|
422 | } |
\ | No newline at end of file |