Reputation: 103
Is there any way to zoom.in()
and zoom.out()
at different levels of zoom, instead of have zoom (zoom.in) or not have zoom (zoom.out)? The problem is that I want different levels of zoom, like 100%-150%-200%-250%-300% (100% = minRatio, 300% = maxRatio), when I'm zooming, and not to get the maxRatio zooming when I zoom.in()
, I would like to be able to go by steps.
I've found this solution: Zoom in on a mousewheel point (using scale and translate) using js + css, but I think that this feature should be included in the library, instead of doing it by hand.
Upvotes: 2
Views: 1854
Reputation: 11
I needed to achieve this for a React app and managed to do so writing a custom module which extended the Zoom module functionality - sure you could use a similar approach for whatever implementation you needed...
// ExtendedZoom.ts
const ExtendedZoom = (_ref: Ref) => {
const { swiper } = _ref;
const gesture: GestureElements = {};
const setZoom = (scale: number) => {
gesture.slideEl = swiper.slides[swiper.activeIndex] as HTMLDivElement;
if (!swiper.params || typeof swiper.params.zoom !== 'object') return;
gesture.imageEl = gesture.slideEl.querySelector(
`.${swiper.params.zoom.containerClass} img`,
) as HTMLImageElement;
gesture.imageWrapEl = gesture.imageEl.closest(
`.${swiper.params.zoom.containerClass}`,
) as HTMLDivElement;
if (swiper.params.zoom.zoomedSlideClass) {
gesture.slideEl.classList.add(swiper.params.zoom.zoomedSlideClass);
}
swiper.zoom.scale = scale;
gesture.imageWrapEl.style.transition = '0.3s';
gesture.imageWrapEl.style.transform = 'translate(0, 0)';
gesture.imageEl.style.transition = '0.3s';
gesture.imageEl.style.transform = `translate(0, 0) scale(${swiper.zoom.scale})`;
};
swiper.zoom.setZoom = setZoom;
};
export default ExtendedZoom;
// ComponentUsingSwiper.tsx
import React, { useState, useMemo } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Keyboard, Zoom } from 'swiper';
import { ZoomOptions } from 'swiper/types';
import ExtendedZoom from './ExtendedZoom';
const WithZoomModules = [Keyboard, Zoom, ExtendedZoom];
const MAX_ZOOM = 4;
const WithIncrementalZoom: React.FC<{ images: Image[] }> = ({
images,
}) => {
const [swipeNavEnabled, setSwipeNavEnabled] = useState(true);
const [activeZoomScale, setActiveZoomScale] = useState(1);
const zoomConfig = useMemo<ZoomOptions>(
() => ({
containerClass: 'swiper-zoom-container',
minRatio: 1,
maxRatio: activeZoomScale < MAX_ZOOM ? activeZoomScale + 1 : MAX_ZOOM,
}),
[activeZoomScale],
);
const onZoomChange = (swiper: SwiperInstanceProps, scale: number) => {
if (scale === 1 && !swipeNavEnabled) setSwipeNavEnabled(true);
if (scale > 1 && swipeNavEnabled) setSwipeNavEnabled(false);
setActiveZoomScale(scale);
};
return (
<Swiper
slidesPerView={1}
modules={WithZoomModules}
loop
keyboard
onSlideChange={onSlideChange}
zoom={zoomConfig}
allowTouchMove={swipeNavEnabled}
onZoomChange={onZoomChange}
>
{images.map((image) => (
<SwiperSlide key={image.href}>
<div className="swiper-zoom-container">
<img src={image.href} alt={image.caption} />
</div>
</SwiperSlide>
))}
<ZoomControls maxZoom={MAX_ZOOM} activeZoomScale={activeZoomScale} />
</Swiper>
);
};
// ZoomControls.tsx
const ZoomControls: React.FC<{ maxZoom: number, activeZoomScale: number }> = ({ maxZoom, activeZoomScale }) => {
const swiper = useSwiper();
const zoomIn = () => {
if (activeZoomScale < maxZoom) {
swiper.zoom.setZoom(activeZoomScale + 1);
}
};
const zoomOut = () => {
if (activeZoomScale > 1) {
swiper.zoom.setZoom(activeZoomScale - 1);
}
};
return (
<>
<button type="button" onClick={zoomIn}>Zoom In</button>
<button type="button" onClick={zoomOut}>Zoom Out</button>
</>
);
}
Upvotes: 1