본문 바로가기

웹/JavaScript

[JavaScript] 자바스크립트로 캔버스 제어하기 - 2d 그래픽 그리기

자바스크립트에서 캔버스를 동적으로 제어하는 기능에 대해 공부한 내용 중, 2d 그래픽을 그리는 부분에 대해 정리했다.

 

캔버스 생성 

화면에 createElement로 캔버스 엘리먼트를 생성하고, getContext로 캔버스에 연결된 렌더링 컨텍스트를 정의한다. 

const myCanvas = document.createElement('canvas'); //캔버스 엘리먼트 생성
const ctx = myCanvas.getContext('2d'); //생성한 캔버스에 컨텍스트를 연결

document.body.appendChild(myCanvas); //body 내에 캔버스를 배치
myCanvas.style.width = 100%;
myCanvas.style.height = 100%;

여기서 렌더링 컨텍스트를 정의한다는건, 쉽게 말하면 캔버스에 어떤 종류의 그림을 그릴지 정하는 것이라고 할 수 있다. 매개변수로 2d를 설정하면 캔버스에 2차원의(x, y의 두 축으로 된) 그림을, 3d로 설정하면 3차원의(x, y, z 세 축으로 된) 그림을 그릴 수 있다.

렌더링 컨텍스트를 정의하면 그때부터 해당 컨텍스트에서 지원하는 그리기 함수들을 사용할 수 있다. 이 포스팅에서는 2d 컨텍스트에서 그리는 방법을 다룬다. 

 

캔버스의 좌표공간 

이미지 출처: MDN Docs

캔버스의 좌표공간은 위의 그림처럼 가장 왼쪽 위를 기준점 (0, 0)으로 한다.

기준점에서 오른쪽으로 갈수록 x값이 증가하고, 왼쪽으로 갈수록 x값이 감소한다.

기준점에서 아래쪽으로 갈수록 y값이 증가하고, 위쪽으로 갈수록 y값이 감소한다.

따라서 위의 그림에서 파란색 사각형의 왼쪽 위 꼭짓점의 좌표는 (x, y)가 된다. 

 

2d 그림 그리기

렌더링 컨텍스트를 2d로 정의했기 때문에, CanvasRenderingContext2D라는 인터페이스에서 제공하는 그리기 함수들을 사용할 수 있다. 기본적으로 경로(path)를 이용해 그림을 그릴 수 있으며, 직사각형의 경우 경로를 설정하지 않고도 바로 그리는게 가능하다.

 

먼저 경로를 설정하지 않고 그리는 함수를 보자. 

 

경로 없이 사각형 그리기 

- CanvasRenderingContext2D.strokeRect(x, y, width, height)

파라미터로 받은 (x, y)에서 시작해 width의 너비와 height의 높이를 가진 직사각형의 선을 그림. (□ 모양이 된다.)

 

- CanvasRenderingContext2D.fillRect(x, y, width, height)

파라미터로 받은 (x, y)에서 시작해 width의 너비와 height의 높이를 가진 직사각형 영역을 색칠함. (■ 모양이 된다. )

 

- CanvasRenderingContext2D.clearRect(x, y, width, height)

파라미터로 받은 (x, y)에서 시작해 width의 너비와 height의 높이를 가진 직사각형 영역만큼 지움. (■ 모양으로 지워진다.)

 

경로를 이용해 그리기

beginPath()로 새 경로를 생성하면 그때부터 경로를 설정한 후, stroke()나 fill()을 사용해 캔버스 위에 그림을 그릴 수 있다. 

 

경로를 생성, 이동, 종료하기

- CanvasRenderingContext2D.beginPath(): 새 경로를 생성함. 

- CanvasRenderingContext2D.moveTo(x, y) : 파라미터로 받은 (x, y)에서부터 새로운 하위경로를 시작함.

- CanvasRenderingContext2D.closePath(): 현재 지점에서 현재 경로가 시작된 부분까지 직선을 추가해 모양을 닫음. 모양이 이미 닫혀있는 경우 아무 것도 하지 않는다.  

 

획 그리기

