Canvas API 활용: 웹 브라우저 자바스크립트 그림판 만들기

안녕하세요!

벌써 여섯 번째 미니 프로젝트네요. 오늘은 웹 브라우저 위에 자유롭게 그림을 그릴 수 있는 ‘자바스크립트 그림판’을 만들어 보았습니다. 단순히 선을 긋는 기능을 넘어, 실제 사용자가 편리하게 도구를 전환하고 그림을 지울 수 있는 로직까지 고민해 본 시간이었는데요.

자바스크립트의 Canvas API는 처음 접하면 조금 생소할 수 있지만, 한 번 원리를 깨우치면 이만큼 강력하고 재밌는 도구도 없는 것 같습니다. 이번 포스팅에서는 제가 어떤 고민을 하며 그림판을 설계했는지, 그리고 초보자분들도 쉽게 따라 할 수 있는 핵심 포인트는 무엇인지 자세히 정리해 보겠습니다.

자바스크립트 그림판 메인 이미지

1. 설계: 마우스의 움직임을 데이터로 읽어오기

그림판의 가장 기본은 “내가 마우스를 누르고 움직일 때만 선이 그려져야 한다”는 것입니다. 이를 구현하기 위해 저는 상태 관리(State Management) 방식을 사용했습니다.

  • isPainting: 현재 그림을 그리는 중인지 아닌지를 알려주는 ‘스위치’ 역할을 합니다.
  • 이벤트 리스너: mousedown(누를 때), mousemove(움직일 때), mouseup(뗄 때)이라는 세 가지 이벤트를 감시합니다.

여기서 한 가지 팁을 드리자면, 마우스를 캔버스 안에서 떼지 않고 영역 밖으로 나갔을 때도 그림 그리기가 멈춰야 합니다. 그렇지 않으면 다시 캔버스로 들어왔을 때 의도치 않은 선이 쭉 그려지는 버그가 생기거든요. 그래서 저는 mouseleave 이벤트에도 드로잉을 멈추는 로직을 추가해 사용자 경험을 개선했습니다.

2. 자바스크립트 그림판 핵심 로직: 지우개는 사실 ‘흰색 펜’이었다?

자바스크립트 그림판의 하이라이트는 지우개 기능의 구현이었습니다. 처음에는 “그려진 픽셀을 어떻게 지우지?”라고 어렵게 생각하실 수 있어요. 하지만 아주 간단하고 명쾌한 해답이 있습니다. 바로 도화지 색상과 똑같은 ‘흰색’으로 덧칠하는 것이죠!

// 드로잉 모드에 따른 로직 분기
function draw(e) {
    if (!isPainting) return;

    // 현재 지우개 모드라면 흰색(#ffffff)을, 아니면 사용자가 고른 색을 선택합니다.
    ctx.strokeStyle = isEraser ? "#ffffff" : colorPicker.value;
    ctx.lineWidth = lineWidthInput.value;

    // 마우스 위치로 선을 연결합니다.
    ctx.lineTo(x, y);
    ctx.stroke();
    
    // 이 부분이 핵심! 경로를 계속 갱신해줘야 선이 끊기지 않고 부드럽게 이어집니다.
    ctx.beginPath();
    ctx.moveTo(x, y);
}

이처럼 삼항 연산자를 활용해 한 줄의 코드로 펜과 지우개를 전환하도록 설계했습니다. 이렇게 하면 코드가 훨씬 깔끔해지고 유지보수도 쉬워집니다. 펜 굵기를 조절하면 지우개 크기도 같이 커지니, 넓은 면적을 지울 때도 아주 편리하겠죠?

3. 시행착오: 캔버스 좌표 정확하게 읽기

개발하면서 가장 신경 썼던 부분은 ‘마우스 포인터의 위치’와 ‘선이 그려지는 위치’를 정확히 일치시키는 것이었습니다.

