import { window, document } from 'ssr-window'; import $ from '../../utils/dom'; import Utils from '../../utils/utils'; function isEventSupported() { const eventName = 'onwheel'; let isSupported = eventName in document; if (!isSupported) { const element = document.createElement('div'); element.setAttribute(eventName, 'return;'); isSupported = typeof element[eventName] === 'function'; } if (!isSupported && document.implementation && document.implementation.hasFeature // always returns true in newer browsers as per the standard. // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature && document.implementation.hasFeature('', '') !== true ) { // This is the only way to test support for the `wheel` event in IE9+. isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); } return isSupported; } const Mousewheel = { lastScrollTime: Utils.now(), event: (function getEvent() { if (window.navigator.userAgent.indexOf('firefox') > -1) return 'DOMMouseScroll'; return isEventSupported() ? 'wheel' : 'mousewheel'; }()), normalize(e) { // Reasonable defaults const PIXEL_STEP = 10; const LINE_HEIGHT = 40; const PAGE_HEIGHT = 800; let sX = 0; let sY = 0; // spinX, spinY let pX = 0; let pY = 0; // pixelX, pixelY // Legacy if ('detail' in e) { sY = e.detail; } if ('wheelDelta' in e) { sY = -e.wheelDelta / 120; } if ('wheelDeltaY' in e) { sY = -e.wheelDeltaY / 120; } if ('wheelDeltaX' in e) { sX = -e.wheelDeltaX / 120; } // side scrolling on FF with DOMMouseScroll if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) { sX = sY; sY = 0; } pX = sX * PIXEL_STEP; pY = sY * PIXEL_STEP; if ('deltaY' in e) { pY = e.deltaY; } if ('deltaX' in e) { pX = e.deltaX; } if ((pX || pY) && e.deltaMode) { if (e.deltaMode === 1) { // delta in LINE units pX *= LINE_HEIGHT; pY *= LINE_HEIGHT; } else { // delta in PAGE units pX *= PAGE_HEIGHT; pY *= PAGE_HEIGHT; } } // Fall-back if spin cannot be determined if (pX && !sX) { sX = (pX < 1) ? -1 : 1; } if (pY && !sY) { sY = (pY < 1) ? -1 : 1; } return { spinX: sX, spinY: sY, pixelX: pX, pixelY: pY, }; }, handleMouseEnter() { const swiper = this; swiper.mouseEntered = true; }, handleMouseLeave() { const swiper = this; swiper.mouseEntered = false; }, handle(event) { let e = event; const swiper = this; const params = swiper.params.mousewheel; if (!swiper.mouseEntered && !params.releaseOnEdges) return true; if (e.originalEvent) e = e.originalEvent; // jquery fix let delta = 0; const rtlFactor = swiper.rtlTranslate ? -1 : 1; const data = Mousewheel.normalize(e); if (params.forceToAxis) { if (swiper.isHorizontal()) { if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = data.pixelX * rtlFactor; else return true; } else if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = data.pixelY; else return true; } else { delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? -data.pixelX * rtlFactor : -data.pixelY; } if (delta === 0) return true; if (params.invert) delta = -delta; if (!swiper.params.freeMode) { if (Utils.now() - swiper.mousewheel.lastScrollTime > 60) { if (delta < 0) { if ((!swiper.isEnd || swiper.params.loop) && !swiper.animating) { swiper.slideNext(); swiper.emit('scroll', e); } else if (params.releaseOnEdges) return true; } else if ((!swiper.isBeginning || swiper.params.loop) && !swiper.animating) { swiper.slidePrev(); swiper.emit('scroll', e); } else if (params.releaseOnEdges) return true; } swiper.mousewheel.lastScrollTime = (new window.Date()).getTime(); } else { // Freemode or scrollContainer: if (swiper.params.loop) { swiper.loopFix(); } let position = swiper.getTranslate() + (delta * params.sensitivity); const wasBeginning = swiper.isBeginning; const wasEnd = swiper.isEnd; if (position >= swiper.minTranslate()) position = swiper.minTranslate(); if (position <= swiper.maxTranslate()) position = swiper.maxTranslate(); swiper.setTransition(0); swiper.setTranslate(position); swiper.updateProgress(); swiper.updateActiveIndex(); swiper.updateSlidesClasses(); if ((!wasBeginning && swiper.isBeginning) || (!wasEnd && swiper.isEnd)) { swiper.updateSlidesClasses(); } if (swiper.params.freeModeSticky) { clearTimeout(swiper.mousewheel.timeout); swiper.mousewheel.timeout = Utils.nextTick(() => { swiper.slideToClosest(); }, 300); } // Emit event swiper.emit('scroll', e); // Stop autoplay if (swiper.params.autoplay && swiper.params.autoplayDisableOnInteraction) swiper.autoplay.stop(); // Return page scroll on edge positions if (position === swiper.minTranslate() || position === swiper.maxTranslate()) return true; } if (e.preventDefault) e.preventDefault(); else e.returnValue = false; return false; }, enable() { const swiper = this; if (!Mousewheel.event) return false; if (swiper.mousewheel.enabled) return false; let target = swiper.$el; if (swiper.params.mousewheel.eventsTarged !== 'container') { target = $(swiper.params.mousewheel.eventsTarged); } target.on('mouseenter', swiper.mousewheel.handleMouseEnter); target.on('mouseleave', swiper.mousewheel.handleMouseLeave); target.on(Mousewheel.event, swiper.mousewheel.handle); swiper.mousewheel.enabled = true; return true; }, disable() { const swiper = this; if (!Mousewheel.event) return false; if (!swiper.mousewheel.enabled) return false; let target = swiper.$el; if (swiper.params.mousewheel.eventsTarged !== 'container') { target = $(swiper.params.mousewheel.eventsTarged); } target.off(Mousewheel.event, swiper.mousewheel.handle); swiper.mousewheel.enabled = false; return true; }, }; export default { name: 'mousewheel', params: { mousewheel: { enabled: false, releaseOnEdges: false, invert: false, forceToAxis: false, sensitivity: 1, eventsTarged: 'container', }, }, create() { const swiper = this; Utils.extend(swiper, { mousewheel: { enabled: false, enable: Mousewheel.enable.bind(swiper), disable: Mousewheel.disable.bind(swiper), handle: Mousewheel.handle.bind(swiper), handleMouseEnter: Mousewheel.handleMouseEnter.bind(swiper), handleMouseLeave: Mousewheel.handleMouseLeave.bind(swiper), lastScrollTime: Utils.now(), }, }); }, on: { init() { const swiper = this; if (swiper.params.mousewheel.enabled) swiper.mousewheel.enable(); }, destroy() { const swiper = this; if (swiper.mousewheel.enabled) swiper.mousewheel.disable(); }, }, };