BetterTyped / react-zoom-pan-pinch

🖼 React library to support easy zoom, pan, pinch on various html dom elements like <img> and <div>
MIT License
1.49k stars 268 forks source link

How can I use controls outside the <TransformWrapper /> #476

Open mfts opened 4 months ago

mfts commented 4 months ago

First of all, thank you for this library. Works perfectly.

I've been breaking my head how to access controls for a TransformComponent outside the TransformWrapper.

My use case is that I display horizontally stacked images (one at a time). In the navbar, which is not part of the TransformWrapper and stays the same for all images I want to play controls for zoomIn, zoomOut of the currently displayed image.

Here's a simply code example:

import React, { Component } from "react";

import { TransformWrapper, TransformComponent, useControls } from "react-zoom-pan-pinch";

const Controls = () => {
  const { zoomIn, zoomOut, resetTransform } = useControls();
  return (
      <button onClick={() => zoomIn()}>
        Zoom In
      </button>
      <button onClick={() => zoomOut()}>
        Zoom Out
      </button>
      <button onClick={() => resetTransform()}>
        Reset
      </button>
  )
}

const Example = () => {
  return (
   <div>
     <Controls />
     {Array.from({length: 3}).map((_, index) => (
        <TransformWrapper key={index}>
          <TransformComponent>
            <img src="image.jpg" alt="test" />
          </TransformComponent>
        </TransformWrapper>
       ))}
    </div>
  );
};

So ideally, I can target a particular TransformWrapper/TransformComponent with useControls or useTransformContext.

I think this should be possible, but I haven't found a way yet. Perhaps someone knows.

mfts commented 4 months ago

I just figured it out, so I thought I'll share it with folks here.


import React, { MutableRefObject, useRef } from "react";
import { TransformWrapper, TransformComponent, ReactZoomPanPinchContentRef } from "react-zoom-pan-pinch";

const Controls = ({pageNumber, refs}: {pageNumber: number; refs: MutableRefObject<(ReactZoomPanPinchContentRef | null)[]>;}) => {

  return (
      <button onClick={() => refs.current[pageNumber - 1]?.zoomIn()}>
        Zoom In
      </button>
      <button onClick={() => refs.current[pageNumber - 1]?.zoomOut()}>
        Zoom Out
      </button>
      <button onClick={() => refs.current[pageNumber - 1]?.resetTransform()}>
        Reset
      </button>
  )
}

const Example = () => {
  const pinchRefs = useRef<(ReactZoomPanPinchContentRef | null)[]>([]);

  return (
   <div>
     <Controls pinchRefs={pinchRefs} />
     {Array.from({length: 3}).map((_, index) => (
        <TransformWrapper 
           key={index} 
           ref={(ref) => { pinchRefs.current[index] = ref; }}
         >
          <TransformComponent>
            <img src="image.jpg" alt="test" />
          </TransformComponent>
        </TransformWrapper>
       ))}
    </div>
  ); 
}