react-zoom-pan-pinch icon indicating copy to clipboard operation
react-zoom-pan-pinch copied to clipboard

Use a input type range to zoom ?

Open steveprn opened this issue 5 years ago • 5 comments

Hi ! I would like to know , if it was possible to use a input type range to zoom ? if we can, Could you show me how ?

Thanks

steveprn avatar Jul 31 '20 07:07 steveprn

You just need to store the value of the input in state, then you can use it to control the scale.

<TransformWrapper>
  {props => (
    <>
      <TransformComponent>{children}</TransformComponent>
      <ZoomControl {...props} />
    </>
  )}
</TransformWrapper>
const ZoomControl = ({ scale, setScale, options }) => {
  const [value, setValue] = useState(scale)

  useEffect(() => {
    setScale(value)
  }, [value])

  return (
    <input
      type="range"
      min={options.minScale}
      max={options.maxScale}
      value={value}
      onChange={e => setValue(e.target.value)}
    />
  )
}

arsmth avatar Aug 06 '20 12:08 arsmth

@arsmth Do you know how using a range make zoom center of the screen?

Vikshen88 avatar Jun 10 '21 14:06 Vikshen88

Do you know how using a range make zoom center of the screen?

Not 100% sure what you want without more information but I'll presume you want to control the position with a range input in which case you could just do the same as above but with position instead of scale. Check the readme for the list of available props.

arsmth avatar Jun 10 '21 14:06 arsmth

@arsmth I meant, when you use 'setScale' the screen go to the top-left corner. And how to make when I am using 'setScale' it will scale the center of the screen? (I used props like 'positionX', 'positionY' - they didnt help me)

Vikshen88 avatar Jun 11 '21 10:06 Vikshen88

try it here : codesandbox

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

// Style
const MainWrapper = {
  background: "salmon",
  width: "100%",
  height: "100vh",
  position: "relative"
};

const InputWrapper = {
  position: "fixed",
  zIndex: 9999,
  width: "100%"
};

const ScaleIndicator = {
  textAlign: "right",
  position: "absolute",
  right: "40px",
  background: "blue",
  color: "white",
  zIndex: "1000",
  padding: "10px"
};

const Slider = {
  width: "200px",
  margin: "10px 30px"
};

export default function App() {
  const transformComponentRef = useRef(null);
  const [scale, setScale] = useState(0.7);

  const updateScale = (e) => {
    const targetScale = parseFloat(e.target.value);
    const factor = Math.log(targetScale / scale);
    const { zoomIn, zoomOut } = transformComponentRef.current;

    /*
      how react-zoom-pan-pinch calculate new scale :
      targetScale = scale * Math.exp(1 * factor);

      we need factor(step) for zoomIn and zoomOut, just reverse the previous equation to get factor
      factor = Math.log(targetScale / currentScale);
    */
    // console.log(scale * Math.exp(1 * factor), targetScale);

    if (targetScale > scale) {
      zoomIn(factor, 0);
    } else {
      zoomOut(-factor, 0);
    }

    setScale(targetScale);
  };

  return (
    <div style={MainWrapper}>
      <h1 style={ScaleIndicator}>{(scale * 100).toFixed(0)}%</h1>
      <div style={InputWrapper}>
        <input
          type="range"
          min="0.1"
          max="1.5"
          step="0.01"
          value={scale}
          onChange={updateScale}
          style={Slider}
        />
      </div>
      <TransformWrapper
        ref={transformComponentRef}
        onZoomStop={(e) => {
          setScale(e.state.scale);
        }}
        initialScale={scale}
        minScale={0.1}
        maxScale={1.5}
        doubleClick={{
          disabled: true
        }}
        // wheel={{
        //   activationKeys: ["z"]
        // }}
        // panning={{
        //   activationKeys: ["x"],
        // }}
        limitToBounds={false}
        zoomAnimation={{ disabled: true }}
        centerOnInit
        onZoom={(e) => {
          setScale(e.state.scale);
        }}
      >
        {({ zoomIn, zoomOut, setTransform, ...rest }) => {
          return (
            <TransformComponent
              wrapperStyle={{
                width: "100%",
                height: "100%"
              }}
            >
              <img
                src="https://images.pexels.com/photos/2450218/pexels-photo-2450218.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
                alt="Cool Astro"
              />
            </TransformComponent>
          );
        }}
      </TransformWrapper>
    </div>
  );
}

try it here : codesandbox

oggnimodd avatar Aug 29 '21 16:08 oggnimodd

Now it's even easier having hooks for interacting with context 👍

prc5 avatar Feb 27 '23 16:02 prc5