이전 포스팅에서 그림판에서 가장 핵심적인 부분이라고 할 수 있었던 클릭한 부분을 칠하는 것을 만들어보았습니다.
그렇다면 이번 포스팅에서는 색깔을 바꾸고 붓 사이즈를 바꾸는 것을 해 보도록 하겠습니다!
이번 포스팅의 내용은 강의 #2.3~#2.4를 다루고 있습니다.
목차
0. 붓 색을 바꿔보자!
먼저 html에 있는 각 색깔들을 담당하는 div의 class에 jsColor를 추가해줍니다. 간단하쥬?
<!-- 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" /> <!-- style.css 연결 -->
<title>PaintJS</title>
</head>
<body>
<!-- JS를 편집할 때는 ID를 사용하고, css를 편집할 때는 cls를 사용할 예정 -->
<canvas id="jsCanvas" class="canvas"></canvas> <!-- clas 아닌 id를 사용해도 같다! -->
<div class="controls">
<div class="controls__range"> <!-- range 바 생성 -->
<!-- 0.1 간격으로 조정 가능하고, 최대 0.1부터 5까지 조정 가능, 초기값 2.5 -->
<input type="range" id="jsRang" min="0.1" max="5" value="2.5" step="0.1"/>
</div>
<!-- 아래 div 생성 단축 명령어 div.controls__btns>button#jsMode+button#jsSave -->
<!-- Fill, Save 버튼 생성 (Fill 클릭하면 Painting, 다시 클릭하면 Fill) -->
<div class="controls__btns">
<button id="jsMode">Fill</button>
<button id="jsSave">Save</button>
</div>
<div class="controls__colors" id="jsColors"><!-- div를 한번에 여러개 생성할 때 div.class명*개수 엔터를 누르면 여러개 생성이 가능하다! -->
<!-- 다중 커서 - 여러 줄 선택하는 방법은 ctrl+alt를 누른 채로 방향키를 눌러 영역을 선택합니다. -->
<div class="controls__color jsColor" style="background-color:black"></div>
<div class="controls__color jsColor" style="background-color:white"></div>
<div class="controls__color jsColor" style="background-color:red"></div>
<div class="controls__color jsColor" style="background-color:orange"></div>
<div class="controls__color jsColor" style="background-color:yellow"></div>
<div class="controls__color jsColor" style="background-color:green"></div>
<div class="controls__color jsColor" style="background-color:skyblue"></div>
<div class="controls__color jsColor" style="background-color:blue"></div>
<div class="controls__color jsColor" style="background-color:violet"></div>
</div>
</div>
<script src="app.js"></script> <!-- app.js 연결 -->
</body>
</html>
이제 추가한 jsColor Class를 가진 친구들을 getElementByClassName으로 모두 불러서 colors에 저장합니다.
colors는 Object 형태의 데이터를 가지고 있는데, 이 데이터들을 array 형태로 바꿔서 사용하기 위해 Array.from()을 사용합니다.
그리고 이 array에서 하나씩 빼오기 위해서 forEach를 사용하고, 하나씩 빼와서 eventListener가 돌아갈 수 있도록 만들었습니다. (화살표 함수의 설명은 생략합니다!)
이렇게 eventListener가 각각의 색을 가진 div들에 동력을 제공했다면, 이제 클릭을 할 때마다 이전 포스팅에서 설정했던ctx.strokeStyle을 클릭한 요소의 색으로 바꿔주면 됩니다.
event.target.style.backgroundColor 위치에 내가 클릭한 div의 색깔 정보가 들어있습니다. 이걸로 ctx.strokeStyle을 바꿔주면 끝입니다!!
// app.js
const canvas = document.getElementById("jsCanvas"); // id를 가져올때는 getElementById!! Class를 가져올 때는 get
const ctx = canvas.getContext("2d") // context 불러오기 (mdn 참고)
const colors = document.getElementsByClassName("jsColor") // jsColors라는 Class를 가진 모든 요소를 가져온다!
// canvas는 2개의 사이즈를 가져야한다. 우리가 보고 있는 CSS size와 pixel manipulating size를 알아야한다
// index에서 생성한 canvas는 css로부터 size 정보를 받아오는데, js는 이것을 알 수 없다.
// 그러므로 여기서 따로
// 아래는 pixel을 관리하기 위해서 알아야하는 size를 canvas에 제공한 것이다.
canvas.width = canvas.offsetWidth; // 강의에서는 700, 700을 넣었지만 실제로는 이렇게 해야 관리가 편하다!
canvas.height = canvas.offsetHeight;
ctx.strokeStyle = "black"; // 사용하려는 사람이 검정색으로 시작하도록 설정 - 추후 변경하면 그 색으로 선이 그어질 것!!
ctx.lineWidth = "2.5"; // 아까 만들었던 range를 이용해 선의 굵기를 결정, 초기값 2.5px!
let painting = false; // 클릭중인지 여부를 나타내는 변수
function stopPainting(){
painting = false;
}
function startPainting(){
painting = true;
}
function onMouseMove(event){ // 마우스가 캔버스 위에 있는지를 나타내는 함수
// 여기서 관심있는 부분은 캔버스 내 위치인 offset에 대한 부분!
// client X Y는 윈도우 전체에서 마우스의 위치
const x = event.offsetX;
const y = event.offsetY;
if(!painting){ // painting(클릭) 상태가 아니라면
ctx.beginPath(); // path를 만든다 (path를 현 위치로 초기화한다)
ctx.moveTo(x, y); // path를 x,y로 옮긴다 - 클릭하면 그 path의 최종 지점이 x와 y로 남는다 (beginPath가 있기에 지워도 상관이 없다)
} else { // painting(클릭) 상태라면
// CanvasRenderingContext2D.lineTo()는 현재 sub-path의 마지막 점을 특정 좌표와 '직선'으로 연결한다
ctx.lineTo(x, y); // 실시간으로 계속해서 클릭한 상태로 이동한 좌표를 따라가서 path를 만든다
// 6,6에서 클릭한 상태로 마우스를 8,8로 가져갔다면 path는 (6,6)~(7,7), (7,7)~(8,8) 이런 식으로 만들어진다.
ctx.stroke(); // 그렇게 생성된 path를 이어서 선을 만든다. 즉 매우 작은 직선들이 우리 눈에는 부드럽게 보이는 것이다!
}
}
/* 이 부분도 startPainting()으로 대체
function onMouseDown(event){ // 캔버스 안을 클릭했을 때를 나타내는 함수
painting = true; // 누르면 true
}
*/
/* 우리가 만들 로직은 onMouseDown에 들어가면 되기 때문에 이 부분도 생략 후 stopPainting으로 대체
function onMouseUp(event)
stopPainting(); // 떼면 false - 다른 문장이 필요하므로 stopPainting()을 가져와서 여기서 사용한다!
}
*/
/*
이 부분은 stopPainting()을 만들면서 만들지 않을 수 있다!
function onMouseLeave(event){
painting = false;
}
*/
function handleColorClick(event){ //클릭했을 때 어떤 반응이 나오게 할 것인지 만드는 함수
// console.log(event.target.style) 찍어보면 우리가 원하는 것은 backgroundColor
const color = event.target.style.backgroundColor;
ctx.strokeStyle = color // strokeStyle을 override! 여기서부터는 클릭한 color로 선이 그려진다!
}
if(canvas){ // 사실상 init와 같은 역할이다 - eventListener들은 한번 작동하면 계속 작동!
canvas.addEventListener("mousemove", onMouseMove); // 캔버스 위 움직임 감지
canvas.addEventListener("mousedown", startPainting); // 클릭했을 때 감지
canvas.addEventListener("mouseup", stopPainting); // 클릭을 멈췄을 때 감지
canvas.addEventListener("mouseleave", stopPainting); // 클릭하다가 캔버스를 벗어났을 때 감지
}
// Array.from 메소드는 object로부터 array를 만든다!
// array를 주면 그 array 안에서 forEach로 color를 가질 수 있다!
// colors의 각각에다가 이벤트리스너를 실행하도록 한다
Array.from(colors).forEach(color => color.addEventListener("click", handleColorClick));
1. 붓 굵기를 바꿔보자!
위와 같은 원리로 붓 굵기 역시 바꿀 수 있습니다.
아까 만들어둔 Range바를 이용합시다. (이번에는 html파일을 따로 바꿀 필요가 없습니다!)
range를 element로 받아온 후에 eventListener를 추가해줍시다. input 동작이 들어왔을 때 handleRangeChange 함수가 작동하도록 만듭니다. (if문으로 감쌌는데, 굳이 감싸지 않아도 문제 없습니다!)
그 후 event.target을 console.log로 뒤져보면 value값이 우리가 원하는 값임을 찾을 수 있습니다.
마지막으로 이 값을 size에 불러와 lineWidth에 overriding합니다.
사실상 복습이나 다름 없으니 쉽죠?!
// app.js
const canvas = document.getElementById("jsCanvas"); // id를 가져올때는 getElementById!! Class를 가져올 때는 get
const ctx = canvas.getContext("2d") // context 불러오기 (mdn 참고)
const colors = document.getElementsByClassName("jsColor") // jsColors라는 Class를 가진 모든 요소를 가져온다!
const range = document.getElementById("jsRange");
// canvas는 2개의 사이즈를 가져야한다. 우리가 보고 있는 CSS size와 pixel manipulating size를 알아야한다
// index에서 생성한 canvas는 css로부터 size 정보를 받아오는데, js는 이것을 알 수 없다.
// 그러므로 여기서 따로
// 아래는 pixel을 관리하기 위해서 알아야하는 size를 canvas에 제공한 것이다.
canvas.width = canvas.offsetWidth; // 강의에서는 700, 700을 넣었지만 실제로는 이렇게 해야 관리가 편하다!
canvas.height = canvas.offsetHeight;
ctx.strokeStyle = "black"; // 사용하려는 사람이 검정색으로 시작하도록 설정 - 추후 변경하면 그 색으로 선이 그어질 것!!
ctx.lineWidth = "2.5"; // 아까 만들었던 range를 이용해 선의 굵기를 결정, 초기값 2.5px!
let painting = false; // 클릭중인지 여부를 나타내는 변수
function stopPainting(){
painting = false;
}
function startPainting(){
painting = true;
}
function onMouseMove(event){ // 마우스가 캔버스 위에 있는지를 나타내는 함수
// 여기서 관심있는 부분은 캔버스 내 위치인 offset에 대한 부분!
// client X Y는 윈도우 전체에서 마우스의 위치
const x = event.offsetX;
const y = event.offsetY;
if(!painting){ // painting(클릭) 상태가 아니라면
ctx.beginPath(); // path를 만든다 (path를 현 위치로 초기화한다)
ctx.moveTo(x, y); // path를 x,y로 옮긴다 - 클릭하면 그 path의 최종 지점이 x와 y로 남는다 (beginPath가 있기에 지워도 상관이 없다)
} else { // painting(클릭) 상태라면
// CanvasRenderingContext2D.lineTo()는 현재 sub-path의 마지막 점을 특정 좌표와 '직선'으로 연결한다
ctx.lineTo(x, y); // 실시간으로 계속해서 클릭한 상태로 이동한 좌표를 따라가서 path를 만든다
// 6,6에서 클릭한 상태로 마우스를 8,8로 가져갔다면 path는 (6,6)~(7,7), (7,7)~(8,8) 이런 식으로 만들어진다.
ctx.stroke(); // 그렇게 생성된 path를 이어서 선을 만든다. 즉 매우 작은 직선들이 우리 눈에는 부드럽게 보이는 것이다!
}
}
/* 이 부분도 startPainting()으로 대체
function onMouseDown(event){ // 캔버스 안을 클릭했을 때를 나타내는 함수
painting = true; // 누르면 true
}
*/
/* 우리가 만들 로직은 onMouseDown에 들어가면 되기 때문에 이 부분도 생략 후 stopPainting으로 대체
function onMouseUp(event)
stopPainting(); // 떼면 false - 다른 문장이 필요하므로 stopPainting()을 가져와서 여기서 사용한다!
}
*/
/*
이 부분은 stopPainting()을 만들면서 만들지 않을 수 있다!
function onMouseLeave(event){
painting = false;
}
*/
function handleColorClick(event){ //클릭했을 때 어떤 반응이 나오게 할 것인지 만드는 함수
// console.log(event.target.style) 찍어보면 우리가 원하는 것은 backgroundColor
const color = event.target.style.backgroundColor;
ctx.strokeStyle = color // strokeStyle을 override! 여기서부터는 클릭한 color로 선이 그려진다!
}
function handleRangeChange(event){ // 조정할 때마다 그에 맞춰서 lineWidth를 변경하는 함수
const size = event.target.value; // 항상 어떤 값인지 console.log()를 찍어보고 찾아보자!
ctx.lineWidth = size;
}
if(canvas){ // 사실상 init와 같은 역할이다 - eventListener들은 한번 작동하면 계속 작동!
canvas.addEventListener("mousemove", onMouseMove); // 캔버스 위 움직임 감지
canvas.addEventListener("mousedown", startPainting); // 클릭했을 때 감지
canvas.addEventListener("mouseup", stopPainting); // 클릭을 멈췄을 때 감지
canvas.addEventListener("mouseleave", stopPainting); // 클릭하다가 캔버스를 벗어났을 때 감지
}
// Array.from 메소드는 object로부터 array를 만든다!
// array를 주면 그 array 안에서 forEach로 color를 가질 수 있다!
// colors의 각각에다가 이벤트리스너를 실행하도록 한다
Array.from(colors).forEach(color => color.addEventListener("click", handleColorClick));
if(range){ // getElementById로 잘 받아왔는지 확인
range.addEventListener("input", handleRangeChange) // input에 반응해야 하기 때문!
}
거의 다 왔습니다! 이제 페인트통 기능과 이미지를 저장하는 기능만 구현하면 끝이네요!
아마 다음 포스팅 혹은 다다음 포스팅에서 마무리가 될 것 같습니다!
그렇다면 다음 포스팅에서 뵙겠습니다 :)
최근댓글