지 구 여 행

노마드코더/바닐라JS로 그림 앱 만들기/1. 그리기 기능 설정하기 본문

필기노트/노마드코더

노마드코더/바닐라JS로 그림 앱 만들기/1. 그리기 기능 설정하기

COSMOSUNION 2022. 10. 2. 14:11

 

그리기 기능 설정하기

선 두께 변경 / 색상 변경 / 그리기 / 채우기 / 지우기


마우스로 선 그리기

 

HTML

<body>
    <canvas id="canvas"></canvas>
</body>

Javascript

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

canvas.width = 300;
canvas.height = 300;

let isPainting = false;

function startPainting() {
  isPainting = true;
}

function stopPainting() {
  isPainting = false;
}

function onMove(event) {
  if (isPainting) {
    ctx.lineTo(event.offsetX, event.offsetY);
    ctx.stroke();
    return;
  }
  ctx.moveTo(event.offsetX, event.offsetY);
}
canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", stopPainting);
canvas.addEventListener("mouseleave", stopPainting);

 

함수 onMove()에서 ctx.moveTo()if(isPainting) 보다 뒤에 위치해야 기능이 정상적으로 작동합니다. isPainting 값이 true일 때, 즉 마우스를 누르고 있는 상태(mousedown)일 때는 return이 등장하는 지점에서 함수 onMove()가 종료되고 ctx.moveTo()를 실행시키지 않습니다.

 

isPainting값이 false일 경우 if(isPainting)을 건너뛰고 ctx.moveTo()가 실행됩니다.

 

 

선 굵기 변경하기

 

HTML

<body>    
    <input id="line-width" type="range" min="1" max="20" step="1" value="10" />
    <label for="line-Width">선 두께</label>
</body>

Javascript

const lineWidth = document.querySelector("#line-width");
ctx.lineWidth = lineWidth.value;

function stopPainting() {
  isPainting = false;
  ctx.beginPath(); // 매번 새 경로를 생성
}

function onLineWidthChange(event) {
  ctx.lineWidth = event.target.value;
}

lineWidth.addEventListener("change", onLineWidthChange);

 

  • ctx.lineWidth = lineWidth.value: 캔버스 선 두께의 초기값(lineWidth)을 슬라이더의 초기값(value)으로 설정
  • ctx.beginPath(): 캔버스 위에서 마우스 버튼을 눌렀다가 뗐을(mouseup)때나, 캔버스 밖으로 마우스 포인터가 이탈(mouseleave)할 때 실행되는 함수인 stopPainting()안에 ctx.beginPath()를 추가해야합니다. 새로운 선 또는 도형을 그릴 때마다 새 경로가 생성되기 때문에 슬라이더 값을 변경하여도 기존의 선 또는 도형들이 영향을 받지 않습니다. 

 

예제 1. 오류 - ctx.beginPath()를 추가하지 않은 경우

ctx.beginPath()를 추가하지 않으면 슬라이더 값이 변경될 때마다 캔버스의 모든 선 또는 도형들이 영향을 받습니다.

See the Pen error - ctx.beginPath() by cosmosunion (@cosmosunion) on CodePen.

 

 

색깔 변경하기

 

HTML

<body>
    <input id="color-picker" type="color" />
</body>

Javascript

const colorPicker = document.querySelector("#color-picker");

function onLineColorChange(event) {
  ctx.strokeStyle = event.target.value;
  ctx.fillStyle = event.target.value;
}

colorPicker.addEventListener("change", onLineColorChange);

 

 

그리기 모드 설정하기(채우기/선그리기)

 

HTML

<body>
    <button id="style-button">채우기</button>
</body>

Javascript

let isFilling = false;

function onModeChangeBtn() {
  if (isFilling) {
    isFilling = false;
    styleBtn.innerText = "채우기";
  } else {
    isFilling = true;
    styleBtn.innerText = "그리기";
  }
}

function onModeChange() {
  if (isFilling) {
    ctx.fillRect(0, 0, 300, 300);
  }
}

styleBtn.addEventListener("click", onModeChangeBtn);

 

 

지우기 모드 설정하기 (전체지우기/부분지우기)

 

HTML

<body>
    <button id="erase-button">지우기</button>
    <button id="destroy-button">전체삭제</button>
</body>

Javascript

const eraseBtn = document.querySelector("#erase-button");
const destroyBtn = document.querySelector("#destroy-button");

function onErase() {
  ctx.strokeStyle = "white";
  isFilling = false;
  styleBtn.innerText = "채우기";
}

function onDestroy() {
  ctx.save();
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, 300, 300);
  ctx.restore();
}

eraseBtn.addEventListener("click", onErase);
destroyBtn.addEventListener("click", onDestroy);

 

두 가지 방법으로 캔버스를 초기화 시킬 수 있습니다.

  • clearRect(x, y, width, height) : 캔버스와 같은 사이즈의 투명한 사각형 생성
  • fillRect(x, y, width, height) : 캔버스와 같은 사이즈의 흰색 사각형 생성 

메소드 clearRect()를 실행하면 캔버스와 같은 사이즈의 투명한 사각형이 생성됩니다. 이후 그린 이미지들은 파일 저장시 투명한 배경이 적용됩니다.

 

ctx.fillStyle = "white" + fillRect()를 실행하면, 캔버스와 같은 사이즈의 흰색 사각형이 생성되고 기존 이미지들은 덮어져서 출력되지 않습니다. 다만 메소드를 실행 후에 '채우기(fill)' 기능이 정상적으로 작동하지 않는 버그가 발생합니다. fillStyle이 colorPicker로 선택된 색상이 아닌 white로 변경되었기 때문입니다. save()restore() 를 이용하여 기존 스타일에 영향을 주지 않고 독립적으로 코드를 실행할 수 있습니다. 두 메소드 사이에 존재하는 변경사항은 저장되지 않기 때문입니다. 즉, fillStyle 값은 colorPicker로 선택된 색상으로 유지됩니다.

 

 

정리

See the Pen NomadCoder/VanillaJS/Meme-maker 1 by cosmosunion (@cosmosunion) on CodePen.

 

 

 

 

 

※ 참고자료

1. MDN web docs : https://developer.mozilla.org/ko/docs/Web/API/Canvas_API

2. 노마드코더/바닐라JS로 그림 앱 만들기 : https://nomadcoders.co/javascript-for-beginners-2

 

Comments