getContext
캔버스에 도형을 그려보자.
도형을 그리려면 어떻게 해야할까? 당연하겠지만, 캔버스 API를 통해 그려야 할 것이다. 그러기 위해선 캔버스의 컨텍스트 객체를 얻어와야 한다. 이 컨텍스트 객체를 통해 우리는 도형을 그릴 것이다.
index.html
우선 아래와 같은 html
파일을 준비한다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>HTML</title>
<style>
html, body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="module" src="index.js"></script>
</body>
</html>
canvas
태그와 이 canvas
를 조작할 스크립트 파일을 준비한다. type="module"
은 브라우저에서 해당 스크립트 파일을 ES6 Module
로 다루게 해준다. Modules와 import를 참고해보도록 하자.
index.js
canvas
는 다른 일반적인 태그와 다를바 없다. 캔버스의 컨텍스트 객체를 얻기 위해서는 HTMLCanvasElement를 먼저 얻어와야 한다.
const canvas = document.querySelector('#canvas')
그 다음, getContext
메서드를 통해 컨텍스트를 얻는다.
const ctx = canvas.getContext('2d')
getContext
는 2d
말고도 여러가지 타입 문자열을 매개변수로 받을 수 있는데, 궁금하다면 getContext MDN 문서를 참고하도록 하고 우리는 2d
만을 사용할 것이다.
그 다음, 우린 캔버스의 크기를 브라우저에 꽉 차게 만들 것이다. 캔버스의 경우, 실제로 캔버스 위에 그림을 표현할 수 있는 크기를 키우려면 캔버스 태그의 width
속성과 height
속성을 줘야 한다. CSS
로 width
와 height
를 설정하면, 기본 캔버스 크기값(350x150)을 단지 확대시킬 뿐이다. 즉, 드로잉할 수 있는 영역인 350x150을 CSS
의 width
, height
값 만큼 확대시키는 형태가 된다.
따라서 width
, height
을 직접 설정해 줄 것이다.
canvas.width = window.innerWidth
canvas.height = window.innerHeight
여기까지 했다면 기본 준비가 끝난 것이다.
컴퓨터 좌표계의 원점은 왼쪽 상단이라는 사실을 기억하라.
캔버스에서는 사각형을 그릴 때, fillRect 메서드를 사용한다.
메서드의 인터페이스는 다음과 같다.
void ctx.fillRect(x, y, width, height)
x
, y
는 사각형을 그리는 기준점이 된다. 이는 캔버스의 (0, 0), 즉 왼쪽 상단을 기준으로 하는 좌표계에서의 x
y
를 뜻한다. 그리고 이 x
y
기준점은 그려질 사각형의 왼쪽 상단 꼭지점이 된다. width
, height
는 그 꼭지점으로부터 너비와 높이의 값을 뜻한다.
기억하자. 항상 좌표계의 시작은 왼쪽 상단이라는 것.
(50, 50)에서 너비, 높이 100의 사각형을 그리고 싶다면
ctx.fillRect(50, 50, 100, 100)
이렇게 메서드를 호출하면 된다.
위 그림을 생각해보면 아주 쉽게 이해할 수 있다.
기본적으로 그려지는 사각형은 검정색이다. 이를 바꿔보자.
ctx.fillRect(50, 50, 100, 100)
ctx.fillStyle = `rgba(255, 0, 0, 1)`
ctx.fillRect(100, 100, 100, 100)
위와 같이 보여질 것이다. fillStyle 프로퍼티로 설정된 값으로 사각형을 그린다.
위에서 보다시피, 캔버스는 말 그대로 도화지이다. 그림을 그리는 메서드를 호출할 때마다, 기존 도화지에 계속 덧그리게 된다.
이번엔 원을 그려보자. 원은 arc 메서드를 이용해서 그린다. 이 때, 우선 beginPath 메서드를 호출해야 한다.
path
에 대한 개념은 포토샵, 일러스트레이터 등을 다뤄봤다면 잘 이해할 수 있는 개념이다.
MDN에서는 아래와 같이 정의한다.
A path is a list of points, connected by segments of lines that can be of different shapes, curved or not, of different width and of different color. A path, or even a subpath, can be closed.
즉, 곡선이나 직선을 표현하는 점들의 집합이라고 생각하면 된다.
아무튼, arc
메서드의 인터페이스는 아래와 같다.
void ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise])
x
y
는 원의 중심 좌표다. radius
는 원의 반지름이다. startAngle
은 현재 좌표계에서 원이 시작되는 각도이고, endAngle
은 원이 끝나는 각도이다. anticlockwise
는 기본값이 false
인데, true
로 설정하면 시계반대방향으로 원을 그린다.
원을 그리는 것은, 컴퍼스로 원을 그리는 것을 생각하면 된다. 원의 중심 (x, y)에 컴퍼스를 고정시키고, radius
만큼 벌린 뒤 startAngle
부터 endAngle
까지 시계방향으로 그린다.
시계반대방향의 의미는 무엇일까? 왜 기본적으로 시계방향으로 원을 그리는 것일까? 이는 컴퓨터 좌표계 때문인데, 컴퓨터 좌표계는 y
값이 아래쪽이라고 했다.
우리가 일반적인 좌표계에서 원을 그릴 때, 각도가 증가하는 방향이 어디였는지를 생각해보면 쉽게 이해가 된다. 보통 1사분면에서 2사분면 쪽으로 원을 그렸다. 즉, 시계반대방향으로 원을 그렸고 이렇게 그릴 때 각도가 커지는 것을 일반적으로 배웠다.
하지만 컴퓨터의 좌표계는 다르다. 컴퓨터의 좌표계에서 각도가 증가하는 방향은 시계방향이다. 따라서 기본적으로 anticlockwise
는 false
이다.
컴퓨터에서의 각도 단위는 degree
값이 아니다. radian값이다.
위의 애니메이션에서도 쉽게 알 수 있듯이, radian
은 원에서 반지름의 길이와 호의 길이가 같을 때 그 각도를 뜻한다.
360° = 2π rad
이다. 따라서 1° = π/180 rad
이다.
startAngle
은 원의 중심으로부터 시작하는 각도다. 원을 그리고자 한다면, startAngle
은 0, endAngle
은 2π이면 될 것이다.
π값은 자바스크립트에서 Math.PI
상수로 표현할 수 있다.
// 도형 그리기를 시작한다.
ctx.beginPath()
// (200, 200)이 중심인 반지름 50의 원의 path를 그린다.
ctx.arc(200, 200, 50, 0, 2*Math.PI)
// path를 닫는다. 즉, 현재까지 그려진 path가 연결된다.
// path의 시작점과 끝점의 path가 연결된다.
// 이 경우, 원을 그렸으므로 그냥 원이다.
ctx.closePath()
// 초록색으로 채우는 스타일을 정하고
ctx.fillStyle = `rgba(0, 255, 0, 1)`
// 현재 닫힌 path에 색을 칠한다.
ctx.fill()
현재까지의 코드를 종합해보면
const canvas = document.querySelector('#canvas')
const ctx = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// 검정색 사각형
ctx.fillRect(50, 50, 100, 100)
// 빨간색 사각형
ctx.fillStyle = `rgba(255, 0, 0, 1)`
ctx.fillRect(100, 100, 100, 100)
// 초록색 원
ctx.beginPath()
ctx.arc(200, 200, 50, 0, 2*Math.PI)
ctx.closePath()
ctx.fillStyle = `rgba(0, 255, 0, 1)`
ctx.fill()
이는 위와 같은 그림일 것이다.
지금까지 사각형과 원을 그려보았다. 핵심은
이 정도일 것이다. 이해가 잘 되지 않는다면, 직접 위치나 startAngle
, endAngle
, anticlockwise
값을 바꿔가면서 그려보면 될 것이다. 그러면 쉽게 이해할 수 있다.
다음 챕터에서는 선을 그려보고, 벡터에 대해 알아보도록 하겠다.