오늘의 결과물

 

- 자바스크립트는 항상 event 라는 점 기억

- ctx.moveTo(0, 0)을 해야 첫 시작점에서 선이 출발한다

- Math.random을 사용해서 랜덤 색상을 그릴 수 있도록 한다 (정수로 바꾸기 위해 Math.floor로 감싸기)

- mousemove로 마우스가 이동할 때마다 해당 위치로 선이 그어지도록 한다

 

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
ctx.lineWidth = 2;

const colors = [
  "#ff3838",
  "#ffb8b8",
  "#c56cf0",
  "#ff9f1a",
  "#fff200",
  "#32ff7e",
  "#7efff5",
  "#18dcff",
  "#7d5fff",
];

function onClick(event) {
  ctx.beginPath();
  ctx.moveTo(0, 0);
  const color = colors[Math.floor(Math.random() * colors.length)];
  ctx.strokeStyle = color;
  ctx.lineTo(event.offsetX, event.offsetY);
  ctx.stroke();
}

canvas.addEventListener("mousemove", onClick);

 

 

마우스 클릭한 채로 움직일 때 그림 그려지게 하기

- offsetx와 isPainting 활용

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
ctx.lineWidth = 2;
let isPainting = false;

function onMove(event) {
  if (isPainting) {
    ctx.lineTo(event.offsetX, event.offsetY);
    ctx.stroke();
    return;
  }
  ctx.moveTo(event.offsetX, event.offsetY);
}

function startPainting() {
  isPainting = true;
}

function cancelPainting() {
  isPainting = false;
}

function onMouseLeave() {
  isPainting = true;
}

canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", cancelPainting);
canvas.addEventListener("mouseleave", cancelPainting);

 

 

- moveTo는 우리가 선을 긋지 않으면서 브러쉬를 움직이게 해준다. 

-> 유저가 canvas 위에서 마우스를 움직일 때마다 moveTo 호출

 

- isPainting 이 true라면, stroke를 써서 선을 그리고 함수를 끝내줄거임

if (isPainting) {
    ctx.lineTo(event.offsetX, event.offsetY);
    ctx.stroke();
    return;
  }

- 만약 isPainting이 false라면, 조용히 브러쉬만 움직여줄거임

ctx.moveTo(event.offsetX, event.offsetY);

- 캔버스 밖으로 마우스를 움직였다가 다시 돌아올 때, 계속 그리고 있는 버그 막기 위한 코드

function onMouseLeave() {
  isPainting = true;
}

canvas.addEventListener("mouseleave", cancelPainting);

 

선 굵기 조정하는 기능 구현

 

- line-width라는 id의 input을 만들어준다

- 이 range 타입의 인풋을 조절하면 선 굵기도 바뀌게 함

- if 문 뒤에 ctx.beginPath();로 끊어줌. 선 굵기 바꾸는 이벤트마다 따로 바뀌게 함. 이렇게 끊어주지 않으면 선 굵기가 바뀔 때 여태까지 그린 선들의 굵기가 전부 마지막 설정대로 바뀌기 때문. 사용자가 선을 그린 후 새로운 path가 시작되게 함.

- (html) range 타입의 다른 attribute 로는 step이 있다. step = "0.1" 이렇게 하면 범위 내 구간 설정을 더 상세하게 할 수 있다.

<input id="line-width" type="range" min="1" max="10" value="5" step="0.1" />

여기까지의 js 코드

const lineWidth = document.getElementById("line-width");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
ctx.lineWidth = lineWidth.value;
let isPainting = false;

function onMove(event) {
  if (isPainting) {
    ctx.lineTo(event.offsetX, event.offsetY);
    ctx.stroke();
    return;
  }
  ctx.beginPath();
  ctx.moveTo(event.offsetX, event.offsetY);
}

function startPainting() {
  isPainting = true;
}

function cancelPainting() {
  isPainting = false;
}

function onMouseLeave() {
  isPainting = true;
}

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

canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", cancelPainting);
canvas.addEventListener("mouseleave", cancelPainting);

lineWidth.addEventListener("change", onlineWidthChange);

 

 

사용자가 브러쉬 색상 선택할 수 있게 하기

이건 아주 쉬움! 굵기 선택 기능과 유사하게 설정 가능

 

html

<input id="color" type="color" />

 

js

const color = document.getElementById("color");

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

color.addEventListener("change", onColorChange);

 

배경색 지정 가능하게 하기

컬러를 클릭하면 -> 어떤 컬러가 클릭되었는지 확인하고 -> data-color 내에서 찾아본다.

js 코드를 짤 때 바로 colorOptions.forEach 하기에는 html 문서이지 array가 아니므로 array로 만들어준다.

 

const colorOptions = Array.from(document.getElementsByClassName("color-option"));

 

fill/draw 버튼 만들어주기

 

1. 

배경 컬러 리스트를 div로 묶어주고

html 파일에 fill button 을 만들어준다

<button id="mode-btn">Fill</button>

 

2.

js에서 id로 버튼을 불러오고

addEventListener 로 click할 경우 onModeClick이 실행되게 한다

isFilling이 false임을 기본값으로 두고

onModeClick function을 추가하여 isFilling이 false일 때 fill, true(클릭됐을 때) draw가 뜨도록 한다

const modeBtn = document.getElementById("mode-btn");
let isFilling = false;

function onModeClick() {
  if (isFilling) {
    isFilling = false;
    modeBtn.innerText = "Fill";
  } else {
    isFilling = true;
    modeBtn.innerText = "Draw";
  }
}

modeBtn.addEventListener("click", onModeClick);

 

배경색 채우기

 

배경색 채우기는 간단함!

 

addEventListener 로 click할 경우 onCanvasClick이 실행되게 하고

isFilling이 false임을 기본값으로 둔다

onCanvasClick function을 추가하여 

isFilling이 false일 때 좌표 0,0에서 시작하여 캔버스 크기의 채워진 사각형을 그리도록 한다

 

let isFilling = false;

function onCanvasClick() {
  if (isFilling) {
    //click하면 canvas 크기의 사각형 만들고 채워주기
    ctx.fillRect(0, 0, 600, 600);
  }
}

canvas.addEventListener("click", onCanvasClick);

+ 캔버스 width height가 반복해서 나오는 숫자이므로

CANVAS_WIDTH, CANVAS_HEIGHT 로 변환해주면 보기 좋음!

const CANVAS_WIDTH = 600;
const CANVAS_HEIGHT = 600;

canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;

function onCanvasClick() {
  if (isFilling) {
    //click하면 canvas 크기의 사각형 만들고 채워주기
    ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  }
}

function onRefreshClick() {
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}

+ 전체 지우기는 더 간단하게 작성하는 방법이 있었음.. 바로 clearRect !! 넘나 편한 것

function onRefreshClick() {
  // ctx.fillStyle = "white";
  // ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}

 

 

지우개 만들기

 

지우개 만들기도 원리를 알면 어렵지 않음! (점점 쉽게 느껴져서 꽤나 뿌듯..ㅋㅋㅋ)

사실 지우개는 배경색과 같은 색상의 브러쉬로 색칠하는 것이므로

이때는 하얀색 브러쉬 + 활성화 버튼만 만들어주면 된다

 

html에 지우개 버튼을 만들어주고

<button id="eraser-btn">Erase</button>

 

js에서 id로 불러온다

아까 했던 것과 유사한 방식으로 작성하고

클릭하면 펑션에서 흰색 stroke의 브러쉬가 활성화되게 한다

 

다만 이때 이렇게만 하면 fill 모드에서는 지우개가 활성화는 되지만 유지되지 않는 오류가 있다

따라서 아래와 같이 해결한다

const eraserBtn = document.getElementById("eraser-btn");

function onEraserClick() {
  ctx.strokeStyle = "white";
  isFilling = false;
  modeBtn.innerText = "Fill";
}

eraserBtn.addEventListener("click", onEraserClick);