canvas 태그 - 마우스로 그림 그리기

너구리오리·2021년 7월 26일
0
post-thumbnail

지난 포스트에서는 canvas 태그 기초와 좌표를 통한 도형 그리기에 대해 알아보았습니다.

하지만 좌표 계산은 어렵고 번거롭고, 또 실시간으로 도형을 그리려면 많은 응용이 필요합니다.
마우스나 터치펜 같은 입력 기기로 canvas 위에 그림을 그릴 수 있다면 훨씬 편리하겠죠?

이번 포스트는 마우스로 그림을 그리는 방법에 대해 알아보겠습니다.

그림판 만들기 프로젝트 시작

본 포스트 내용은 노마드 코더의 강좌 내용을 바탕으로 진행됩니다.
무료로 강좌 들으러 가기(광고아님, 스팸아님)

사실 본 포스트를 작성하기 전 몇 시간 동안 위 강좌를 들으며 canvas에 대해 공부했습니다.
아래가 그 결과물인데, 무료 강좌만 들어도 큰 도움이 되지만 아직 그림판에 지우개, 실행 취소, 올가미툴 등이 없어서 많이 아쉽습니다. 그래서 이번 시리즈를 통해 제가 직접 추가 구현해 볼 예정입니다.

너구리오리의 그림판 현재 결과물

프로젝트 설명

기본적인 캔버스 위에 마우스 포인터를 이용하여 그림을 그려봅니다.
HTML, CSS, JavaScript 를 모두 사용하여 구현합니다.

기본 코드 보기

먼저 코드부터 공유하겠습니다.
자세한 내용은 노마드 코더의 오리지널 강좌에서 확인할 수 있으니 생략하겠습니다.

이번 포스트에서는 기본 틀을 알아보고 다음 포스트부터 제가 추가로 구현한 부분에 대해서 더 자세히 설명하겠습니다.

HTML 코드 (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css" />
    <title>PaintJS</title>
</head>
<body>
    <canvas id="jsCanvas" class="canvas"></canvas>
    <script src="app.js"></script>
</body>
</html>

CSS 코드 (styles.css)

body {
    background-color: #f6f9fc;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, 
    Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 50px;
}

.canvas {
    width: 500px;
    height: 500px;
    background-color: white;
    border-radius: 15px;
    box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
}

JS 코드 (app.js)

const canvas = document.getElementById("jsCanvas");
const ctx = canvas.getContext("2d");

canvas.width = 500;
canvas.height = 500;

ctx.strokeStyle = "black";
ctx.lineWidth = 2.5;

let painting = false;

function startPainting() {
    painting=true;
}
function stopPainting(event) {
    painting=false;
}

function onMouseMove(event) {
    const x = event.offsetX;
    const y = event.offsetY;
    if(!painting) {
        ctx.beginPath();
        ctx.moveTo(x, y);
    }
    else {
        ctx.lineTo(x, y);
        ctx.stroke();
    }
}

if (canvas) {
    canvas.addEventListener("mousemove", onMouseMove);
    canvas.addEventListener("mousedown", startPainting);
    canvas.addEventListener("mouseup", stopPainting);
    canvas.addEventListener("mouseleave", stopPainting);
}

여기까지 3개의 파일을 한 폴더에 작성하신 후, index.html 파일을 인터넷 브라우저를 통해 실행하시면 그림판이 나타납니다.

어떻게 그림이 그려지는걸까?

위 코드 내용 중 몇 가지만 살펴보겠습니다.

EventListener

먼저 app.js 가장 아래에 EventListener 라는 내용들이 있습니다.
해당 코드 4줄은 "캔버스 위에서" 각각 해당하는 event가 발생하면 두 번째 인자로 지정된 함수를 수행하는 코드입니다.

각각의 event는 아래와 같습니다.

  • 마우스 커서가 움직일 때(move)
  • 마우스 버튼을 클릭할 때(down)
  • 마우스 버튼을 클릭한 손을 뗄 때(up)
  • 마우스 영역을 벗어날 때(leave)

startPainting() / stopPainting()

painting 이라는 bool 변수를 켜고 끕니다.

켜고 끄는 시점은 위에서 정한 이벤트에 따릅니다.

그렇다면 true/false 일 때 동작이 어떻게 다를까요?

먼저 프로그래밍을 해보신 분들이라면 변수 이름을 보았을 때 true이면 선이 그려지고, false 이면 선이 그려지지 않을 것이라 예상하실겁니다. 맞습니다.

해당 내용은 onMouseMove() 함수 안에 있습니다.

마우스를 누르지 않은 상태에서는 painting === false 이고,
계속해서 beginPath()와 moveTo()를 반복하며 시작점만 옮겨 다닙니다.

마우스를 누르고 있는 동안에는 painting === true 가 됩니다.
이때는 lineTo()와 stroke()이 반복 호출되며 연속해서 선이 그려집니다.

하지만 마우스의 위치(좌표)는 어떻게 컴퓨터가 아는 걸까요?

바로 event 속에 좌표 정보가 숨어있습니다.
onMouseMove() 함수는 event를 입력값으로 받은 후, event 속에 있는 offset 값을 가져와 (x, y) 좌표로 사용하고 있습니다.

event에 대해서는 나중에 다루어보도록 하겠습니다.

시리즈 포스팅 계획

무료 강좌 내용을 통해 그림판 클론 코딩을 완수하고 나면 우리가 알던 그림판보다 많이 부족한 것을 느끼실 겁니다.

일단 지우개, 부분 색칠 같은 기본적인 기능은 반드시 필요할 것 같고, 가능하다면 실행 취소도 있으면 좋을 것 같습니다.

그리고 마우스가 아닌 모바일, 태블릿(펜) 인터페이스에서도 동작하도록 구현하고 싶습니다.

나아가 올가미 툴, 복사/붙여넣기, 텍스트 박스도 구현 욕심은 있는데 구현이 어려울 것으로 예상됩니다.

처음엔 막막하지만 하나씩 배워가며 구현해보도록 하겠습니다.

참고자료

노마드 코더 강좌
https://nomadcoders.co/

니콜라스가 짱이야

0개의 댓글