Skip to content

4. 라이브러리 없이 Canvas 구현하기

D.Joung edited this page Dec 5, 2024 · 6 revisions

🪵 세부 기술 로그

  1. Canvas 마스터 클래스
  2. canvas 기본 기능 주요 이슈 및 해결
  3. 보간법 적용 및 커서 보정
  4. Canvas Undo, Redo 구현 - path 단위 관리
  5. 캔버스 성능 최적화 시도 - requestAnimationFrame, throttle, offscreenCanvas
  6. 캔버스 활용하여 불규칙 패턴 & 커스터마이징 커서 제작

Canvas API란?

Canvas API는 HTML Element를 통해 화면에 그리기를 할 수 있는 JavaScript 도구들을 제공합니다. 주로 2D 그래픽에 중점을 두고 있으며 CanvasRenderingContext2D 객체로 2D 비트맵 이미지를 그릴 수 있습니다.

  • 프로젝트 주요 구현 주제 중 하나인 실시간 드로잉 기능을 구현하기 위해서는, 플레이어들이 그림을 그려갈 캔버스를 구현해야 했습니다.
  • 캔버스를 구현할 수 있는 다양한 라이브러리들이 있지만, 캔버스에 대한 깊은 이해외부 의존성 최소화 를 도전 과제로 삼고 라이브러리 없이 Canvas API만을 활용해 구현해보기로 했습니다.
  • 이를 위해 Canvas API를 직접 다뤄보는 것은 처음이었기에 작동 원리와 기초 사용법에 대한 학습이 선행되어야 했습니다.

기본 로직

  • 팀원들과 상의해 캔버스 기능을 아래와 같이 구현하기로 정했습니다.
    • 펜 툴 : 마우스의 경로를 따라 선을 드로잉
    • 페인트 툴 : 픽셀 잔여량 만큼 클릭한 좌표를 중심으로 색을 채움
    • 색상 선택 툴 : 색상을 변경할 수 있음
    • 두께 조절 툴 : 펜 툴의 선 두께를 변경할 수 있음
    • Undo / Redo : 내가 그린 선 한정으로 캔버스 상태를 뒤로가기 및 복구
    • 픽셀 잔여량 표시 : 사용 가능한 잔여 픽셀량을 표시
  • MouseEvent 및 TouchEvent를 활용해 사용자와 상호작용 하였고, 구현 과정에서 아래와 같은 이슈 & 구현 과제가 발생했습니다.
    • 캔버스 터치 시 화면이 같이 움직임 (화면 스크롤링이 활성화)
    • MouseEvent와 TouchEvent가 제공하는 좌표 속성이 다름
    • 캔버스 페인트 툴 기능 구현

캔버스 사용성 최적화

  • Undo & Redo 제외한 캔버스의 기본 기능이 모두 구현된 후, 사용자 경험을 헤칠 수 있는 두 가지 이슈가 발생했습니다.

    1. 빠르게 그렸을 때 캔버스 모서리에서 선이 끊김
    2. 선을 그릴 때 (샘플링 좌표 기준으로) 각이 짐
    3. 선이 마우스를 조금 늦게 따라옴
  • 1, 2번 이슈는 드로잉 로직에 보간법을 추가해 해결하였습니다.

  • 하지만 보간법은 드로잉 로직과 관련이 있고, 드로잉 로직은 CRDT 및 소켓 연결과 관련이 있었기에, CRDT 작업이 완료되기까지 병합이 연기되었습니다.

  • 모든 기능이 구현된 6주 차, 빠르게 그렸을 때 캔버스 모서리에서 선이 끊김 이슈는 CPU 작업량 문제로 지연이 발생해 적용을 미루게 되었고, 선을 그릴 때 (샘플링 좌표 기준으로) 각이 짐 이슈 개선 내용만 적용하게 되었습니다.


Undo / redo 프로토타입 구현

  • Undo & Redo 구현은 1인용 캔버스에서는 구현이 매우 단순했지만, 동시 편집 캔버스에서는 난이도가 상승했습니다.
  • 또한, Undo & Redo는 CRDT 로직과도 연관이 있어, Canvas 단에서는 이후 CRDT 로직 구현 시 참고할만한 기능 프로토타입을 먼저 만들어보기로 했습니다.
  • 이후 Undo & Redo 구현 로직은 CRDT 로직 구현과 병행 작업되어, stroke 단위 관리 로 구현되었다가, 다시 path 단위 관리 로 변경되어 최종 구현 되었습니다.

캔버스 성능 최적화 시도

  • 4-5주차에는 윈도우에서 그리면 렉이 심해지는 이슈가 발생했습니다.
  • 해당 이슈는 CRDT 로직 단에서 주요하게 수정해야할 점들이 있었지만, 캔버스 측에서도 최적화 할 수 있는 방안을 몇 가지 시도해보았습니다.
  • 아래 세 가지 측면에서의 최적화를 시도하였고, 결과적으로 시작 페이지의 캔버스에만 requestAnimationFrame 및 throttle을 추가하였습니다.
    • requestAnimationFrame으로 좌표 전송 및 드로잉 주기 최적화 (시작 페이지)
    • throttle로 좌표 샘플링 주기 최적화 (시작 페이지)
    • OffScreenCanvas로 GPU 단에서의 렌더링 (미적용)

캔버스 활용 - 패턴 제작 & 커서 커스터마이징

  • 캔버스 배경화면에 들어갈 패턴 이미지를 제작해야했는데, 캔버스에서 랜덤한 위치에 패턴을 찍은 후 export 하였습니다.

  • 또한, 꼬리가 길게 이어지는 모양의 커스텀 커서를 제작했습니다.

  • 커스텀 커서는 게임 캔버스에서도 선이 마우스를 조금 늦게 따라오는 사용성 이슈를 해결하기 위해 적용되었습니다.

😎 웨베베베벱

👮🏻 팀 규칙

💻 프로젝트

🪵 웨베벱 기술로그

🪄 데모 공유

🔄 스프린트 기록

📗 회의록

Clone this wiki locally