"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > إنشاء خطاف تفاعلي لتدوير الصور بأي زاوية

إنشاء خطاف تفاعلي لتدوير الصور بأي زاوية

تم النشر بتاريخ 2024-11-08
تصفح:205

Creating a React Hook for Rotating Images at Any Angle

في تطوير الويب، قد تحتاج إلى تدوير صورة، وهو أمر يسهل القيام به في 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);

وبعد ذلك، نستخدم بعض واجهات برمجة التطبيقات القماشية لإجراء التدوير الفعلي:

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