- CanvasRenderingContext2D.stroke(): 현재 경로를 strokeStyle설정대로 획을 그림.

- CanvasRenderingContext2D.strokeStyle: 현재 설정된 획 속성. 색상, 그라디언트, 또는 패턴으로 속성을 지정할 수 있다. 기본값은 검정색(#000). 

 

색칠하기

- CanvasRenderingContext2D.fill(): 현재 경로를 fillStyle설정대로 색칠함. 

- CanvasRenderingContext2D.fillStyle: 현재 설정된 채우기 속성. stroke와 마찬가지로 색상, 그라디언트, 또는 패턴으로 속성을 지정할 수 있다. 기본값은 검정색(#000). 

 

도형 경로 그리기 

- CanvasRenderingContext2D.lineTo(x, y): 현재 경로 위치에서부터 파라미터로 받은 (x, y)까지 이어지는 선분의 경로를 그림. 

 

//이등변 삼각형 그리기
ctx.beginPath();
ctx.moveTo(50, 50); // A(50, 50)으로 이동
ctx.lineTo(80, 80); // A(50, 50)에서 B(80, 80)으로 이어지는 직선 경로 생성 
ctx.lineTo(20, 80); // B(80, 80)에서 C(20, 80)으로 이어지는 직선 경로 생성 
ctx.closePath(); // C(20, 80)에서 시작점인 A(50, 50)으로 닫히는 직선 경로 생성 
ctx.stroke();

설명 편의상 꼭짓점에 글자를 추가했다.

 

- CanvasRenderingContext2D.rect(x, y, width, height): 파라미터로 받은 (x, y)에서 시작해 width의 너비와 height의 높이를 가진 사각형의 경로를 그림.

- CanvasRenderingContext2D.arc(x, y, radius, startAngle, endAngle, [counterclockwise])

파라미터로 받은 (x, y)를 중심점으로, 반지름 radius의 startAngle각도에서 endAngle각도까지 원호의 경로를 그림. counterclockwise는 호를 시계 방향으로 그리는지 시계 반대방향으로 그리는지를 결정하며, 생략 가능하다. 생략 시 기본값은 시계 방향이다. 원호를 그릴 때, 시작점은 중심점을 기준으로 3시 방향이라는 점에 주의. 

//(50, 50)을 중심으로 반지름 10의 ● 모양을 그린다면
ctx.beginPath();
ctx.arc(50, 50, 10, 0, 2 * Math.PI); //9시 방향에서 시작해 시계 방향으로 한바퀴
ctx.fill();

//(100, 125)을 중심으로 반지름 20의 ∩ 모양을 그린다면 
ctx.beginPath();
ctx.arc(100, 125, 20, 0, Math.PI, true); //3시 방향에서 시작해 시계 반대방향으로 반바퀴
ctx.stroke();

//(180, 200)을 중심으로 반지름 30의 D 모양을 그린다면 
ctx.beginPath();
ctx.arc(180, 200, 30, 1.5 * Math.PI, 0.5 * Math.PI); //12시 방향에서 시작해 시계방향으로 반바퀴
ctx.closePath(); //반바퀴 돌아간 지점에서 시작점인(180, 200)로 이어지는 직선경로를 만들어 모양을 닫음
ctx.stroke();

 

기타 캔버스 설정 

Window.devicePixelRatio: 현재 화면을 표시하는 장치(모니터, 핸드폰 화면 등)의 물리적 픽셀과 CSS 픽셀의 비율을 나타내는 속성. 

CanvasRenderingContext2D.scale(x, y) : 캔버스의 배율을 바꾸는 함수. 기본값은 (캔버스의 1단위) = (1픽셀). 

 

 

 

 

여기서는 주로 사용되는 기본적인 함수만 다뤘으며, 그 외의 함수는 여기서 확인할 수 있다. 


참고 자료

MDN Docs

- 2d컨텍스트 https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D

- 캔버스 도형 그리기 https://developer.mozilla.org/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes

체리의 두번째 세상 https://cherryopatra.tistory.com/92

유튜브 Interactive Developer  https://youtu.be/sLCiI6d5vTM