feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
1
f_scripts/shared/swiper/modules/zoom/zoom-element.min.css
vendored
Normal file
1
f_scripts/shared/swiper/modules/zoom/zoom-element.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.swiper-zoom-container{width:100%;height:100%;display:flex;justify-content:center;align-items:center;text-align:center}.swiper-zoom-container>canvas,.swiper-zoom-container>img,.swiper-zoom-container>svg{max-width:100%;max-height:100%;object-fit:contain}.swiper-slide-zoomed{cursor:move;touch-action:none}
|
||||
559
f_scripts/shared/swiper/modules/zoom/zoom.js
Normal file
559
f_scripts/shared/swiper/modules/zoom/zoom.js
Normal file
@@ -0,0 +1,559 @@
|
||||
import { getWindow } from 'ssr-window';
|
||||
import { elementChildren, elementOffset, elementParents, getTranslate } from '../../shared/utils.js';
|
||||
export default function Zoom({
|
||||
swiper,
|
||||
extendParams,
|
||||
on,
|
||||
emit
|
||||
}) {
|
||||
const window = getWindow();
|
||||
extendParams({
|
||||
zoom: {
|
||||
enabled: false,
|
||||
maxRatio: 3,
|
||||
minRatio: 1,
|
||||
toggle: true,
|
||||
containerClass: 'swiper-zoom-container',
|
||||
zoomedSlideClass: 'swiper-slide-zoomed'
|
||||
}
|
||||
});
|
||||
swiper.zoom = {
|
||||
enabled: false
|
||||
};
|
||||
let currentScale = 1;
|
||||
let isScaling = false;
|
||||
let fakeGestureTouched;
|
||||
let fakeGestureMoved;
|
||||
const evCache = [];
|
||||
const gesture = {
|
||||
slideEl: undefined,
|
||||
slideWidth: undefined,
|
||||
slideHeight: undefined,
|
||||
imageEl: undefined,
|
||||
imageWrapEl: undefined,
|
||||
maxRatio: 3
|
||||
};
|
||||
const 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: {}
|
||||
};
|
||||
const velocity = {
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
prevPositionX: undefined,
|
||||
prevPositionY: undefined,
|
||||
prevTime: undefined
|
||||
};
|
||||
let scale = 1;
|
||||
Object.defineProperty(swiper.zoom, 'scale', {
|
||||
get() {
|
||||
return scale;
|
||||
},
|
||||
set(value) {
|
||||
if (scale !== value) {
|
||||
const imageEl = gesture.imageEl;
|
||||
const slideEl = gesture.slideEl;
|
||||
emit('zoomChange', value, imageEl, slideEl);
|
||||
}
|
||||
scale = value;
|
||||
}
|
||||
});
|
||||
function getDistanceBetweenTouches() {
|
||||
if (evCache.length < 2) return 1;
|
||||
const x1 = evCache[0].pageX;
|
||||
const y1 = evCache[0].pageY;
|
||||
const x2 = evCache[1].pageX;
|
||||
const y2 = evCache[1].pageY;
|
||||
const distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
||||
return distance;
|
||||
}
|
||||
function getScaleOrigin() {
|
||||
if (evCache.length < 2) return {
|
||||
x: null,
|
||||
y: null
|
||||
};
|
||||
const box = gesture.imageEl.getBoundingClientRect();
|
||||
return [(evCache[0].pageX + (evCache[1].pageX - evCache[0].pageX) / 2 - box.x) / currentScale, (evCache[0].pageY + (evCache[1].pageY - evCache[0].pageY) / 2 - box.y) / currentScale];
|
||||
}
|
||||
function getSlideSelector() {
|
||||
return swiper.isElement ? `swiper-slide` : `.${swiper.params.slideClass}`;
|
||||
}
|
||||
function eventWithinSlide(e) {
|
||||
const slideSelector = getSlideSelector();
|
||||
if (e.target.matches(slideSelector)) return true;
|
||||
if (swiper.slides.filter(slideEl => slideEl.contains(e.target)).length > 0) return true;
|
||||
return false;
|
||||
}
|
||||
function eventWithinZoomContainer(e) {
|
||||
const selector = `.${swiper.params.zoom.containerClass}`;
|
||||
if (e.target.matches(selector)) return true;
|
||||
if ([...swiper.el.querySelectorAll(selector)].filter(containerEl => containerEl.contains(e.target)).length > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Events
|
||||
function onGestureStart(e) {
|
||||
if (e.pointerType === 'mouse') {
|
||||
evCache.splice(0, evCache.length);
|
||||
}
|
||||
if (!eventWithinSlide(e)) return;
|
||||
const params = swiper.params.zoom;
|
||||
fakeGestureTouched = false;
|
||||
fakeGestureMoved = false;
|
||||
evCache.push(e);
|
||||
if (evCache.length < 2) {
|
||||
return;
|
||||
}
|
||||
fakeGestureTouched = true;
|
||||
gesture.scaleStart = getDistanceBetweenTouches();
|
||||
if (!gesture.slideEl) {
|
||||
gesture.slideEl = e.target.closest(`.${swiper.params.slideClass}, swiper-slide`);
|
||||
if (!gesture.slideEl) gesture.slideEl = swiper.slides[swiper.activeIndex];
|
||||
let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
|
||||
if (imageEl) {
|
||||
imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
|
||||
}
|
||||
gesture.imageEl = imageEl;
|
||||
if (imageEl) {
|
||||
gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
|
||||
} else {
|
||||
gesture.imageWrapEl = undefined;
|
||||
}
|
||||
if (!gesture.imageWrapEl) {
|
||||
gesture.imageEl = undefined;
|
||||
return;
|
||||
}
|
||||
gesture.maxRatio = gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
|
||||
}
|
||||
if (gesture.imageEl) {
|
||||
const [originX, originY] = getScaleOrigin();
|
||||
gesture.imageEl.style.transformOrigin = `${originX}px ${originY}px`;
|
||||
gesture.imageEl.style.transitionDuration = '0ms';
|
||||
}
|
||||
isScaling = true;
|
||||
}
|
||||
function onGestureChange(e) {
|
||||
if (!eventWithinSlide(e)) return;
|
||||
const params = swiper.params.zoom;
|
||||
const zoom = swiper.zoom;
|
||||
const pointerIndex = evCache.findIndex(cachedEv => cachedEv.pointerId === e.pointerId);
|
||||
if (pointerIndex >= 0) evCache[pointerIndex] = e;
|
||||
if (evCache.length < 2) {
|
||||
return;
|
||||
}
|
||||
fakeGestureMoved = true;
|
||||
gesture.scaleMove = getDistanceBetweenTouches();
|
||||
if (!gesture.imageEl) {
|
||||
return;
|
||||
}
|
||||
zoom.scale = gesture.scaleMove / gesture.scaleStart * currentScale;
|
||||
if (zoom.scale > gesture.maxRatio) {
|
||||
zoom.scale = gesture.maxRatio - 1 + (zoom.scale - gesture.maxRatio + 1) ** 0.5;
|
||||
}
|
||||
if (zoom.scale < params.minRatio) {
|
||||
zoom.scale = params.minRatio + 1 - (params.minRatio - zoom.scale + 1) ** 0.5;
|
||||
}
|
||||
gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
|
||||
}
|
||||
function onGestureEnd(e) {
|
||||
if (!eventWithinSlide(e)) return;
|
||||
if (e.pointerType === 'mouse' && e.type === 'pointerout') return;
|
||||
const params = swiper.params.zoom;
|
||||
const zoom = swiper.zoom;
|
||||
const pointerIndex = evCache.findIndex(cachedEv => cachedEv.pointerId === e.pointerId);
|
||||
if (pointerIndex >= 0) evCache.splice(pointerIndex, 1);
|
||||
if (!fakeGestureTouched || !fakeGestureMoved) {
|
||||
return;
|
||||
}
|
||||
fakeGestureTouched = false;
|
||||
fakeGestureMoved = false;
|
||||
if (!gesture.imageEl) return;
|
||||
zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio);
|
||||
gesture.imageEl.style.transitionDuration = `${swiper.params.speed}ms`;
|
||||
gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
|
||||
currentScale = zoom.scale;
|
||||
isScaling = false;
|
||||
if (zoom.scale === 1) gesture.slideEl = undefined;
|
||||
}
|
||||
function onTouchStart(e) {
|
||||
const device = swiper.device;
|
||||
if (!gesture.imageEl) return;
|
||||
if (image.isTouched) return;
|
||||
if (device.android && e.cancelable) e.preventDefault();
|
||||
image.isTouched = true;
|
||||
image.touchesStart.x = e.pageX;
|
||||
image.touchesStart.y = e.pageY;
|
||||
}
|
||||
function onTouchMove(e) {
|
||||
if (!eventWithinSlide(e) || !eventWithinZoomContainer(e)) return;
|
||||
const zoom = swiper.zoom;
|
||||
if (!gesture.imageEl) return;
|
||||
swiper.allowClick = false;
|
||||
if (!image.isTouched || !gesture.slideEl) return;
|
||||
if (!image.isMoved) {
|
||||
image.width = gesture.imageEl.offsetWidth;
|
||||
image.height = gesture.imageEl.offsetHeight;
|
||||
image.startX = getTranslate(gesture.imageWrapEl, 'x') || 0;
|
||||
image.startY = getTranslate(gesture.imageWrapEl, 'y') || 0;
|
||||
gesture.slideWidth = gesture.slideEl.offsetWidth;
|
||||
gesture.slideHeight = gesture.slideEl.offsetHeight;
|
||||
gesture.imageWrapEl.style.transitionDuration = '0ms';
|
||||
}
|
||||
// Define if we need image drag
|
||||
const scaledWidth = image.width * zoom.scale;
|
||||
const 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 = evCache.length > 0 ? evCache[0].pageX : e.pageX;
|
||||
image.touchesCurrent.y = evCache.length > 0 ? evCache[0].pageY : e.pageY;
|
||||
if (!image.isMoved && !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 - (image.minX - image.currentX + 1) ** 0.8;
|
||||
}
|
||||
if (image.currentX > image.maxX) {
|
||||
image.currentX = image.maxX - 1 + (image.currentX - image.maxX + 1) ** 0.8;
|
||||
}
|
||||
if (image.currentY < image.minY) {
|
||||
image.currentY = image.minY + 1 - (image.minY - image.currentY + 1) ** 0.8;
|
||||
}
|
||||
if (image.currentY > image.maxY) {
|
||||
image.currentY = image.maxY - 1 + (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.style.transform = `translate3d(${image.currentX}px, ${image.currentY}px,0)`;
|
||||
}
|
||||
function onTouchEnd() {
|
||||
const zoom = swiper.zoom;
|
||||
if (!gesture.imageEl) return;
|
||||
if (!image.isTouched || !image.isMoved) {
|
||||
image.isTouched = false;
|
||||
image.isMoved = false;
|
||||
return;
|
||||
}
|
||||
image.isTouched = false;
|
||||
image.isMoved = false;
|
||||
let momentumDurationX = 300;
|
||||
let momentumDurationY = 300;
|
||||
const momentumDistanceX = velocity.x * momentumDurationX;
|
||||
const newPositionX = image.currentX + momentumDistanceX;
|
||||
const momentumDistanceY = velocity.y * momentumDurationY;
|
||||
const 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);
|
||||
const momentumDuration = Math.max(momentumDurationX, momentumDurationY);
|
||||
image.currentX = newPositionX;
|
||||
image.currentY = newPositionY;
|
||||
|
||||
// Define if we need image drag
|
||||
const scaledWidth = image.width * zoom.scale;
|
||||
const 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.style.transitionDuration = `${momentumDuration}ms`;
|
||||
gesture.imageWrapEl.style.transform = `translate3d(${image.currentX}px, ${image.currentY}px,0)`;
|
||||
}
|
||||
function onTransitionEnd() {
|
||||
const zoom = swiper.zoom;
|
||||
if (gesture.slideEl && swiper.previousIndex !== swiper.activeIndex) {
|
||||
if (gesture.imageEl) {
|
||||
gesture.imageEl.style.transform = 'translate3d(0,0,0) scale(1)';
|
||||
}
|
||||
if (gesture.imageWrapEl) {
|
||||
gesture.imageWrapEl.style.transform = 'translate3d(0,0,0)';
|
||||
}
|
||||
zoom.scale = 1;
|
||||
currentScale = 1;
|
||||
gesture.slideEl = undefined;
|
||||
gesture.imageEl = undefined;
|
||||
gesture.imageWrapEl = undefined;
|
||||
}
|
||||
}
|
||||
function zoomIn(e) {
|
||||
const zoom = swiper.zoom;
|
||||
const params = swiper.params.zoom;
|
||||
if (!gesture.slideEl) {
|
||||
if (e && e.target) {
|
||||
gesture.slideEl = e.target.closest(`.${swiper.params.slideClass}, swiper-slide`);
|
||||
}
|
||||
if (!gesture.slideEl) {
|
||||
if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
|
||||
gesture.slideEl = elementChildren(swiper.slidesEl, `.${swiper.params.slideActiveClass}`)[0];
|
||||
} else {
|
||||
gesture.slideEl = swiper.slides[swiper.activeIndex];
|
||||
}
|
||||
}
|
||||
let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
|
||||
if (imageEl) {
|
||||
imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
|
||||
}
|
||||
gesture.imageEl = imageEl;
|
||||
if (imageEl) {
|
||||
gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
|
||||
} else {
|
||||
gesture.imageWrapEl = undefined;
|
||||
}
|
||||
}
|
||||
if (!gesture.imageEl || !gesture.imageWrapEl) return;
|
||||
if (swiper.params.cssMode) {
|
||||
swiper.wrapperEl.style.overflow = 'hidden';
|
||||
swiper.wrapperEl.style.touchAction = 'none';
|
||||
}
|
||||
gesture.slideEl.classList.add(`${params.zoomedSlideClass}`);
|
||||
let touchX;
|
||||
let touchY;
|
||||
let offsetX;
|
||||
let offsetY;
|
||||
let diffX;
|
||||
let diffY;
|
||||
let translateX;
|
||||
let translateY;
|
||||
let imageWidth;
|
||||
let imageHeight;
|
||||
let scaledWidth;
|
||||
let scaledHeight;
|
||||
let translateMinX;
|
||||
let translateMinY;
|
||||
let translateMaxX;
|
||||
let translateMaxY;
|
||||
let slideWidth;
|
||||
let slideHeight;
|
||||
if (typeof image.touchesStart.x === 'undefined' && e) {
|
||||
touchX = e.pageX;
|
||||
touchY = e.pageY;
|
||||
} else {
|
||||
touchX = image.touchesStart.x;
|
||||
touchY = image.touchesStart.y;
|
||||
}
|
||||
const forceZoomRatio = typeof e === 'number' ? e : null;
|
||||
if (currentScale === 1 && forceZoomRatio) {
|
||||
touchX = undefined;
|
||||
touchY = undefined;
|
||||
}
|
||||
zoom.scale = forceZoomRatio || gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
|
||||
currentScale = forceZoomRatio || gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
|
||||
if (e && !(currentScale === 1 && forceZoomRatio)) {
|
||||
slideWidth = gesture.slideEl.offsetWidth;
|
||||
slideHeight = gesture.slideEl.offsetHeight;
|
||||
offsetX = elementOffset(gesture.slideEl).left + window.scrollX;
|
||||
offsetY = elementOffset(gesture.slideEl).top + window.scrollY;
|
||||
diffX = offsetX + slideWidth / 2 - touchX;
|
||||
diffY = offsetY + slideHeight / 2 - touchY;
|
||||
imageWidth = gesture.imageEl.offsetWidth;
|
||||
imageHeight = gesture.imageEl.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.style.transitionDuration = '300ms';
|
||||
gesture.imageWrapEl.style.transform = `translate3d(${translateX}px, ${translateY}px,0)`;
|
||||
gesture.imageEl.style.transitionDuration = '300ms';
|
||||
gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
|
||||
}
|
||||
function zoomOut() {
|
||||
const zoom = swiper.zoom;
|
||||
const params = swiper.params.zoom;
|
||||
if (!gesture.slideEl) {
|
||||
if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
|
||||
gesture.slideEl = elementChildren(swiper.slidesEl, `.${swiper.params.slideActiveClass}`)[0];
|
||||
} else {
|
||||
gesture.slideEl = swiper.slides[swiper.activeIndex];
|
||||
}
|
||||
let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
|
||||
if (imageEl) {
|
||||
imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
|
||||
}
|
||||
gesture.imageEl = imageEl;
|
||||
if (imageEl) {
|
||||
gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
|
||||
} else {
|
||||
gesture.imageWrapEl = undefined;
|
||||
}
|
||||
}
|
||||
if (!gesture.imageEl || !gesture.imageWrapEl) return;
|
||||
if (swiper.params.cssMode) {
|
||||
swiper.wrapperEl.style.overflow = '';
|
||||
swiper.wrapperEl.style.touchAction = '';
|
||||
}
|
||||
zoom.scale = 1;
|
||||
currentScale = 1;
|
||||
gesture.imageWrapEl.style.transitionDuration = '300ms';
|
||||
gesture.imageWrapEl.style.transform = 'translate3d(0,0,0)';
|
||||
gesture.imageEl.style.transitionDuration = '300ms';
|
||||
gesture.imageEl.style.transform = 'translate3d(0,0,0) scale(1)';
|
||||
gesture.slideEl.classList.remove(`${params.zoomedSlideClass}`);
|
||||
gesture.slideEl = undefined;
|
||||
}
|
||||
|
||||
// Toggle Zoom
|
||||
function zoomToggle(e) {
|
||||
const zoom = swiper.zoom;
|
||||
if (zoom.scale && zoom.scale !== 1) {
|
||||
// Zoom Out
|
||||
zoomOut();
|
||||
} else {
|
||||
// Zoom In
|
||||
zoomIn(e);
|
||||
}
|
||||
}
|
||||
function getListeners() {
|
||||
const passiveListener = swiper.params.passiveListeners ? {
|
||||
passive: true,
|
||||
capture: false
|
||||
} : false;
|
||||
const activeListenerWithCapture = swiper.params.passiveListeners ? {
|
||||
passive: false,
|
||||
capture: true
|
||||
} : true;
|
||||
return {
|
||||
passiveListener,
|
||||
activeListenerWithCapture
|
||||
};
|
||||
}
|
||||
|
||||
// Attach/Detach Events
|
||||
function enable() {
|
||||
const zoom = swiper.zoom;
|
||||
if (zoom.enabled) return;
|
||||
zoom.enabled = true;
|
||||
const {
|
||||
passiveListener,
|
||||
activeListenerWithCapture
|
||||
} = getListeners();
|
||||
|
||||
// Scale image
|
||||
|
||||
swiper.wrapperEl.addEventListener('pointerdown', onGestureStart, passiveListener);
|
||||
swiper.wrapperEl.addEventListener('pointermove', onGestureChange, activeListenerWithCapture);
|
||||
['pointerup', 'pointercancel', 'pointerout'].forEach(eventName => {
|
||||
swiper.wrapperEl.addEventListener(eventName, onGestureEnd, passiveListener);
|
||||
});
|
||||
|
||||
// Move image
|
||||
swiper.wrapperEl.addEventListener('pointermove', onTouchMove, activeListenerWithCapture);
|
||||
}
|
||||
function disable() {
|
||||
const zoom = swiper.zoom;
|
||||
if (!zoom.enabled) return;
|
||||
zoom.enabled = false;
|
||||
const {
|
||||
passiveListener,
|
||||
activeListenerWithCapture
|
||||
} = getListeners();
|
||||
|
||||
// Scale image
|
||||
swiper.wrapperEl.removeEventListener('pointerdown', onGestureStart, passiveListener);
|
||||
swiper.wrapperEl.removeEventListener('pointermove', onGestureChange, activeListenerWithCapture);
|
||||
['pointerup', 'pointercancel', 'pointerout'].forEach(eventName => {
|
||||
swiper.wrapperEl.removeEventListener(eventName, onGestureEnd, passiveListener);
|
||||
});
|
||||
|
||||
// Move image
|
||||
swiper.wrapperEl.removeEventListener('pointermove', onTouchMove, activeListenerWithCapture);
|
||||
}
|
||||
on('init', () => {
|
||||
if (swiper.params.zoom.enabled) {
|
||||
enable();
|
||||
}
|
||||
});
|
||||
on('destroy', () => {
|
||||
disable();
|
||||
});
|
||||
on('touchStart', (_s, e) => {
|
||||
if (!swiper.zoom.enabled) return;
|
||||
onTouchStart(e);
|
||||
});
|
||||
on('touchEnd', (_s, e) => {
|
||||
if (!swiper.zoom.enabled) return;
|
||||
onTouchEnd(e);
|
||||
});
|
||||
on('doubleTap', (_s, e) => {
|
||||
if (!swiper.animating && swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) {
|
||||
zoomToggle(e);
|
||||
}
|
||||
});
|
||||
on('transitionEnd', () => {
|
||||
if (swiper.zoom.enabled && swiper.params.zoom.enabled) {
|
||||
onTransitionEnd();
|
||||
}
|
||||
});
|
||||
on('slideChange', () => {
|
||||
if (swiper.zoom.enabled && swiper.params.zoom.enabled && swiper.params.cssMode) {
|
||||
onTransitionEnd();
|
||||
}
|
||||
});
|
||||
Object.assign(swiper.zoom, {
|
||||
enable,
|
||||
disable,
|
||||
in: zoomIn,
|
||||
out: zoomOut,
|
||||
toggle: zoomToggle
|
||||
});
|
||||
}
|
||||
21
f_scripts/shared/swiper/modules/zoom/zoom.less
Normal file
21
f_scripts/shared/swiper/modules/zoom/zoom.less
Normal file
@@ -0,0 +1,21 @@
|
||||
.swiper-zoom-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
> img,
|
||||
> svg,
|
||||
> canvas {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-slide-zoomed {
|
||||
cursor: move;
|
||||
touch-action: none;
|
||||
}
|
||||
1
f_scripts/shared/swiper/modules/zoom/zoom.min.css
vendored
Normal file
1
f_scripts/shared/swiper/modules/zoom/zoom.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.swiper-zoom-container{width:100%;height:100%;display:flex;justify-content:center;align-items:center;text-align:center}.swiper-zoom-container>canvas,.swiper-zoom-container>img,.swiper-zoom-container>svg{max-width:100%;max-height:100%;object-fit:contain}.swiper-slide-zoomed{cursor:move;touch-action:none}
|
||||
21
f_scripts/shared/swiper/modules/zoom/zoom.scss
Normal file
21
f_scripts/shared/swiper/modules/zoom/zoom.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.swiper-zoom-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
> img,
|
||||
> svg,
|
||||
> canvas {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-slide-zoomed {
|
||||
cursor: move;
|
||||
touch-action: none;
|
||||
}
|
||||
Reference in New Issue
Block a user