브라우저 전체에서의 마우스 위치(clientX)와 캔버스 도화지 안에서의 위치는 서로 다릅니다. 그래서 getBoundingClientRect()라는 메서드를 사용해 캔버스가 화면 어디에 있는지 먼저 계산한 뒤, 그 값을 마우스 위치에서 빼주는 과정이 필요합니다. 이 계산이 틀리면 내가 클릭한 곳이 아닌 엉뚱한 곳에 그림이 그려지게 되니, 혹시 직접 만드시는 분들이 있다면 이 좌표 계산 부분을 꼭 체크해 보세요!

→ 좌표값은 console.log()를 활용하여 출력해보면 쉽게 알 수 있습니다.

4. 디자인과 UX: 펜과 지우개, 시각적으로 구분하기

기능만큼 중요한 것이 디자인이죠. 사용자가 지금 펜을 들었는지, 지우개를 들었는지 헷갈리지 않도록 현재 활성화된 버튼에 강조 효과(Active 클래스)를 주었습니다. CSS로 선택된 버튼의 배경색을 다르게 설정하고, 자바스크립트로 버튼 클릭 시 클래스를 뺐다 끼워넣는 간단한 조작만으로도 훨씬 ‘앱다운’ 완성도가 느껴지게 되었습니다.

저는 지금 간단하게 만들다보니 텍스트로 버튼 이름을 설정하였지만, 이모지나 이미지를 추가하여 버튼을 만들면 더 멋있는 그림판이 될 것 같습니다.

5. 실행 화면

자바스크립트 그림판 실행 영상

6. 앞으로 더 보완하고 싶은 점

오늘 만든 그림판은 기본기에 충실했지만, 앞으로 추가하고 더 보강해야 될 부분들이 아주 많습니다.

  • 이미지 다운로드: 내가 그린 작품을 PNG나 JPG 파일로 저장하여 내보내는 기능을 추가해보면 좋을 것 같습니다.
  • Undo(되돌리기), Redo(다시하기): 실수로 선을 잘못 그었을 때 Ctrl+Z처럼 이전 상태로 되돌리는 기능과 Ctrl+Y와 같이 다시 앞으로 돌리기 같은 기능을 추가하면 훨씬 사용자가 그림판을 사용하기 편할 것 같습니다. 또, 지금은 마우스 클릭으로만 모든 기능을 사용하지만, 키보드의 단축키도 사용할 수 있도록 추가하면 좋을 것 같습니다.
  • 도형 도구: 지금은 그리기 기능만 있지만 직선, 원, 사각형과 같은 도형들을 그릴 수 있는 기능을 추가하면 더욱 그럴싸한 자바스크립트 그림판이 될 것 같습니다.

이번 프로젝트는 단순히 코드를 짜는 것을 넘어, 사용자의 움직임을 어떻게 시각적으로 부드럽게 표현할 것인가를 깊이 고민해 본 시간이었습니다. 캔버스 위에서 자유롭게 움직이는 선들을 보니, 우리가 사용하는 복잡한 디자인 툴들도 결국 이런 기초적인 로직에서 시작되었다는 게 새삼 신기하게 다가오네요.

Canvas 위에서 마우스를 빠르게 움직일 때 선이 끊겨 보이는 현상을 해결하는 과정이 가장 기억에 남습니다. 단순히 점을 찍는 게 아니라 lineTo()와 stroke()를 연결해 부드러운 곡선을 만드는 로직을 구현하며 캔버스 렌더링의 원리를 깊이 이해할 수 있었습니다. 웹에서 그래픽을 다루는 기초를 다지고 싶은 분들께 이 프로젝트를 강력히 추천합니다.

캔버스 조작에 익숙해지면 훨씬 복잡한 시각 효과인 [자바스크립트 스크래치 카드 제작] 프로젝트도 충분히 도전하실 수 있습니다.

제 글이 그림판 구현을 고민하시는 분들에게 조금이나마 도움이 되었으면 좋겠습니다. 혹시 코드를 짜다가 막히는 부분이 있거나 더 좋은 아이디어가 있다면 언제든 댓글로 소통해 주세요! 우리 함께 꾸준히 성장해 봐요. 🙂

댓글 남기기