캔버스 기본 세팅 for React


<aside> 💡 캔버스는 HTML 요소 중 하나로 스크립트 언어로 그림을 그리는데 사용한다.

</aside>

canvas를 사용하기 위해선 캔버스 context에 DOM으로 접근해야 한다. React에선 useRef()를 사용해서 Ref 객체를 만들고 접근하고 싶은 DOM의 ref 값으로 설정해주면 된다. 그럼 Ref 객체의 .current 값은 해당 DOM을 가리킨다.

캔버스 엘리먼트 생성 및 useRef 설정

import React, { useRef, useEffect, useState } from 'react';
import styled from 'styled-components';

const Canvas = () => {
	const canvasRef = useRef(null);

	// 생략
	return <DrawingArea ref={canvasRef} />
}

/* ----- 스타일 영역 ----- */
const DrawingArea = styled.canvas`
	// 생략
`

캔버스 사이즈 설정 및 드로잉 컨텍스트 참조

canvasRef의 기본값은 null이기 때문에 컴포넌트가 마운트 된 후 코드를 실행하도록 useEffect 안에다 코드를 작성한다.

아직 경험하진 못했지만 컴포넌트가 렌더되고 가끔 useRef 참조값이 null인 경우가 있다고. useState를 활용해 드로잉 컨텍스트를 상태로 저장하면 이런 경우를 방지할 수 있다고 함.

const Canvas = () => {
	const canvasRef = useRef(null);
	const [ctx, setCtx] = useState();

	useEffect(() => {
		// 캔버스 사이즈 설정
		const canvas = canvasRef.current;
		canvas.width = window.innerHeight; // 혹은 원하는 사이즈 px없이 숫자만 입력
		canvas.height = window.innerWidth; // 혹은 원하는 사이즈 px없이 숫자만 입력

		// 캔버스 context 접근 후 기본 설정
		const context = canvas.getContext('2d') // "그리기 메서드와 속성을 갖는" 2차원 드로잉 컨텍스트 참조
		context.strokeStyle = 'black'; // line 색
	  context.lineWidth = 3; // line 굵기
	  context.lineJoin = 'round'; // 선 연결 모양(기본 값 miter 일반 모양)
	  context.lineCap = 'round'; // 선 끝 모양
		context.save(); // 드로잉 컨텍스트 설정 저장
		setCtx(context) // 설정한 드로잉 컨텍스트를 상태로 저장
	}, [])
}

마우스 이벤트 핸들러 설정

<aside> 💡 offset 좌표는 이벤트가 걸려 있는 DOM 객체를 기준으로 좌표를 출력한다. canvas 요소에 이벤트를 걸었다면 브라우저 화면이 아닌 canvas 요소가 기준이 된다. offset 좌표의 기본값은 왼쪽 상단 (0, 0)

</aside>

캔버스에서 마우스로 그림을 그릴 때 이벤트 대상의 x(가로), y(세로) 좌표를 반환하는 offsetX offsetY가 필요하다. 리액트에선 성능 최적화를 위해 래핑된 합성 이벤트(Synthetic Event)를 전달하며 재사용된다.

하지만 이 합성 이벤트에선 offset 좌표를 사용할 수 없다. 핸들러에서 이벤트 객체를 콘솔로 찍어보면 offsetX, offsetY를 찾을 수 없다. — 참고 글

리액트에서 offset 좌표를 사용하려면 event.nativeEvent를 통해 브라우저의 고유 이벤트에 접근해야 한다. 매개변수 구조분해를 이용해 ({ nativeEvent })이런식으로 명시하면 사용하기 편하다.

const Canvas = () => {
	const [isDrawing, setIsDrawing] = useState(false); // 그리기 상태 설정
	const [path, setPath2D] = useState(new Path2D()); // path 객체 생성

	const startDrawing = ({ nativeEvent }) => {}
	const drawing = ({ nativeEvent }) => {}
	const finishDrawing = ({ nativeEvent }) => {}

  return (
    <DrawingArea
      ref={canvasRef}
      onMouseDown={startDrawing}
      onMouseUp={finishDrawing}
      onMouseMove={drawing}
      // onMouseLeave={finishDrawing} // 마우스가 이벤트 영역 벗어났을 때
    />
  );
};
  1. 캔버스 위에서 마우스를 움직이면 시작점을 마우스가 위치한 좌표로 이동 ctx.moveTo(x, y)
  2. 마우스를 클릭하면 그리기 상태롤 true로 변경하고
  3. 클릭한 상태에서 마우스를 드래그하면 선을 그린다. ctx.lineTo(x, y) ctx.stroke(x, y)