UNPKG

swiper

Version:

Most modern mobile touch slider and framework with hardware accelerated transitions

606 lines (538 loc) 22.2 kB
"use strict"; exports.__esModule = true; exports.default = void 0; var _dom = _interopRequireDefault(require("../../utils/dom")); var _utils = require("../../utils/utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } var Zoom = { // Calc Scale From Multi-touches getDistanceBetweenTouches: function getDistanceBetweenTouches(e) { if (e.targetTouches.length < 2) return 1; var x1 = e.targetTouches[0].pageX; var y1 = e.targetTouches[0].pageY; var x2 = e.targetTouches[1].pageX; var y2 = e.targetTouches[1].pageY; var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); return distance; }, // Events onGestureStart: function onGestureStart(e) { var swiper = this; var support = swiper.support; var params = swiper.params.zoom; var zoom = swiper.zoom; var gesture = zoom.gesture; zoom.fakeGestureTouched = false; zoom.fakeGestureMoved = false; if (!support.gestures) { if (e.type !== 'touchstart' || e.type === 'touchstart' && e.targetTouches.length < 2) { return; } zoom.fakeGestureTouched = true; gesture.scaleStart = Zoom.getDistanceBetweenTouches(e); } if (!gesture.$slideEl || !gesture.$slideEl.length) { gesture.$slideEl = (0, _dom.default)(e.target).closest("." + swiper.params.slideClass); if (gesture.$slideEl.length === 0) gesture.$slideEl = swiper.slides.eq(swiper.activeIndex); gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target'); gesture.$imageWrapEl = gesture.$imageEl.parent("." + params.containerClass); gesture.maxRatio = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio; if (gesture.$imageWrapEl.length === 0) { gesture.$imageEl = undefined; return; } } if (gesture.$imageEl) { gesture.$imageEl.transition(0); } swiper.zoom.isScaling = true; }, onGestureChange: function onGestureChange(e) { var swiper = this; var support = swiper.support; var params = swiper.params.zoom; var zoom = swiper.zoom; var gesture = zoom.gesture; if (!support.gestures) { if (e.type !== 'touchmove' || e.type === 'touchmove' && e.targetTouches.length < 2) { return; } zoom.fakeGestureMoved = true; gesture.scaleMove = Zoom.getDistanceBetweenTouches(e); } if (!gesture.$imageEl || gesture.$imageEl.length === 0) { if (e.type === 'gesturechange') zoom.onGestureStart(e); return; } if (support.gestures) { zoom.scale = e.scale * zoom.currentScale; } else { zoom.scale = gesture.scaleMove / gesture.scaleStart * zoom.currentScale; } if (zoom.scale > gesture.maxRatio) { zoom.scale = gesture.maxRatio - 1 + Math.pow(zoom.scale - gesture.maxRatio + 1, 0.5); } if (zoom.scale < params.minRatio) { zoom.scale = params.minRatio + 1 - Math.pow(params.minRatio - zoom.scale + 1, 0.5); } gesture.$imageEl.transform("translate3d(0,0,0) scale(" + zoom.scale + ")"); }, onGestureEnd: function onGestureEnd(e) { var swiper = this; var device = swiper.device; var support = swiper.support; var params = swiper.params.zoom; var zoom = swiper.zoom; var gesture = zoom.gesture; if (!support.gestures) { if (!zoom.fakeGestureTouched || !zoom.fakeGestureMoved) { return; } if (e.type !== 'touchend' || e.type === 'touchend' && e.changedTouches.length < 2 && !device.android) { return; } zoom.fakeGestureTouched = false; zoom.fakeGestureMoved = false; } if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio); gesture.$imageEl.transition(swiper.params.speed).transform("translate3d(0,0,0) scale(" + zoom.scale + ")"); zoom.currentScale = zoom.scale; zoom.isScaling = false; if (zoom.scale === 1) gesture.$slideEl = undefined; }, onTouchStart: function onTouchStart(e) { var swiper = this; var device = swiper.device; var zoom = swiper.zoom; var gesture = zoom.gesture, image = zoom.image; if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; if (image.isTouched) return; if (device.android && e.cancelable) e.preventDefault(); image.isTouched = true; image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; }, onTouchMove: function onTouchMove(e) { var swiper = this; var zoom = swiper.zoom; var gesture = zoom.gesture, image = zoom.image, velocity = zoom.velocity; if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; swiper.allowClick = false; if (!image.isTouched || !gesture.$slideEl) return; if (!image.isMoved) { image.width = gesture.$imageEl[0].offsetWidth; image.height = gesture.$imageEl[0].offsetHeight; image.startX = (0, _utils.getTranslate)(gesture.$imageWrapEl[0], 'x') || 0; image.startY = (0, _utils.getTranslate)(gesture.$imageWrapEl[0], 'y') || 0; gesture.slideWidth = gesture.$slideEl[0].offsetWidth; gesture.slideHeight = gesture.$slideEl[0].offsetHeight; gesture.$imageWrapEl.transition(0); if (swiper.rtl) { image.startX = -image.startX; image.startY = -image.startY; } } // Define if we need image drag var scaledWidth = image.width * zoom.scale; var scaledHeight = image.height * zoom.scale; if (scaledWidth < gesture.slideWidth && scaledHeight < gesture.slideHeight) return; image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0); image.maxX = -image.minX; image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0); image.maxY = -image.minY; image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; if (!image.isMoved && !zoom.isScaling) { if (swiper.isHorizontal() && (Math.floor(image.minX) === Math.floor(image.startX) && image.touchesCurrent.x < image.touchesStart.x || Math.floor(image.maxX) === Math.floor(image.startX) && image.touchesCurrent.x > image.touchesStart.x)) { image.isTouched = false; return; } if (!swiper.isHorizontal() && (Math.floor(image.minY) === Math.floor(image.startY) && image.touchesCurrent.y < image.touchesStart.y || Math.floor(image.maxY) === Math.floor(image.startY) && image.touchesCurrent.y > image.touchesStart.y)) { image.isTouched = false; return; } } if (e.cancelable) { e.preventDefault(); } e.stopPropagation(); image.isMoved = true; image.currentX = image.touchesCurrent.x - image.touchesStart.x + image.startX; image.currentY = image.touchesCurrent.y - image.touchesStart.y + image.startY; if (image.currentX < image.minX) { image.currentX = image.minX + 1 - Math.pow(image.minX - image.currentX + 1, 0.8); } if (image.currentX > image.maxX) { image.currentX = image.maxX - 1 + Math.pow(image.currentX - image.maxX + 1, 0.8); } if (image.currentY < image.minY) { image.currentY = image.minY + 1 - Math.pow(image.minY - image.currentY + 1, 0.8); } if (image.currentY > image.maxY) { image.currentY = image.maxY - 1 + Math.pow(image.currentY - image.maxY + 1, 0.8); } // Velocity if (!velocity.prevPositionX) velocity.prevPositionX = image.touchesCurrent.x; if (!velocity.prevPositionY) velocity.prevPositionY = image.touchesCurrent.y; if (!velocity.prevTime) velocity.prevTime = Date.now(); velocity.x = (image.touchesCurrent.x - velocity.prevPositionX) / (Date.now() - velocity.prevTime) / 2; velocity.y = (image.touchesCurrent.y - velocity.prevPositionY) / (Date.now() - velocity.prevTime) / 2; if (Math.abs(image.touchesCurrent.x - velocity.prevPositionX) < 2) velocity.x = 0; if (Math.abs(image.touchesCurrent.y - velocity.prevPositionY) < 2) velocity.y = 0; velocity.prevPositionX = image.touchesCurrent.x; velocity.prevPositionY = image.touchesCurrent.y; velocity.prevTime = Date.now(); gesture.$imageWrapEl.transform("translate3d(" + image.currentX + "px, " + image.currentY + "px,0)"); }, onTouchEnd: function onTouchEnd() { var swiper = this; var zoom = swiper.zoom; var gesture = zoom.gesture, image = zoom.image, velocity = zoom.velocity; if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; if (!image.isTouched || !image.isMoved) { image.isTouched = false; image.isMoved = false; return; } image.isTouched = false; image.isMoved = false; var momentumDurationX = 300; var momentumDurationY = 300; var momentumDistanceX = velocity.x * momentumDurationX; var newPositionX = image.currentX + momentumDistanceX; var momentumDistanceY = velocity.y * momentumDurationY; var newPositionY = image.currentY + momentumDistanceY; // Fix duration if (velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - image.currentX) / velocity.x); if (velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - image.currentY) / velocity.y); var momentumDuration = Math.max(momentumDurationX, momentumDurationY); image.currentX = newPositionX; image.currentY = newPositionY; // Define if we need image drag var scaledWidth = image.width * zoom.scale; var scaledHeight = image.height * zoom.scale; image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0); image.maxX = -image.minX; image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0); image.maxY = -image.minY; image.currentX = Math.max(Math.min(image.currentX, image.maxX), image.minX); image.currentY = Math.max(Math.min(image.currentY, image.maxY), image.minY); gesture.$imageWrapEl.transition(momentumDuration).transform("translate3d(" + image.currentX + "px, " + image.currentY + "px,0)"); }, onTransitionEnd: function onTransitionEnd() { var swiper = this; var zoom = swiper.zoom; var gesture = zoom.gesture; if (gesture.$slideEl && swiper.previousIndex !== swiper.activeIndex) { if (gesture.$imageEl) { gesture.$imageEl.transform('translate3d(0,0,0) scale(1)'); } if (gesture.$imageWrapEl) { gesture.$imageWrapEl.transform('translate3d(0,0,0)'); } zoom.scale = 1; zoom.currentScale = 1; gesture.$slideEl = undefined; gesture.$imageEl = undefined; gesture.$imageWrapEl = undefined; } }, // Toggle Zoom toggle: function toggle(e) { var swiper = this; var zoom = swiper.zoom; if (zoom.scale && zoom.scale !== 1) { // Zoom Out zoom.out(); } else { // Zoom In zoom.in(e); } }, in: function _in(e) { var swiper = this; var zoom = swiper.zoom; var params = swiper.params.zoom; var gesture = zoom.gesture, image = zoom.image; if (!gesture.$slideEl) { if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) { gesture.$slideEl = swiper.$wrapperEl.children("." + swiper.params.slideActiveClass); } else { gesture.$slideEl = swiper.slides.eq(swiper.activeIndex); } gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target'); gesture.$imageWrapEl = gesture.$imageEl.parent("." + params.containerClass); } if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; gesture.$slideEl.addClass("" + params.zoomedSlideClass); var touchX; var touchY; var offsetX; var offsetY; var diffX; var diffY; var translateX; var translateY; var imageWidth; var imageHeight; var scaledWidth; var scaledHeight; var translateMinX; var translateMinY; var translateMaxX; var translateMaxY; var slideWidth; var slideHeight; if (typeof image.touchesStart.x === 'undefined' && e) { touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; } else { touchX = image.touchesStart.x; touchY = image.touchesStart.y; } zoom.scale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio; zoom.currentScale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio; if (e) { slideWidth = gesture.$slideEl[0].offsetWidth; slideHeight = gesture.$slideEl[0].offsetHeight; offsetX = gesture.$slideEl.offset().left; offsetY = gesture.$slideEl.offset().top; diffX = offsetX + slideWidth / 2 - touchX; diffY = offsetY + slideHeight / 2 - touchY; imageWidth = gesture.$imageEl[0].offsetWidth; imageHeight = gesture.$imageEl[0].offsetHeight; scaledWidth = imageWidth * zoom.scale; scaledHeight = imageHeight * zoom.scale; translateMinX = Math.min(slideWidth / 2 - scaledWidth / 2, 0); translateMinY = Math.min(slideHeight / 2 - scaledHeight / 2, 0); translateMaxX = -translateMinX; translateMaxY = -translateMinY; translateX = diffX * zoom.scale; translateY = diffY * zoom.scale; if (translateX < translateMinX) { translateX = translateMinX; } if (translateX > translateMaxX) { translateX = translateMaxX; } if (translateY < translateMinY) { translateY = translateMinY; } if (translateY > translateMaxY) { translateY = translateMaxY; } } else { translateX = 0; translateY = 0; } gesture.$imageWrapEl.transition(300).transform("translate3d(" + translateX + "px, " + translateY + "px,0)"); gesture.$imageEl.transition(300).transform("translate3d(0,0,0) scale(" + zoom.scale + ")"); }, out: function out() { var swiper = this; var zoom = swiper.zoom; var params = swiper.params.zoom; var gesture = zoom.gesture; if (!gesture.$slideEl) { if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) { gesture.$slideEl = swiper.$wrapperEl.children("." + swiper.params.slideActiveClass); } else { gesture.$slideEl = swiper.slides.eq(swiper.activeIndex); } gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target'); gesture.$imageWrapEl = gesture.$imageEl.parent("." + params.containerClass); } if (!gesture.$imageEl || gesture.$imageEl.length === 0) return; zoom.scale = 1; zoom.currentScale = 1; gesture.$imageWrapEl.transition(300).transform('translate3d(0,0,0)'); gesture.$imageEl.transition(300).transform('translate3d(0,0,0) scale(1)'); gesture.$slideEl.removeClass("" + params.zoomedSlideClass); gesture.$slideEl = undefined; }, toggleGestures: function toggleGestures(method) { var swiper = this; var zoom = swiper.zoom; var selector = zoom.slideSelector, passive = zoom.passiveListener; swiper.$wrapperEl[method]('gesturestart', selector, zoom.onGestureStart, passive); swiper.$wrapperEl[method]('gesturechange', selector, zoom.onGestureChange, passive); swiper.$wrapperEl[method]('gestureend', selector, zoom.onGestureEnd, passive); }, enableGestures: function enableGestures() { if (this.zoom.gesturesEnabled) return; this.zoom.gesturesEnabled = true; this.zoom.toggleGestures('on'); }, disableGestures: function disableGestures() { if (!this.zoom.gesturesEnabled) return; this.zoom.gesturesEnabled = false; this.zoom.toggleGestures('off'); }, // Attach/Detach Events enable: function enable() { var swiper = this; var support = swiper.support; var zoom = swiper.zoom; if (zoom.enabled) return; zoom.enabled = true; var passiveListener = swiper.touchEvents.start === 'touchstart' && support.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false; var activeListenerWithCapture = support.passiveListener ? { passive: false, capture: true } : true; var slideSelector = "." + swiper.params.slideClass; swiper.zoom.passiveListener = passiveListener; swiper.zoom.slideSelector = slideSelector; // Scale image if (support.gestures) { swiper.$wrapperEl.on(swiper.touchEvents.start, swiper.zoom.enableGestures, passiveListener); swiper.$wrapperEl.on(swiper.touchEvents.end, swiper.zoom.disableGestures, passiveListener); } else if (swiper.touchEvents.start === 'touchstart') { swiper.$wrapperEl.on(swiper.touchEvents.start, slideSelector, zoom.onGestureStart, passiveListener); swiper.$wrapperEl.on(swiper.touchEvents.move, slideSelector, zoom.onGestureChange, activeListenerWithCapture); swiper.$wrapperEl.on(swiper.touchEvents.end, slideSelector, zoom.onGestureEnd, passiveListener); if (swiper.touchEvents.cancel) { swiper.$wrapperEl.on(swiper.touchEvents.cancel, slideSelector, zoom.onGestureEnd, passiveListener); } } // Move image swiper.$wrapperEl.on(swiper.touchEvents.move, "." + swiper.params.zoom.containerClass, zoom.onTouchMove, activeListenerWithCapture); }, disable: function disable() { var swiper = this; var zoom = swiper.zoom; if (!zoom.enabled) return; var support = swiper.support; swiper.zoom.enabled = false; var passiveListener = swiper.touchEvents.start === 'touchstart' && support.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false; var activeListenerWithCapture = support.passiveListener ? { passive: false, capture: true } : true; var slideSelector = "." + swiper.params.slideClass; // Scale image if (support.gestures) { swiper.$wrapperEl.off(swiper.touchEvents.start, swiper.zoom.enableGestures, passiveListener); swiper.$wrapperEl.off(swiper.touchEvents.end, swiper.zoom.disableGestures, passiveListener); } else if (swiper.touchEvents.start === 'touchstart') { swiper.$wrapperEl.off(swiper.touchEvents.start, slideSelector, zoom.onGestureStart, passiveListener); swiper.$wrapperEl.off(swiper.touchEvents.move, slideSelector, zoom.onGestureChange, activeListenerWithCapture); swiper.$wrapperEl.off(swiper.touchEvents.end, slideSelector, zoom.onGestureEnd, passiveListener); if (swiper.touchEvents.cancel) { swiper.$wrapperEl.off(swiper.touchEvents.cancel, slideSelector, zoom.onGestureEnd, passiveListener); } } // Move image swiper.$wrapperEl.off(swiper.touchEvents.move, "." + swiper.params.zoom.containerClass, zoom.onTouchMove, activeListenerWithCapture); } }; var _default = { name: 'zoom', params: { zoom: { enabled: false, maxRatio: 3, minRatio: 1, toggle: true, containerClass: 'swiper-zoom-container', zoomedSlideClass: 'swiper-slide-zoomed' } }, create: function create() { var swiper = this; (0, _utils.bindModuleMethods)(swiper, { zoom: _extends({ enabled: false, scale: 1, currentScale: 1, isScaling: false, gesture: { $slideEl: undefined, slideWidth: undefined, slideHeight: undefined, $imageEl: undefined, $imageWrapEl: undefined, maxRatio: 3 }, image: { isTouched: undefined, isMoved: undefined, currentX: undefined, currentY: undefined, minX: undefined, minY: undefined, maxX: undefined, maxY: undefined, width: undefined, height: undefined, startX: undefined, startY: undefined, touchesStart: {}, touchesCurrent: {} }, velocity: { x: undefined, y: undefined, prevPositionX: undefined, prevPositionY: undefined, prevTime: undefined } }, Zoom) }); var scale = 1; Object.defineProperty(swiper.zoom, 'scale', { get: function get() { return scale; }, set: function set(value) { if (scale !== value) { var imageEl = swiper.zoom.gesture.$imageEl ? swiper.zoom.gesture.$imageEl[0] : undefined; var slideEl = swiper.zoom.gesture.$slideEl ? swiper.zoom.gesture.$slideEl[0] : undefined; swiper.emit('zoomChange', value, imageEl, slideEl); } scale = value; } }); }, on: { init: function init(swiper) { if (swiper.params.zoom.enabled) { swiper.zoom.enable(); } }, destroy: function destroy(swiper) { swiper.zoom.disable(); }, touchStart: function touchStart(swiper, e) { if (!swiper.zoom.enabled) return; swiper.zoom.onTouchStart(e); }, touchEnd: function touchEnd(swiper, e) { if (!swiper.zoom.enabled) return; swiper.zoom.onTouchEnd(e); }, doubleTap: function doubleTap(swiper, e) { if (swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) { swiper.zoom.toggle(e); } }, transitionEnd: function transitionEnd(swiper) { if (swiper.zoom.enabled && swiper.params.zoom.enabled) { swiper.zoom.onTransitionEnd(); } }, slideChange: function slideChange(swiper) { if (swiper.zoom.enabled && swiper.params.zoom.enabled && swiper.params.cssMode) { swiper.zoom.onTransitionEnd(); } } } }; exports.default = _default;