برنامه نویسی

ساخت انیمیشن های ایموجی تعاملی در React ⚛️🎯

Summarize this content to 400 words in Persian Lang آیا تا به حال به این فکر کرده اید که چگونه برنامه ریزی جلسات پوکر خود را تعاملی تر کنید؟ بیایید با استفاده از React hooks و Web Animation API یک سیستم انیمیشن پرتاب ایموجی سرگرم کننده را پیاده سازی کنیم. من به شما نشان خواهم داد که چگونه این ویژگی را برای Kollabe، ابزار رایگان برنامه ریزی پوکر ما ایجاد کردم.

چالش

برنامه ریزی جلسات پوکر می تواند یکنواخت شود، به خصوص در تنظیمات از راه دور. در حین ساختن Kollabe، ما می خواستیم عناصر تعاملی را اضافه کنیم که:

اعضای تیم را درگیر نگه دارید
گزینه های بازخورد غیرکلامی را ارائه دهید
جلسات از راه دور را شخصی تر کنید
یک عامل سرگرم کننده بدون به خطر انداختن عملکرد اضافه کنید

راه حل: اموجی های پرنده

ما یک سیستم پرتاب ایموجی را پیاده‌سازی کردیم که به اعضای تیم اجازه می‌دهد با پرتاب کردن ایموجی‌ها در سراسر صفحه به تخمین‌ها واکنش نشان دهند. در اینجا نحوه ساخت آن آمده است:

پیاده سازی کامل

در اینجا پیاده سازی کامل و کارآمدی است که می توانید در پروژه های خود استفاده کنید:

import { useCallback, useRef } from “react”;

interface Point {
x: number;
y: number;
}

interface DOMRect {
left: number;
top: number;
width: number;
height: number;
}

/**
* Generates a random number within a specified range.
*/
const getRandomNumber = (
min = 0.1,
max = 0.4,
isPositive = Math.random() < 0.5,
): number => {
const random = Math.random() * (max – min) + min;
return isPositive ? random : -random;
};

/**
* Calculates the center position of a DOM element.
*/
const getCenterPosition = (rect: DOMRect): Point => ({
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
});

/**
* Calculates the target position with a random offset from the center.
*/
const getTargetPosition = (rect: DOMRect): Point => {
const center = getCenterPosition(rect);
return {
x: center.x – getRandomNumber(0, 15, true),
y: center.y – getRandomNumber(0, 25, true),
};
};

/**
* Calculates the midpoint between two points.
*/
const getMidpoint = (start: Point, target: Point): Point => ({
x: (start.x + target.x) / 2,
y: (start.y + target.y) / 2,
});

/**
* Calculates the distance between two points.
*/
const getDistance = (start: Point, target: Point): number => {
return Math.sqrt(
Math.pow(target.x – start.x, 2) + Math.pow(target.y – start.y, 2),
);
};

/**
* Calculates the control point for the quadratic Bezier curve.
*/
const getControlPoint = (start: Point, target: Point): Point => {
const midpoint = getMidpoint(start, target);
const distance = getDistance(start, target);

const angle = Math.atan2(target.y – start.y, target.x – start.x);
const perpAngle = angle + Math.PI / 2;
const controlPointDistance = distance * getRandomNumber(0.2, 0.4, true);

return {
x: midpoint.x + Math.cos(perpAngle) * controlPointDistance,
y: midpoint.y + Math.sin(perpAngle) * controlPointDistance,
};
};

/**
* Creates and styles the emoji element.
*/
const createEmojiElement = (
emoji: string,
startPoint: Point,
): HTMLDivElement => {
const emojiElement = document.createElement(“div”);
Object.assign(emojiElement.style, {
position: “fixed”,
fontSize: “24px”,
pointerEvents: “none”,
zIndex: “1”,
left: “0”,
top: “0”,
transform: `translate(${startPoint.x}px, ${startPoint.y}px) translate(-50%, -50%)`,
});
emojiElement.textContent = emoji;
document.body.appendChild(emojiElement);
return emojiElement;
};

