어떤 각도에서든 이미지를 회전할 수 있는 React Hook 만들기

PHPz
풀어 주다: 2024-09-05 19:00:10
원래의
822명이 탐색했습니다.

Creating a React Hook for Rotating Images at Any Angle

웹 개발 시 이미지 회전이 필요할 수 있는데, 이는 CSS에서 쉽게 할 수 있습니다. 다음 변환과 같은 간단한 코드:rotate(90deg);. 그런데 JS에서 하고 싶다면 어떻게 해야 할까요?

TLDR

브라우저 환경에서 캔버스에 이미지를 그려서 회전시킵니다. 하지만 그 전에 원본 이미지 종횡비를 유지하기 위해 몇 가지 계산을 수행해야 합니다.

핵심

이미지를 로드했다고 가정하면 회전된 이미지를 다음과 같이 계산할 수 있습니다.

const { PI, sin, cos, abs } = Math;
const angle = (degree * PI) / 180;
const sinAngle = sin(angle);
const cosAngle = cos(angle);

const rotatedWidth = abs(imageWidth * cosAngle) + abs(imageHeight * sinAngle);

const rotatedHeight = abs(imageWidth * sinAngle) + abs(imageHeight * cosAngle);
로그인 후 복사

다음으로 캔버스 API 중 일부를 사용하여 실제 회전을 수행합니다.

const canvas = document.createElement('canvas');

const { width: canvasWidth, height: canvasHeight } = canvas;
const canvasCtx2D = canvas.getContext('2d');

canvasCtx2D.clearRect(0, 0, canvasWidth, canvasHeight);
canvasCtx2D.translate(canvasWidth / 2, canvasHeight / 2);
canvasCtx2D.rotate(angle);

canvasCtx2D.drawImage(
  image,
  -imageWidth / 2,
  -imageHeight / 2,
  imageWidth,
  imageHeight,
);

return canvas.toDataURL('image/png');
로그인 후 복사

마무리

핵심 코드가 있으면 일부 최적화를 수행하고 이를 사용하기 위한 전용 React 후크를 작성할 수 있습니다.

import { useEffect, useRef, useState } from 'react';

type RotatedImage = {
  src: string;
  width: number;
  height: number;
} | null;

let canvas: HTMLCanvasElement | null = null;
let canvasCtx2D: CanvasRenderingContext2D | null = null;

const getRotatedImage = (
  image: HTMLImageElement | null,
  rotation: number,
): RotatedImage => {
  canvas ??= document.createElement('canvas');
  canvasCtx2D ??= canvas.getContext('2d');

  if (!image || !canvasCtx2D) return null;

  const { width: imageWidth, height: imageHeight, currentSrc } = image;
  const degree = rotation % 360;
  if (!degree) {
    return {
      src: currentSrc,
      width: imageWidth,
      height: imageHeight,
    };
  }

  const { PI, sin, cos, abs } = Math;
  const angle = (degree * PI) / 180;
  const sinAngle = sin(angle);
  const cosAngle = cos(angle);

  canvas.width = abs(imageWidth * cosAngle) + abs(imageHeight * sinAngle);
  canvas.height = abs(imageWidth * sinAngle) + abs(imageHeight * cosAngle);

  // The width and height of the canvas will be automatically rounded.
  const { width: canvasWidth, height: canvasHeight } = canvas;

  canvasCtx2D.clearRect(0, 0, canvasWidth, canvasHeight);
  canvasCtx2D.translate(canvasWidth / 2, canvasHeight / 2);
  canvasCtx2D.rotate(angle);

  canvasCtx2D.drawImage(
    image,
    -imageWidth / 2,
    -imageHeight / 2,
    imageWidth,
    imageHeight,
  );

  const src = canvas.toDataURL('image/png');
  canvas.width = 0;
  canvas.height = 0;

  return {
    src,
    width: canvasWidth,
    height: canvasHeight,
  };
};

const useRotateImage = (imageSrc: string, rotation?: number): RotatedImage => {
  const imageEle = useRef<HTMLImageElement | null>(null);
  const [rotatedImage, setRotatedImage] = useState<RotatedImage>(null);

  useEffect(() => {
    if (typeof rotation === 'number') {
      let currImage = imageEle.current;

      if (currImage?.currentSrc !== imageSrc) {
        currImage = new Image();
        imageEle.current = currImage;

        currImage.src = imageSrc;
      }

      currImage.decode().then(
        () => setRotatedImage(getRotatedImage(currImage, rotation)),
        () => setRotatedImage(null),
      );
    }
  }, [imageSrc, rotation]);

  return rotatedImage;
};

export default useRotateImage;
로그인 후 복사

여기에서는 동일한 캔버스 요소를 재사용하여 반복 생성을 줄입니다. 둘째, 메모리 사용량을 줄이기 위해 각 회전 후에 너비와 높이를 0으로 설정했다는 점에 유의해야 합니다. 그런데, 캔버스를 지우는 작업도 했습니다. 이는 HTML 사양에서 캔버스의 너비와 높이(이전과 동일한지 여부)를 수정하면 canvasCtx2D.clearRect(0, 0, canvasWidth, canvasHeight)와 동일한 캔버스가 지워지기 때문입니다. 최신 브라우저에서 지원됩니다.

useRotateImage에서는 이미지 요소에 대한 참조를 유지하고 이미지 데이터가 준비된 후 확인되는 image.decode() 이후에 회전된 이미지 상태를 설정합니다.

다음은 온라인 사용 사례입니다.


이 내용이 도움이 되었다면 제 뉴스레터를 구독 웹 개발에 대한 더 유용한 기사와 도구를 받아보세요. 읽어주셔서 감사합니다!

위 내용은 어떤 각도에서든 이미지를 회전할 수 있는 React Hook 만들기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