Canvas API 기초
우리는 9장에서 Fetch API로 서버와 통신하고, 로컬/세션 스토리지로 클라이언트 데이터를 관리하며, History API로 SPA 라우팅을 구현하는 흐름을 학습했습니다.
이번 절에서는 웹 페이지를 더 시각적이고 인터랙티브하게 만드는 핵심 도구인 Canvas API를 다룹니다.
Canvas API는 HTML5에 도입된 <canvas> 요소를 이용해 웹 페이지에서 2D 그래픽을 직접 그릴 수 있게 해주는 JavaScript API입니다.
픽셀 단위 이미지 조작, 도형/텍스트 렌더링, 애니메이션 구현이 가능해 정적 이미지로 표현하기 어려운 동적 시각화를 만들 때 유용합니다.
간단한 게임, 이미지 편집기, 데이터 시각화(차트 등) 같은 다양한 분야에서 활용됩니다.
이번 절에서는 캔버스 요소 준비, 컨텍스트 획득, 선/사각형/원/텍스트 렌더링까지 기본 사용 흐름을 순서대로 정리하겠습니다.
Canvas API 개요 및 <canvas> 요소
Canvas는 말 그대로 도화지와 같습니다. HTML 문서에는 <canvas>라는 빈 도화지 요소를 배치하고, 실제 그림은 JavaScript 코드를 사용하여 이 도화지 위에 그리는 방식입니다.
<canvas> 요소 준비
HTML 문서에 <canvas> 태그를 추가하여 그림을 그릴 공간을 정의합니다. width와 height 속성으로 캔버스의 크기를 지정할 수 있습니다. (CSS로 크기를 조절할 수도 있지만, 렌더링 품질에 영향을 줄 수 있으므로 HTML 속성으로 고정 크기를 지정하는 것이 좋습니다.)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas API 기초</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f0f0f0;
margin: 0;
}
canvas {
border: 2px solid #333; /* 캔버스 경계를 시각적으로 보여주기 위함 */
background-color: #fff;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="500" height="300">
이 브라우저는 Canvas를 지원하지 않습니다.
</canvas>
<script src="canvas-script.js"></script>
</body>
</html>렌더링 컨텍스트 가져오기
<canvas> 요소 자체는 그림을 그릴 수 있는 인터페이스를 직접 제공하지 않습니다. 그림을 그리기 위해서는 렌더링 컨텍스트(Rendering Context)를 얻어야 합니다. 가장 흔히 사용되는 것은 2D 그래픽을 위한 2d 컨텍스트입니다.
// canvas-script.js
const canvas = document.getElementById('myCanvas');
// getContext() 메서드를 사용하여 렌더링 컨텍스트를 가져옵니다.
const ctx = canvas.getContext('2d');
// 캔버스가 정상적으로 초기화되었는지 확인
if (ctx) {
console.log("2D 렌더링 컨텍스트를 성공적으로 가져왔습니다.");
// 이제 ctx 객체를 사용하여 그림을 그릴 수 있습니다.
} else {
console.error("이 브라우저는 Canvas 2D 컨텍스트를 지원하지 않습니다.");
}ctx (Context) 객체는 캔버스에 도형, 텍스트, 이미지 등을 그리는 데 필요한 모든 메서드와 속성을 가지고 있습니다.
캔버스는 CSS 크기와 실제 픽셀 버퍼 크기를 따로 다루므로, 고해상도 화면에서는 devicePixelRatio까지 함께 고려해야 선과 글자가 흐려지지 않습니다.
아래 다이어그램은 캔버스 크기 설정을 "보이는 크기"와 "그리는 좌표계"로 나눠 확인하는 기준입니다.
기본적인 도형 그리기
Canvas에서 그림을 그리는 과정은 보통 다음과 같습니다.
경로 시작: ctx.beginPath()로 새로운 그림 경로를 시작합니다.
경로 정의: moveTo(), lineTo(), arc(), rect() 등으로 경로를 정의합니다.
그림 그리기: stroke()로 선을 그리거나, fill()로 도형을 채웁니다.
(선택) 경로 닫기: closePath()로 현재 경로를 시작점으로 연결하여 닫습니다.
선(Lines) 그리기
// 선의 색상 설정
ctx.strokeStyle = 'blue';
// 선의 두께 설정
ctx.lineWidth = 5;
// 첫 번째 선: (50, 50)에서 (200, 50)까지
ctx.beginPath(); // 새로운 경로 시작
ctx.moveTo(50, 50); // 시작점 이동
ctx.lineTo(200, 50); // (200, 50)까지 선 그리기
ctx.stroke(); // 경로를 따라 선 그리기 (stroke)
// 두 번째 선: (200, 50)에서 (200, 150)까지
// beginPath()를 다시 호출하면 이전 경로와 독립적으로 그림
ctx.beginPath();
ctx.moveTo(200, 50);
ctx.lineTo(200, 150);
ctx.stroke();
// 삼각형 그리기
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(300, 100);
ctx.lineTo(350, 200);
ctx.lineTo(250, 200);
ctx.closePath(); // 시작점으로 경로를 닫아 삼각형 완성
ctx.stroke();사각형(Rectangles) 그리기
사각형을 그리는 전용 메서드가 있습니다.
ctx.rect(x, y, width, height): 사각형 경로를 정의ctx.strokeRect(x, y, width, height): 윤곽선 사각형 그리기ctx.fillRect(x, y, width, height): 채워진 사각형 그리기ctx.clearRect(x, y, width, height): 지정된 영역을 투명하게 지우기
// 채워진 사각형 (fillStyle 설정)
ctx.fillStyle = 'green'; // 채울 색상 설정
ctx.fillRect(50, 100, 100, 50); // (x, y, width, height)
// 윤곽선 사각형 (strokeStyle, lineWidth 설정)
ctx.strokeStyle = 'purple';
ctx.lineWidth = 3;
ctx.strokeRect(200, 100, 100, 50);
// 특정 영역 지우기
ctx.clearRect(70, 110, 60, 30); // 초록색 사각형의 일부를 지움원(Arcs/Circles) 그리기
arc() 메서드를 사용하여 원 또는 호를 그립니다.
ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise)x, y: 원의 중심 좌표radius: 반지름startAngle, endAngle: 호의 시작 및 끝 각도 (라디안 단위)counterclockwise:true면 반시계 방향,false면 시계 방향 (기본값)
// 라디안 계산: Math.PI는 파이 (180도)
// 전체 원: 0부터 2 * Math.PI
// 반원: 0부터 Math.PI
// 채워진 원
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.arc(150, 230, 40, 0, 2 * Math.PI, false); // (x, y, 반지름, 시작각, 끝각, 반시계방향)
ctx.fill();
// 윤곽선 원
ctx.strokeStyle = 'darkblue';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(350, 230, 40, 0, 2 * Math.PI, false);
ctx.stroke();
// 반원 (파이차트 조각처럼)
ctx.fillStyle = 'lightblue';
ctx.beginPath();
ctx.moveTo(400, 50); // 중심점에서 시작
ctx.arc(400, 50, 40, 0, Math.PI, false); // 오른쪽 절반 원
ctx.closePath(); // 시작점으로 다시 돌아와 닫음 (채우려면 필요)
ctx.fill();텍스트(Text) 그리기
텍스트를 그리는 메서드와 스타일 속성이 있습니다.
ctx.fillText(text, x, y, maxWidth): 채워진 텍스트 그리기ctx.strokeText(text, x, y, maxWidth): 윤곽선 텍스트 그리기
텍스트 스타일 속성
ctx.font: 폰트 스타일 (예:'48px serif')ctx.textAlign: 텍스트 정렬 ('left','right','center','start','end')ctx.textBaseline: 텍스트 기준선 ('alphabetic','top','hanging','middle','ideographic','bottom')
ctx.fillStyle = 'black';
ctx.font = '30px Arial'; // 폰트 크기와 패밀리
ctx.textAlign = 'center'; // 수평 정렬
ctx.textBaseline = 'middle'; // 수직 정렬
// 캔버스 중앙에 텍스트 그리기
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
ctx.fillText('Hello Canvas!', centerX, centerY);
ctx.strokeStyle = 'gray';
ctx.lineWidth = 1;
ctx.font = '20px Sans-serif';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.strokeText('Web Graphics', 10, 10);경로(Paths) 상태 저장 및 복원
캔버스 컨텍스트의 현재 그리기 상태(색상, 선 두께, 변형 등)를 저장하고 나중에 복원할 수 있습니다. 이는 복잡한 그림을 그릴 때 매우 유용합니다.
ctx.save(): 현재 그리기 상태를 스택에 저장합니다.ctx.restore(): 스택의 가장 최근 상태를 복원합니다.
// 기본 상태: 빨간색, 두께 2
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 50, 50); // (0,0)에 빨간색 사각형
ctx.save(); // 현재 상태 저장 (빨간색, 두께 2)
ctx.fillStyle = 'blue'; // 새로운 상태: 파란색
ctx.fillRect(60, 0, 50, 50); // (60,0)에 파란색 사각형
ctx.save(); // 현재 상태 저장 (파란색, 두께 2)
ctx.fillStyle = 'green'; // 새로운 상태: 초록색
ctx.fillRect(120, 0, 50, 50); // (120,0)에 초록색 사각형
ctx.restore(); // 스택에서 가장 최근 상태 복원 (파란색)
ctx.fillRect(180, 0, 50, 50); // (180,0)에 파란색 사각형
ctx.restore(); // 스택에서 다음 상태 복원 (빨간색)
ctx.fillRect(240, 0, 50, 50); // (240,0)에 빨간색 사각형save()와 restore()는 색상, 선 스타일, 그림자, 변형(이동, 회전, 크기 조절) 등 모든 컨텍스트 속성들을 저장하고 복원합니다.
상태 저장과 복원은 중첩될수록 흐름이 헷갈리기 쉽습니다. 아래 다이어그램은 save()와 restore()를 작은 그리기 단위로 묶어 색상, 좌표 변환, 선 스타일이 의도치 않게 번지는 일을 막는 기준을 보여줍니다.
Canvas API 활용 분야
- 게임 개발: 2D 게임 엔진이나 캐주얼 게임 개발에 널리 사용됩니다.
- 데이터 시각화: 차트(막대 그래프, 파이 차트, 선 그래프 등)나 복잡한 통계 데이터를 시각적으로 표현하는 데 활용됩니다 (예: Chart.js).
- 이미지 편집: 이미지 필터 적용, 크롭, 회전, 그림 그리기 등의 기능 구현.
- 애니메이션: 프레임 단위로 그림을 지우고 다시 그리면서 동적인 애니메이션 효과를 만듭니다.
- 사용자 정의 UI 컴포넌트: SVG만으로는 부족한 복잡한 그래픽이 필요할 때 사용됩니다.
Canvas API 마무리
이번 장에서는 HTML5에 도입된 웹 그래픽 도구인 Canvas API의 기초를 학습했습니다.
<canvas> 요소와 getContext('2d')를 사용하면 JavaScript로 2D 렌더링 컨텍스트를 다룰 수 있습니다. 선, 사각형, 원, 텍스트를 그리는 기본 메서드와 save()/restore()를 이용한 상태 관리 흐름을 함께 확인했습니다.
Canvas API는 정적인 이미지로 표현하기 어려운 동적 그래픽을 직접 제어할 때 사용합니다. 웹 게임, 데이터 시각화, 인터랙티브 아트처럼 픽셀 단위 제어가 필요한 화면에서는 좌표계, 렌더링 순서, 다시 그리기 비용을 함께 고려해야 합니다.
Canvas API 기초 절은 Canvas API 개요 및 요소, 요소 준비, 렌더링 컨텍스트 가져오기 중심으로 개념, 코드 흐름, 실전 판단을 연결합니다.
Canvas API 기초를 학습할 때 흔들리기 쉬운 개념 경계와 적용 순서를 함께 정리했습니다.
다음 학습으로 넘어가기 전, Canvas API 기초에서 남은 개념 경계와 실습 확인 포인트를 점검합니다.