whatisthis?

javaScript. Painting App 구현 - (3) 2D context 본문

PRACTICE/SELF

javaScript. Painting App 구현 - (3) 2D context

thisisyjin 2022. 2. 2. 12:28
 

javaScript. Painting App 구현 - (2) Canvas Event

PaintJS Fill Save - canvas 태그 - input type="range" - class는 스타일 적용에 / id는 js에 사용함. - id 구조 : controls > controls__r.." data-og-host="mywebproject.tistory.com" data-og-source-url="htt..

mywebproject.tistory.com

지난 회차 진행사항

- app.js 이벤트리스너 (mouse event) 작성

const canvas = document.getElementById("jsCanvas");

let painting = false;

function stopPainting() {
    painting = false;
}

function onMouseMove(event) {
    const x = event.offsetX;
    const y = event.offsetY;
}

function onMouseDown(event) {
	painting: true;
}

function onMouseUp(event) {
    stopPainting();     // 함수 호출 ㅡ painting = false
}

if(canvas) {
    canvas.addEventListener('mousemove',onMouseMove);   // 마우스가 위에 있을때
    canvas.addEventListener('mousedown', onMouseDown);   // 마우스 클릭시
    canvas.addEventListener('mouseup', onMouseUp);   // 마우스 클릭 놓았을때
    canvas.addEventListener('mouseleave', stopPainting); // 마우스 떠날때
}

 


 

Canvas API - Web API | MDN

Canvas API는 JavaScript와 HTML <canvas> 엘리먼트를 통해 그래픽을 그리기위한 수단을 제공합니다. 무엇보다도 애니메이션, 게임 그래픽, 데이터 시각화, 사진 조작 및 실시간 비디오 처리를 위해 사용

developer.mozilla.org

 

< canvas >

- HTML의 element 이다.

- context를 갖는다. ( = 픽셀에 접근할 수 있음 )

 

const canvas = document.getElementById('jsCanvas');
const ctx = canvas.getContext('2d');     // 2d 컨텍스트를 가져옴

 

HTMLCanvasElement.getContext() 메소드는 element의 컨텍스트(렌더링될 그리기의 대상)를 얻는다.

 

 

예제> 초록색 사각형(Rectangle) 그리기

ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);

 

 


app.js

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

canvas.width = 700;
canvas.heigth = 700;

// Default
ctx.strokeStyle = "#2c2c2c";
ctx.lineWidth = 2.5;


let painting = false;

function stopPainting() {
    painting = false;
}

function startPainting() {
    painting = true;
}

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); 
}

 

- 우선, getContext("2d")를 해서  element의 컨텍스트(렌더링될 그리기의 대상)를 얻는다.

- 그 다음 디폴트값으로 설정을 한 다음 (strokeStyle과 lineWidth)

- StartPainting 함수를 만들어서 painting = true를 하는 동작을.

>> mousedown일때 startPainting함수를 실행한다.

 

로직을 살펴보면

마우스 클릭시 = startPainting
마우스 떼면 = stopPainting
캔버스 벗어나면 =stopPainting
마우스 움직이면 = onMouseMove

결국엔 paiting변수를 true와 false로 바꿔주는 것이고,
실질적으로 x좌표와 y좌표를 가진 onMouseMove함수를 설계해야함.
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();
    }
}​

 

위와 같이 작성하였는데,

📌 painting이 false이면?
ㅡ  1. 맨처음 상황 (painting변수는 false로 초기화됨)
     2. 마우스 떼었을때
     3. 마우스가 캔버스 벗어났을 때

>> beginPath (Path를 만들기 시작) ㅡ moveTo(x, y) 해당 x,y가 바뀔때마다 Path가 이동 


📌 painting이 true면? (마우스 클릭시)
lineTo(x, y) ㅡ line(선)이 이동. 즉 그려진 path대로 선이 이어짐
stroke();  ㅡ 그림
💡 반드시 canvas의 크기를 줘야함.
>> 픽셀 modifier로서의 width * height 를 지정.

 

 

 

 

 

❓ 문제 발생

canvas.width와 canvas.height를 700으로 설정했더니

이상하게 그려진다.

 

canvas.width = document.getElementsByClassName("canvas")[0].offsetWidth;
canvas.height = document.getElementsByClassName("canvas")[0].offsetHeight;

위와 같은 코드로 대체했더니 정상작동함.

 

왜?

>> width , height 값에 700, 700 주면 오류생길 여지가 있으므로 캔버스 크기를 가져와야함.

 

굳이 왜 id로 안가져오고 getElementsByClassName()으로 가져옴?

>> 우리가 <canvas>태그에 직접 width, height를 준게 아니고 css로 주었기 때문에

css를 적용시킨 클래스를 가져와야함.

 

그리고, class로 가져오면 클래스는 중복 가능이므로 값이 하나더라도 배열(array)의 형태로 가져옴.

따라서, 뒤에 [0]을 붙여서 배열의 첫번째 요소를 가져온 것임.

 

offsetWidth는 무엇?

>> HTML 요소인 <canvas>의 너비.

즉, 엘리먼트의 크기를 구하려면 offsetWidth를 가져와야함.

 

참고

- offsetWidth : 엘리먼트 전체 크기 (패딩, 보더, 스크롤바 포함) 
- clientWidth : 창에서 실제로 보여지고 있는 컨텐츠의 크기. (패딩 포함. / 보더,스크롤바는 X)
- scrollWidth : 보이는 것과 상관없이 실제 컨텐츠의 크기. (전체 스크롤바 ㅡ 숨겨진 영역 포함)

 

 


REFERENCE

Nomadcoder - Free Course