Frontend study 일지 #5 - React에서 TypeScript로 html canvas 사용하기

이유미·2022년 11월 10일
0

frontend-study

목록 보기
5/5

참고 사이트
https://velog.io/@mokyoungg/JS-JS에서-Canvas-사용하기마우스로-그리기
https://basketdeveloper.tistory.com/79
https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html

html canvas tag란?

  • 웹에서 그림을 그릴 수 있는 html 요소
  • JS를 통해 그림을 그리고 애니메이션과 이벤트 처리 등의 작업을 할 수 있다
  • canvas API는 주로 2D 그래픽에 중점을 두고 있다.

html canvas tag 특징

  1. class, id, style 등의 모든 html 요소들이 사용할 수 있는 글로벌 속성을 가짐

    HTML Global Attributes The global attributes are attributes that can be used with all HTML elements.

  1. 캔버스 크기인 width, height 속성을 필수로 제공해야 한다.

    css를 통해 너비와 높이 값을 제공하면 오류가 발생할 가능성이 있다. 사용하게 될 경우 바로 tag에서 제공하는 습관을 들이자.

    ※ 웹에서 이미지를 불러와서 canvas의 background-image 속성값으로 제공해서 canvas의 바탕화면에 이미지를 설정하는 작업을 했었다. 이 때 미리 canvas에 width와 height를 제공하지 않으면 이미지가 잘려서 일부만 보이는 렌더링 오류를 보였다 => Image객체에서 onload시 이미지의 width와 height를 미리 알아내어 canvas tag에 제공하니 문제가 해결되었다.

(...)

const [isLoading, setIsLoading] = React.useState<boolean>(false); //로딩 state 관리 부분
React.useEffect(() => {
    const img = new Image();
    if (imageSource !== undefined) {
      img.src = imageSource; //JS로 이미지 객체에 이미지 소스 uri를(imageSource) 제공
    }
    img.onload = function () {
      setIsLoading(false); 
      setImageFigure({ width: img.width, height: img.height }); //이미지 크기를 imageFigure라는 객체 형태의 상태로 관리하여 canvas tag에 각각 width와 height props로 제공
    };
  }, [imageSource, setIsLoading]);
  
  (...)
  
  return (
    <>
      <SelectButton
        isSelected={mode.isSelectModeOn}
        onClick={() => setMode({ isSelectModeOn: true, isCreateModeOn: false })}
      />
      <CreateButton
        isSelected={mode.isCreateModeOn}
        onClick={() => setMode({ isSelectModeOn: false, isCreateModeOn: true })}
      />

      <Main>
        <div>
        {/* 로딩중일 때에는 Loading... 텍스트 렌더링 */}
          {isLoading === true && <LoadingText>Loading...</LoadingText>} 
          
         {/* 이미지 uri가 undefined가 아닐 경우에 canvas 컴포넌트 렌더링 */}
          {imageSource !== undefined && (
            <Canvas
              ref={canvasRef}
              imgSrc={imageSource}
              width={imageFigure.width}
              height={imageFigure.height}
              (...)
              }}
            />
          )}
        </div>
      </Main>
    </>
  );
};

참고 사이트 : https://bbuljj.tistory.com/m/96

  1. window.onload 시 캔버스를 그릴수 있도록 짜는 것이 좋다.

React에서 TS로 canvas 사용해보기

  1. canvas 요소에 직접 접근해야 canvas에서 드로잉 컨텍스트를 뽑아서 활용할 수 있다. => DOM 요소에 직접 접근해야하기 때문에 useRef()를 사용한다. DOM을 건드리는 목적으로 useRef() 사용시 기본값은 null로 제공 + type을 'HTMLCanvasElement'같이 HTML~~Element 로 지정
const canvasRef = React.useRef<HTMLCanvasElement>(null);
  1. 캔버스 태그에 children으로 텍스트컴포넌트, html 요소를 넣으면 children은 캔버스가 호환되지 않는 브라우저에서만 보이게 된다!! 하위 레벨로 어떤 것도 넣으면 안된다. 다른 컴포넌트를 렌더링하고 싶으면 캔버스 태그 사이에 children으로 들어가게 코드를 짜면 안되고 반드시 동일한 레벨의 형제 관계로 넣어
    => canvas 태그가 '컨테이너' 요소라서 div처럼 레이아웃 역할도 하는 줄 알았는데 아니었다. 정확한 이유는 아직 모른다. canvas 태그를 뜯어봐야 알 수 있을 것 같다

  2. getContext("2d") 메서드 => 캔버스의 드로잉 컨텍스트를 받는다. getContext()메서드를 할당한 캔버스를 기준으로 그림을 그리는 기능들이 작동한다고 생각하면 된다.
    => ref의 current에서 바로 getContext()를 호출하면 "Object is possibly 'null'" 에러가 발생한다. 아래를 확인할 것!

//1번 예시에서 이어짐
const canvasCtx = canvasRef.current.getContext('2d'); //Error : canvasRef.current is possibly 'null'

//캔버스 요소에서 가져온 드로잉 컨텍스트는 상태로 관리 해줘야한다. *type 주의*
  const [canvasCtx, setCanvasCtx] = React.useState<CanvasRenderingContext2D>();
  
  React.useEffect(() => {
    const tempCanvas : HTMLCanvasElement | null = canvasRef.current;
    const tempContext : CanvasRenderingContext2D | null =
      tempCanvas === null ? null : tempCanvas.getContext("2d"); //조건부로 null 핸들링 => 일부러 null 반환함
      //DO NOT USE '&&' => tempContext type으로 boolean이 반환 될 수 있기 때문에!!
      //tempCanvas !== null && tempCanvas.getContext('2d'); //(X) tempContext type => CanvasRenderingContext2D | null | false
    tempContext !== null && setCanvasCtx(tempContext);
  }, []);
  1. 캔버스 내의 마우스 위치는 이벤트 객체의 offsetX, offsetY 속성을 사용한다. 그냥 이벤트 객체에서 바로 가져오면 에러 발생, event.nativeEvent에서 가져와야한다.
   const x = e.nativeEvent.offsetX; //이벤트 발생시 마우스의 x 좌표
   const y = e.nativeEvent.offsetY; //이벤트 발생시 마우스의 y 좌표
  1. 만약 경로를 이용하여 선을 그릴 때는 몇 가지 추가적인 단계를 거쳐야 한다. -> 우선 경로를 생성 -> 그 다음 그리기 명령어를 사용하여 경로상에 그립니다. -> 경로가 한번 만들어졌다면, 경로를 렌더링 하기 위해서 윤곽선을 그리거나 도형 내부를 채울 수 있다

  2. 캔버스의 드로잉 컨택스트에서 사용할 수 있는 대표적인 메서드와 속성

    (속성)

    • 선의 색 : strokeStyle
    • 선의 굵기 : lineWidth
    • 선의 끝모양 : lineCap

    (메서드)

    • beginPath() //path 시작. 경로 시작점 초기화
    • moveTo() //좌표를 옮김
    • closePath() //path 종료.(눈에 보이는 동작은 없음)
    • fill() //
    • stroke() //실제로 화면에 라인을 그림
    • lineTo() //인자로 전달된 x,y좌표를 라인의 도착점으로 설정
profile
신입 프론트엔드 개발자 구직중

0개의 댓글