Maison > interface Web > js tutoriel > le corps du texte

Création d'un crochet React pour faire pivoter des images sous n'importe quel angle

PHPz
Libérer: 2024-09-05 19:00:10
original
725 Les gens l'ont consulté

Creating a React Hook for Rotating Images at Any Angle

En développement Web, vous devrez peut-être faire pivoter une image, ce qui est facile à faire en CSS. Code simple comme cette transformation : rotate(90deg);. Mais et si on voulait le faire en JS ?

TLDR

Dessine l'image sur le canevas dans l'environnement du navigateur et la fait pivoter. Mais avant cela, nous devons faire quelques calculs pour conserver le rapport hauteur/largeur de l'image d'origine.

Noyau

En supposant que nous avons chargé l'image, le calcul de l'image pivotée peut être effectué comme suit :

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);
Copier après la connexion

Et ensuite, nous utilisons certaines API du canevas pour effectuer la rotation proprement dite :

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');
Copier après la connexion

Conclusion

Une fois le code de base en place, nous pouvons effectuer quelques optimisations et écrire des hooks React dédiés pour l'utiliser :

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;
Copier après la connexion

Ici, je réutilise le même élément de canevas pour réduire les créations répétées. Deuxièmement, il convient de noter que j'ai défini sa largeur et sa hauteur à 0 après chaque rotation pour réduire l'utilisation de la mémoire. D’ailleurs, j’ai aussi fait l’opération de dégagement de la toile. En effet, dans la spécification HTML, lorsque vous modifiez la largeur et la hauteur du canevas (qu'elles soient les mêmes qu'auparavant), le canevas sera effacé, ce qui est identique à canvasCtx2D.clearRect(0, 0, canvasWidth, canvasHeight), qui est pris en charge par les navigateurs modernes.

Dans useRotateImage, je garde une référence à l'élément image et définit l'état de l'image pivotée après image.decode(), qui est résolu une fois les données de l'image prêtes.

Vous trouverez ci-dessous un cas d'utilisation en ligne :


Si vous avez trouvé cela utile, pensez à à vous abonner à ma newsletter pour des articles et des outils plus utiles sur le développement Web. Merci d'avoir lu !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!