Rumah  >  Artikel  >  hujung hadapan web  >  Mencipta Cangkuk Reaksi untuk Memusing Imej di Mana-mana Sudut

Mencipta Cangkuk Reaksi untuk Memusing Imej di Mana-mana Sudut

PHPz
PHPzasal
2024-09-05 19:00:10814semak imbas

Creating a React Hook for Rotating Images at Any Angle

Dalam pembangunan web, anda mungkin perlu memutarkan imej, yang mudah dilakukan dalam CSS. Kod mudah seperti transformasi ini: rotate(90deg);. Tetapi bagaimana jika kita mahu melakukannya dalam JS?

TLDR

Melukis imej ke kanvas dalam persekitaran penyemak imbas dan memutarkannya. Tetapi sebelum itu, kita perlu melakukan beberapa matematik untuk mengekalkan nisbah bidang imej asal.

Teras

Dengan mengandaikan bahawa kita telah memuatkan imej, pengiraan imej yang diputar boleh dilakukan seperti berikut:

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);

Dan seterusnya, kami menggunakan beberapa API kanvas untuk melakukan putaran sebenar:

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');

Selesaikan

Dengan adanya kod teras, kami boleh membuat beberapa pengoptimuman dan menulis cangkuk React khusus untuk menggunakannya:

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;

Di sini saya menggunakan semula elemen kanvas yang sama untuk mengurangkan penciptaan berulang. Kedua, perlu diingatkan bahawa saya menetapkan lebar dan ketinggiannya kepada 0 selepas setiap putaran untuk mengurangkan penggunaan memori. By the way, saya juga melakukan operasi membersihkan kanvas. Ini kerana dalam spesifikasi HTML apabila anda mengubah suai lebar dan ketinggian kanvas (sama ada ia sama seperti sebelumnya) akan mengosongkan kanvas, yang sama seperti canvasCtx2D.clearRect(0, 0, canvasWidth, canvasHeight), yang disokong oleh penyemak imbas moden.

Dalam useRotateImage, saya menyimpan rujukan kepada elemen imej dan menetapkan keadaan imej diputar selepas image.decode(), yang diselesaikan selepas data imej sedia.

Di bawah ialah kes penggunaan dalam talian:


Jika anda mendapati ini membantu, sila pertimbangkan melanggan surat berita saya untuk lebih banyak artikel dan alatan berguna tentang pembangunan web. Terima kasih kerana membaca!

Atas ialah kandungan terperinci Mencipta Cangkuk Reaksi untuk Memusing Imej di Mana-mana Sudut. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn