Как добавить событие onClick по <canvas> и его элементам в React

Обработка клика по пустому canvas

Создадим компонент React, который будет реагировать на щелчок по элементу <canvas>. В консоль должно выводиться сообщение «Клик!».

В качестве эксперимента попросил написать код GPT:

import { useEffect, useRef } from 'react';
export default function Canvas() {
  // Создаём ссылку на элемент canvas
  const canvasRef = useRef(null);

  // Функция-обработчик клика
  function handleClick(e) {
    console.log('Клик!'); // Выводим в консоль сообщение «Клик!»
  }

  useEffect(() => {
    // Добавляем обработчик клика на холст при рендере компонента
    canvasRef.current.addEventListener('click', handleClick);
    return () => {
      // Удаляем обработчик при размонтировании компонента
      canvasRef.current.removeEventListener('click', handleClick);
    };
  }, []); // Второй аргумент useEffect — массив зависимостей, здесь он пустой, что означает, что эффект будет выполнен только один раз при первом рендере

  return (
    <canvas
      ref={canvasRef} // Присваиваем ссылку на canvas элементу canvasRef
      width="500"
      height="300" // Устанавливаем ширину и высоту холста
      style={{ border: '1px solid black' }} // Добавляем рамку
    ></canvas>
  ); // Возвращаем элемент canvas с атрибутами width, height и style
}

Даже без учета комментариев, код получился слишком «многословный». Чтобы его значительно сократить, добавим onClick={handleClick} в JSX, а о подкапотных нюансах позаботиться React.

export default function Canvas() {
  function handleClick() {
    console.log("Клик!");
  }

  return (
    <canvas
      width="500"
      height="300"
      style={{ border: "1px solid black" }}
      onClick={handleClick} // Одна строка и кода стало значительно меньше!
    ></canvas>
  );
}

Получение координат клика по холсту

При щелчке на канвасе мы можем, например, выводить координаты щелчка.

import React from 'react';

const CanvasComponent = () => {
  const handleClick = (event) => {
    // Получаем координаты щелчка
    const rect = event.target.getBoundingClientRect();
    const x = event.clientX - rect.left; // Учитываем смещение
    const y = event.clientY - rect.top;  // Учитываем смещение
    console.log(`Координаты щелчка: (${x}, ${y})`);
  };

  return (
    <div>
      <canvas
        onClick={handleClick}
        width={400}
        height={400}
        style={{ border: '1px solid black' }}
      ></canvas>
    </div>
  );
};

export default CanvasComponent;

Объяснение кода:

  1. handleClick — то функция-обработчик, которая вызывается при щелчке на канвасе. Мы используем event.target.getBoundingClientRect() для получения размеров и позиции канваса на экране. Затем вычисляем координаты щелчка относительно канваса.
  2. canvas -создаем элемент
  3. onClick — добавляем обработчик события onClick к элементу

Теперь, когда вы щелкнете по канвасу, в консоли появится сообщение с координатами щелчка.

Обработка клика по кругу на канвасе

На холсте нарисован круг и требуется добавить событие — при клики мыши по кругу выводить сообщение в консоль «Клик по кругу!»

Чтобы добавить обработку события клика мыши по кругу на элементе <canvas>, нужно выполнить следующие шаги:

  1. Определить координаты круга и его радиус.
  2. Обработать событие клика, чтобы проверить, попадает ли клик в круг.
  3. Если клик попадает в круг, выводить сообщение в консоли.

Чистый JavaScript

Вот пример кода на чистом JavaScript:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas Click Example</title>
</head>
<body>
    <canvas id="myCanvas" width="400" height="400" style="border:1px solid #000;"></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');

        // Параметры круга
        const circleX = 200; // координата X центра круга
        const circleY = 200; // координата Y центра круга
        const circleRadius = 50; // радиус круга

        // Функция для рисования круга
        function drawCircle() {
            ctx.beginPath();
            ctx.arc(circleX, circleY, circleRadius, 0, Math.PI * 2);
            ctx.fillStyle = 'blue';
            ctx.fill();
            ctx.closePath();
        }

        // Обработчик события клика
        canvas.addEventListener('click', function(event) {
            const rect = canvas.getBoundingClientRect();
            const mouseX = event.clientX - rect.left; // координата X мыши
            const mouseY = event.clientY - rect.top; // координата Y мыши

            // Проверка, попадает ли клик в круг
            const distance = Math.sqrt((mouseX - circleX) ** 2 + (mouseY - circleY) ** 2);
            if (distance <= circleRadius) {
                console.log('Клик по кругу!');
            }
        });

        // Рисуем круг
        drawCircle();
    </script>
</body>
</html>

Объяснение кода:

  • Мы создаем элемент.
  • Определяем параметры круга: его центр и радиус.
  • Функция drawCircle рисует круг на холсте.
  • Добавляем обработчик события клика на canvas. Когда пользователь кликает, мы рассчитываем координаты клика и проверяем, находится ли точка клика внутри круга, используя теорему Пифагора.
  • Если клик попадает в круг, выводим сообщение «Клик по кругу!» в консоли.

React

Если бы мы использовали React для реализации подобного функционала с элементом <canvas>, структура кода немного изменилась. В React мы бы использовали компоненты и состояние для управления рисованием и обработкой событий. Вот пример, как это можно сделать:

import React, { useRef, useEffect } from 'react';

const CanvasComponent = () => {
  const canvasRef = useRef(null);
  const circleX = 200; // координата X центра круга
  const circleY = 200; // координата Y центра круга
  const circleRadius = 50; // радиус круга

  // Функция для рисования круга
  const drawCircle = (ctx) => {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // очищаем холст
    ctx.beginPath();
    ctx.arc(circleX, circleY, circleRadius, 0, Math.PI * 2);
    ctx.fillStyle = 'blue';
    ctx.fill();
    ctx.closePath();
  };

  // Обработчик события клика
  const handleClick = (event) => {
    const rect = canvasRef.current.getBoundingClientRect();
    const mouseX = event.clientX - rect.left; // координата X мыши
    const mouseY = event.clientY - rect.top; // координата Y мыши

    // Проверка, попадает ли клик в круг
    const distance = Math.sqrt((mouseX - circleX) ** 2 + (mouseY - circleY) ** 2);
    if (distance <= circleRadius) {
      console.log('Клик по кругу!');
    }
  };

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    drawCircle(ctx);
    
    // Установка обработчика события клика
    canvas.addEventListener('click', handleClick);
    
    // Очистка обработчика при размонтировании компонента
    return () => {
      canvas.removeEventListener('click', handleClick);
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      width={400}
      height={400}
      style={{ border: '1px solid #000' }}
    />
  );
};

const App = () => {
  return (
    <div>
      <h1>Canvas Click Example in React</h1>
      <CanvasComponent />
    </div>
  );
};

export default App;

Объяснение кода:

  1. Использование useRef: мы используем useRef для получения ссылки на элемент <canvas>, Это позволяет нам взаимодействовать с элементом непосредственно.
  2. Функция drawCircle: эта функция рисует круг на холсте. Мы очищаем холст перед рисованием, чтобы избежать наложения.
  3. Обработчик клика: функция handleClick обрабатывает клики по холсту, аналогично предыдущему примеру.
  4. useEffect: этот хук используется для выполнения побочных эффектов. Мы рисуем круг и добавляем обработчик события клика при монтировании компонента. Также мы очищаем обработчик при размонтировании компонента, чтобы избежать утечек памяти.
  5. Компонент App: в этом компоненте мы просто рендерим наш CanvasComponent.

Этот подход позволяет легко управлять состоянием и эффектами в React, делая код более организованным и поддерживаемым.

Оставьте первый комментарий

Оставить комментарий

Ваш электронный адрес не будет опубликован.


*