ホームページ > ウェブフロントエンド > jsチュートリアル > 画像を任意の角度で回転するための React フックの作成

画像を任意の角度で回転するための React フックの作成

PHPz
リリース: 2024-09-05 19:00:10
オリジナル
849 人が閲覧しました

Creating a React Hook for Rotating Images at Any Angle

Web 開発では画像を回転する必要がある場合がありますが、これは 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() の後に回転した画像の状態を設定します。これは、画像データの準備ができた後に解決されます。

以下はオンラインの使用例です:


これが役立つと思われた場合は、 ニュースレターの購読を検討してください Web 開発に関するさらに役立つ記事やツールをご覧ください。読んでいただきありがとうございます!

以上が画像を任意の角度で回転するための React フックの作成の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート