Dans le 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 que se passe-t-il si nous voulons 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 des API du canevas pour effectuer la rotation réelle :
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');
Avec 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(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;
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 d'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 !
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3