2

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.

1 Answers1

1

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>
    </>
  );
}
stu197188
  • 11
  • 1