/**
* Calculates a point on a quadratic Bezier curve.
*/
const calculateBezierPoint = (
start: Point,
control: Point,
target: Point,
progress: number,
): Point => {
const easeProgress = 1 – Math.pow(1 – progress, 2);
return {
x:
Math.pow(1 – easeProgress, 2) * start.x +
2 * (1 – easeProgress) * easeProgress * control.x +
Math.pow(easeProgress, 2) * target.x,
y:
Math.pow(1 – easeProgress, 2) * start.y +
2 * (1 – easeProgress) * easeProgress * control.y +
Math.pow(easeProgress, 2) * target.y,
};
};

/**
* Custom hook for throwing emoji animations.
*/
export const useEmojiThrow = () => {
const animationRef = useRef<number>();
const emojiRef = useRef<HTMLDivElement | null>(null);

const throwEmoji = useCallback(
(emoji: string, sourceId: string, targetId: string) => {
const sourceEl = document.getElementById(sourceId);
const targetEl = document.getElementById(targetId);

if (!sourceEl || !targetEl) return;

const startRect = sourceEl.getBoundingClientRect();
const targetRect = targetEl.getBoundingClientRect();

const startPoint = getCenterPosition(startRect);
const targetPoint = getTargetPosition(targetRect);
const controlPoint = getControlPoint(startPoint, targetPoint);

const emojiElement = createEmojiElement(emoji, startPoint);
emojiRef.current = emojiElement;

let startTime = performance.now();
const duration = 1000; // Animation duration in milliseconds

const animate = (currentTime: number) => {
const elapsed = currentTime – startTime;
const progress = Math.min(elapsed / duration, 1);

const position = calculateBezierPoint(
startPoint,
controlPoint,
targetPoint,
progress,
);

emojiElement.style.transform =
`translate(${position.x}px, ${position.y}px) translate(-50%, -50%)`;

if (progress < 1) {
animationRef.current = requestAnimationFrame(animate);
} else {
emojiElement.style.transform =
`translate(${targetPoint.x}px, ${targetPoint.y}px) translate(-50%, -50%)`;
setTimeout(() => {
emojiElement.remove();
}, duration);
}
};

requestAnimationFrame(() => {
startTime = performance.now();
animate(startTime);
});
},
[],
);

const cleanup = useCallback(() => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
if (emojiRef.current) {
emojiRef.current.remove();
}
}, []);

return { throwEmoji, cleanup };
};

نحوه استفاده از آن

در اینجا یک مثال کامل از نحوه پیاده سازی ایموجی در کامپوننت React آورده شده است:

import React from ‘react’;
import { useEmojiThrow } from ‘./useEmojiThrow’;

const PlanningPokerRoom: React.FC = () => {
const { throwEmoji } = useEmojiThrow();

const handleEmojiClick = (emoji: string) => {
// Assuming you have elements with these IDs in your DOM
throwEmoji(emoji, “source-player-avatar”, “target-player-avatar”);
};

return (
<div className=”poker-room”>
<div id=”source-player-avatar” className=”avatar”>
Player 1
</div>

<div className=”emoji-controls”>
<button onClick={() => handleEmojiClick(“🎉”)}>Throw Confetti</button>
<button onClick={() => handleEmojiClick(“👍”)}>Throw Thumbs Up</button>
<button onClick={() => handleEmojiClick(“❤️”)}>Throw Heart</button>
</div>

<div id=”target-player-avatar” className=”avatar”>
Player 2
</div>
</div>
);
};

export default PlanningPokerRoom;

ویژگی های کلیدی

حرکت طبیعی: از منحنی های Bezier درجه دوم برای حرکت صاف و قوس مانند استفاده می کند

تصادفی سازی: تغییرات جزئی را به موقعیت ها و مسیرهای هدف اضافه می کند

عملکرد: موارد استفاده requestAnimationFrame برای انیمیشن های روان

پاکسازی: شامل پاکسازی مناسب انیمیشن ها و عناصر DOM است

پشتیبانی TypeScript: برای تجربه بهتر توسعه دهنده کاملا تایپ شده است

جزئیات فنی

این انیمیشن توسط:

