Maison > Article > interface Web > Création d'un crochet React pour faire pivoter des images sous n'importe quel 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 ?
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.
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);
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');
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;
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!