「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > 画像を任意の角度で回転するための React フックを作成する

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

2024 年 11 月 8 日に公開
ブラウズ:831

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(null);
  const [rotatedImage, setRotatedImage] = useState(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() の後に回転した画像の状態を設定します。これは、画像データの準備ができた後に解決されます。

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


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

リリースステートメント この記事は次の場所に転載されています: https://dev.to/zacharylee/creating-a-react-hook-for-rotating-images-at-any-angle-4nnb?1 侵害がある場合は、study_golang@163 までご連絡ください。 .comを削除してください
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3