محاسبه موقعیت های شروع و پایان از عناصر DOM
ایجاد یک عنصر ایموجی موقت
متحرک سازی آن در امتداد منحنی Bezier
پاکسازی پس از تکمیل انیمیشن

را useEmojiThrow هوک تمام پیچیدگی ها را کنترل می کند و یک رابط ساده برای پرتاب ایموجی ها بین هر دو عنصر در صفحه شما فراهم می کند.

آن را در عمل ببینید

آیا می خواهید این کد را در یک محیط تولید مشاهده کنید؟ اتاق آزمایشی ما را بررسی کنید که در آن می‌توانید شکلک‌ها را به بازیکنان ربات پرتاب کنید یا جلسه پوکر برنامه‌ریزی خود را در Kollabe شروع کنید.

ملاحظات عملکرد

انیمیشن ها از تبدیل های CSS برای عملکرد بهتر استفاده می کنند
برای جلوگیری از نشت حافظه، عناصر به درستی تمیز می شوند
محاسبات بهینه شده و در صورت امکان ذخیره می شوند
فریم های انیمیشن در پاکسازی لغو می شوند

سفارشی سازی های بالقوه

شما به راحتی می توانید کد را تغییر دهید:

تنظیم مدت زمان انیمیشن
تغییر اندازه ایموجی
تغییر تصادفی مسیر
افکت‌های چرخش یا مقیاس‌بندی را اضافه کنید
توابع مختلف تسهیل را اجرا کنید

این همه چیز است

افزودن عناصر تعاملی مانند پرتاب ایموجی می تواند جلسات پوکر برنامه ریزی استاندارد را به تجربیات تیمی جذاب تبدیل کند. با خیال راحت از این کد در پروژه های خود استفاده کنید و اگر به دنبال راه حل آماده برای استفاده هستید، Kollabe را برای جلسات برنامه ریزی تیم خود امتحان کنید.

آیا تا به حال به این فکر کرده اید که چگونه برنامه ریزی جلسات پوکر خود را تعاملی تر کنید؟ بیایید با استفاده از React hooks و Web Animation API یک سیستم انیمیشن پرتاب ایموجی سرگرم کننده را پیاده سازی کنیم. من به شما نشان خواهم داد که چگونه این ویژگی را برای Kollabe، ابزار رایگان برنامه ریزی پوکر ما ایجاد کردم.

چالش

برنامه ریزی جلسات پوکر می تواند یکنواخت شود، به خصوص در تنظیمات از راه دور. در حین ساختن Kollabe، ما می خواستیم عناصر تعاملی را اضافه کنیم که:

  • اعضای تیم را درگیر نگه دارید
  • گزینه های بازخورد غیرکلامی را ارائه دهید
  • جلسات از راه دور را شخصی تر کنید
  • یک عامل سرگرم کننده بدون به خطر انداختن عملکرد اضافه کنید

راه حل: اموجی های پرنده

ایموجی پوکر برنامه ریزی

ما یک سیستم پرتاب ایموجی را پیاده‌سازی کردیم که به اعضای تیم اجازه می‌دهد با پرتاب کردن ایموجی‌ها در سراسر صفحه به تخمین‌ها واکنش نشان دهند. در اینجا نحوه ساخت آن آمده است:

پیاده سازی کامل

در اینجا پیاده سازی کامل و کارآمدی است که می توانید در پروژه های خود استفاده کنید:

import { useCallback, useRef } from "react";

interface Point {
  x: number;
  y: number;
}

interface DOMRect {
  left: number;
  top: number;
  width: number;
  height: number;
}

/**
 * Generates a random number within a specified range.
 */
const getRandomNumber = (
  min = 0.1,
  max = 0.4,
  isPositive = Math.random() < 0.5,
): number => {
  const random = Math.random() * (max - min) + min;
  return isPositive ? random : -random;
};

/**
 * Calculates the center position of a DOM element.
 */
const getCenterPosition = (rect: DOMRect): Point => ({
  x: rect.left + rect.width / 2,
  y: rect.top + rect.height / 2,
});

/**
 * Calculates the target position with a random offset from the center.
 */
const getTargetPosition = (rect: DOMRect): Point => {
  const center = getCenterPosition(rect);
  return {
    x: center.x - getRandomNumber(0, 15, true),
    y: center.y - getRandomNumber(0, 25, true),
  };
};

/**
 * Calculates the midpoint between two points.
 */
const getMidpoint = (start: Point, target: Point): Point => ({
  x: (start.x + target.x) / 2,
  y: (start.y + target.y) / 2,
});

/**
 * Calculates the distance between two points.
 */
const getDistance = (start: Point, target: Point): number => {
  return Math.sqrt(
    Math.pow(target.x - start.x, 2) + Math.pow(target.y - start.y, 2),
  );
};

/**
 * Calculates the control point for the quadratic Bezier curve.
 */
const getControlPoint = (start: Point, target: Point): Point => {
  const midpoint = getMidpoint(start, target);
  const distance = getDistance(start, target);

  const angle = Math.atan2(target.y - start.y, target.x - start.x);
  const perpAngle = angle + Math.PI / 2;
  const controlPointDistance = distance * getRandomNumber(0.2, 0.4, true);

  return {
    x: midpoint.x + Math.cos(perpAngle) * controlPointDistance,
    y: midpoint.y + Math.sin(perpAngle) * controlPointDistance,
  };
};

/**
 * Creates and styles the emoji element.
 */
const createEmojiElement = (
  emoji: string,
  startPoint: Point,
): HTMLDivElement => {
  const emojiElement = document.createElement("div");
  Object.assign(emojiElement.style, {
    position: "fixed",
    fontSize: "24px",
    pointerEvents: "none",
    zIndex: "1",
    left: "0",
    top: "0",
    transform: `translate(${startPoint.x}px, ${startPoint.y}px) translate(-50%, -50%)`,
  });
  emojiElement.textContent = emoji;
  document.body.appendChild(emojiElement);
  return emojiElement;
};

/**
 * Calculates a point on a quadratic Bezier curve.
 */
const calculateBezierPoint = (
  start: Point,
  control: Point,
  target: Point,
  progress: number,
): Point => {
  const easeProgress = 1 - Math.pow(1 - progress, 2);
  return {
    x:
      Math.pow(1 - easeProgress, 2) * start.x +
      2 * (1 - easeProgress) * easeProgress * control.x +
      Math.pow(easeProgress, 2) * target.x,
    y:
      Math.pow(1 - easeProgress, 2) * start.y +
      2 * (1 - easeProgress) * easeProgress * control.y +
      Math.pow(easeProgress, 2) * target.y,
  };
};

/**
 * Custom hook for throwing emoji animations.
 */
export const useEmojiThrow = () => {
  const animationRef = useRef<number>();
  const emojiRef = useRef<HTMLDivElement | null>(null);

  const throwEmoji = useCallback(
    (emoji: string, sourceId: string, targetId: string) => {
      const sourceEl = document.getElementById(sourceId);
      const targetEl = document.getElementById(targetId);

      if (!sourceEl || !targetEl) return;

      const startRect = sourceEl.getBoundingClientRect();
      const targetRect = targetEl.getBoundingClientRect();

      const startPoint = getCenterPosition(startRect);
      const targetPoint = getTargetPosition(targetRect);
      const controlPoint = getControlPoint(startPoint, targetPoint);

      const emojiElement = createEmojiElement(emoji, startPoint);
      emojiRef.current = emojiElement;

      let startTime = performance.now();
      const duration = 1000; // Animation duration in milliseconds

      const animate = (currentTime: number) => {
        const elapsed = currentTime - startTime;
        const progress = Math.min(elapsed / duration, 1);

        const position = calculateBezierPoint(
          startPoint,
          controlPoint,
          targetPoint,
          progress,
        );

        emojiElement.style.transform = 
          `translate(${position.x}px, ${position.y}px) translate(-50%, -50%)`;

        if (progress < 1) {
          animationRef.current = requestAnimationFrame(animate);
        } else {
          emojiElement.style.transform = 
            `translate(${targetPoint.x}px, ${targetPoint.y}px) translate(-50%, -50%)`;
          setTimeout(() => {
            emojiElement.remove();
          }, duration);
        }
      };

      requestAnimationFrame(() => {
        startTime = performance.now();
        animate(startTime);
      });
    },
    [],
  );

  const cleanup = useCallback(() => {
    if (animationRef.current) {
      cancelAnimationFrame(animationRef.current);
    }
    if (emojiRef.current) {
      emojiRef.current.remove();
    }
  }, []);

  return { throwEmoji, cleanup };
};

نحوه استفاده از آن

در اینجا یک مثال کامل از نحوه پیاده سازی ایموجی در کامپوننت React آورده شده است:

import React from 'react';
import { useEmojiThrow } from './useEmojiThrow';

const PlanningPokerRoom: React.FC = () => {
  const { throwEmoji } = useEmojiThrow();

  const handleEmojiClick = (emoji: string) => {
    // Assuming you have elements with these IDs in your DOM
    throwEmoji(emoji, "source-player-avatar", "target-player-avatar");
  };

  return (
    <div className="poker-room">
      <div id="source-player-avatar" className="avatar">
        Player 1
      </div>

      <div className="emoji-controls">
        <button onClick={() => handleEmojiClick("🎉")}>Throw Confetti</button>
        <button onClick={() => handleEmojiClick("👍")}>Throw Thumbs Up</button>
        <button onClick={() => handleEmojiClick("❤️")}>Throw Heart</button>
      </div>

      <div id="target-player-avatar" className="avatar">
        Player 2
      </div>
    </div>
  );
};

export default PlanningPokerRoom;

ویژگی های کلیدی

  1. حرکت طبیعی: از منحنی های Bezier درجه دوم برای حرکت صاف و قوس مانند استفاده می کند
  2. تصادفی سازی: تغییرات جزئی را به موقعیت ها و مسیرهای هدف اضافه می کند
  3. عملکرد: موارد استفاده requestAnimationFrame برای انیمیشن های روان
  4. پاکسازی: شامل پاکسازی مناسب انیمیشن ها و عناصر DOM است
  5. پشتیبانی TypeScript: برای تجربه بهتر توسعه دهنده کاملا تایپ شده است

جزئیات فنی

این انیمیشن توسط:

  1. محاسبه موقعیت های شروع و پایان از عناصر DOM
  2. ایجاد یک عنصر ایموجی موقت
  3. متحرک سازی آن در امتداد منحنی Bezier
  4. پاکسازی پس از تکمیل انیمیشن

را useEmojiThrow هوک تمام پیچیدگی ها را کنترل می کند و یک رابط ساده برای پرتاب ایموجی ها بین هر دو عنصر در صفحه شما فراهم می کند.

آن را در عمل ببینید

آیا می خواهید این کد را در یک محیط تولید مشاهده کنید؟ اتاق آزمایشی ما را بررسی کنید که در آن می‌توانید شکلک‌ها را به بازیکنان ربات پرتاب کنید یا جلسه پوکر برنامه‌ریزی خود را در Kollabe شروع کنید.

ملاحظات عملکرد

  • انیمیشن ها از تبدیل های CSS برای عملکرد بهتر استفاده می کنند
  • برای جلوگیری از نشت حافظه، عناصر به درستی تمیز می شوند
  • محاسبات بهینه شده و در صورت امکان ذخیره می شوند
  • فریم های انیمیشن در پاکسازی لغو می شوند

سفارشی سازی های بالقوه

شما به راحتی می توانید کد را تغییر دهید:

  • تنظیم مدت زمان انیمیشن
  • تغییر اندازه ایموجی
  • تغییر تصادفی مسیر
  • افکت‌های چرخش یا مقیاس‌بندی را اضافه کنید
  • توابع مختلف تسهیل را اجرا کنید

این همه چیز است

افزودن عناصر تعاملی مانند پرتاب ایموجی می تواند جلسات پوکر برنامه ریزی استاندارد را به تجربیات تیمی جذاب تبدیل کند. با خیال راحت از این کد در پروژه های خود استفاده کنید و اگر به دنبال راه حل آماده برای استفاده هستید، Kollabe را برای جلسات برنامه ریزی تیم خود امتحان کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا