그림판 만들기 with vanillaJS

*본 포스트는 노마드코더 강의를 보고 정리하는 글입니다.

canvas API로 그림판을 만들었어요!

Canvas API는 JavaScript와 HTML < canvas > 엘리먼트를 통해 그래픽을 그리기위한 수단을 제공합니다.

-MDN

1. Html

<body>
  <canvas id="jsCanvas" class="canvas"></canvas>
  <div class="controls">
      <div class="controls_range">
          <input type="range" id="jsRange" min="0.1" max="5.0" value="2.5" step="0.1"/>
      </div>
      <div class="controls_btns">
          <button id="jsMode">Fill</button>
          <button id="jsSave">Save</button>
      </div>
      <div class="controls_colors" id="jsColors">
          <div class="controls_color jsColor" style="background-color: #2c2c2c;"></div>
          <div class="controls_color jsColor" style="background-color: white;"></div>
          <div class="controls_color jsColor" style="background-color: #FF3B30;"></div>
          <div class="controls_color jsColor" style="background-color: #FF9500;"></div>
          <div class="controls_color jsColor" style="background-color: #FFCC00;"></div>
          <div class="controls_color jsColor" style="background-color: #4CD963;"></div>
          <div class="controls_color jsColor" style="background-color: #5AC8FA;"></div>
          <div class="controls_color jsColor" style="background-color: #0579FF;"></div>
          <div class="controls_color jsColor" style="background-color: #5856D6;"></div>
      </div>
  </div>
  <script src="app.js"></script>
</body>

먼저 html은 위와 같이 작성했습니다.
canvas 태그는 그림을 그리기 위한 판을 만든 것입니다. controls라는 영역 안에는 펜의 굵기(controls_range), 드로잉 방식과 저장 버튼(controls_btns), 색상(controls_colors)이 있어요.

펜의 굵기를 조절할 때는 input의 속성값으로 type="range"를 했습니다. min, max, value(기본값), step(얼만큼씩 움직일지)을 설정해 줍니다.

2. vanillaJS

다음은 자바스크립트로 어떻게 구현했는지 알아볼까요?
총 9개의 함수를 만들어서 구현했습니다.

1) stopPainting(), startPainting()

//1. 그림 그리기를 멈추는 기능
function stopPainting() {
  painting = false;
}

//2. 그림 그리기를 하는 기능
function startPainting() {
  painting = true;
}

canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", stopPainting);
canvas.addEventListener("mouseleave", stopPainting);

캔버스는 document.getElementById 를 통해 canvas 변수명에 할당했습니다. 캔버스를 클릭할 때, 그림 그리기를 시작하고, 손을 떼면 멈추도록 구현했습니다. 또, 캔버스 밖으로 마우스가 나가면 그림 그리기를 멈추도록 했습니다.

2) onMouseMove()

const ctx = canvas.getContext("2d");
  
//3. 마우스를 움직일 때, x,y좌표를 읽고 선을 그리는 기능
function onMouseMove(event) {
    const x = event.offsetX; //event 안에는 offset X,Y좌표를 가져올 수 있음
    const y = event.offsetY;
    if(!painting){
        ctx.beginPath();
        ctx.moveTo(x, y);
    } else {
        ctx.lineTo(x, y);
        ctx.stroke();
    }
}
  
canvas.addEventListener("mousemove", onMouseMove);

마우스를 움직일 때, 선을 그리는 기능입니다.

const ctx = canvas.getContext("2d");
이 코드에 관한 아래 설명을 확인해 주세요!

< canvas > 요소는 getContext() 메서드를 이용해서, 랜더링 컨텍스트와 (렌더링 컨텍스트의) 그리기 함수들을 사용할 수 있습니다. getContext() 메서드는 렌더링 컨텍스트 타입을 지정하는 하나의 파라메터를 가집니다.

-MDN

그림을 그리기 위한 기본 설정인데, 우리는 기본적인 선을 그릴 것이기 때문에 "2d"로 파라메터를 지정해 줍니다.

beginPath()
새로운 경로를 만듭니다. 경로가 생성됬다면, 이후 그리기 명령들은 경로를 구성하고 만드는데 사용하게 됩니다.

moveTo(x, y)
펜을 x와 y 로 지정된 좌표로 옮깁니다

lineTo(x, y)
현재의 드로잉 위치에서 x와 y로 지정된 위치까지 선을 그립니다.

stroke()
윤곽선을 이용하여 도형을 그립니다.

-MDN

각 메소드에 대한 설명입니다!

이 함수의 과정을 설명해 보자면,

먼저 마우스의 X, Y좌표를 가져옵니다.
그림을 그리지 않는 상태일 때(!painting), 펜의 새로운 경로를 만들고, 마우스가 움직이는대로 펜의 X, Y좌표를 옮겨줍니다.
(마우스를 클릭하는 순간 그 위치부터 그림을 그려야 하기 때문입니다.)
그림을 그리는 상태일 때(painting), 지정된 위치까지 선을 만들고, 그림을 그립니다.
(stroke()이 없으면 그림이 안그려집니다!)

마우스가 움직일 때, 이 기능을 사용해야 합니다. 따라서
canvas.addEventListener("mousemove", onMouseMove);
로 구현했습니다.

3) handleColorClick()

색상을 정하는 기능입니다.

const colors = document.getElementsByClassName("jsColor");

function handleColorClick(event) {
  const color = event.target.style.backgroundColor;
  ctx.strokeStyle = color;
  ctx.fillStyle = color;
}

Array.from(colors).forEach(color => color.addEventListener("click", handleColorClick));

색상은 여러가지가 있었죠. 이들을 배열로 묶어줍니다. forEach를 통해 배열에 있는 요소 하나하나에 접근해서 click이 되는 요소로 색상을 바꿔주는 과정입니다.

ctx.strokeStyle = color;
ctx.fillStyle = color;

이 코드가 색상을 지정하는 코드입니다.

4) handleRange()

function handleRange(event) {
    ctx.lineWidth = event.target.value;
}
  
if(range) {
    range.addEventListener("input", handleRange);
}

펜의 굵기를 조절하는 코드입니다.
ctx.lineWidth = event.target.value;
를 통해 펜의 굵기를 설정했습니다.

5) handleModeClick(), handleCanvasClick()

// 6. 버튼 클릭하면 텍스트 변경되는 기능
function handleModeClick(event) {
   if(filling) {
       filling = false;
       mode.innerText = "Fill"
   } else {
       filling = true;
       mode.innerText = "Paint"
   }
}
 
//7. 캔버스 클릭하면 색 채워지는 기능 
 function handleCanvasClick() {
   if(filling) {
       ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
   }
}

이 기능은 캔버스 위에 그림을 그릴 것이냐, 클릭하면 전체가 칠해지도록 할 것이냐를 고르는 기능입니다.

버튼을 클릭하면 text가 변경되는 코드입니다. innerText로 구현할 수 있습니다.

ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);

캔버스의 크기만큼 채워진 직사각형을 만들겠다는 의미입니다. 즉, 캔버스 전체를 칠하는 것이죠.

6) handleCM(), handleSaveClick()

function handleCM(event) {
  event.preventDefault();
}

function handleSaveClick() {
  const image = canvas.toDataURL("image/jpeg");
  const link = document.createElement("a");
  link.href = image;
  link.download = "paintJS[EXPORT]";
  link.click();
}

canvas.addEventListener("contextmenu", handleCM);

마지막을 jpg 파일로 저장하는 코드입니다. contextmenu를 클릭하면, 즉, 우클릭을 막아줍니다. handleCM()이 그 코드입니다! 우리는 저장 버튼을 클릭해서 저장하게 할 것이기 때문에 우클릭을 방지합니다.

handleSaveClick()이 함수가 jpg로 저장하는 코드입니다. 임의의 링크를 만들고, download 속성을 추가하면 다운이 가능합니다! 다운로드 속성에는 "저장될 파일명"을 정해줍니다.

이렇게 하면 완성입니다! canvas API를 살펴보고, 도형을 만드는 기능, 텍스트 박스를 추가하는 기능 등을 추가해보면 더 좋을 것 같아요!! 더 많은 기능이 있으니 꼭 한 번 찾아보시는 걸 추천드려요😉

포스트는 여기까지 하고, 전체 코드 올려두고 가겠습니다~

*본 포스트는 노마드코더 강의를 보고 정리하는 글입니다.

좋은 웹페이지 즐겨찾기