JavaScript

캔버스

9tun 2025. 5. 5. 19:58

캔버스란

  • 웹 문서에 Canvas API를 이용해서 그림을 그릴 수 있는 기능

캔버스 생성

 

<canvas>

<canvas></canvas>

<canvas width = "너비" height = "높이"></canvas>

 

  <div id="canvas-1">
    <h2>크기를 지정하지 않을 때</h2>
    <canvas></canvas>
  </div>
  <div>
    <h2>크기를 지정했을 때 400*300</h2>
    <canvas width="400" height="300"></canvas>
  </div>

 

화면 전체를 캔버스로 사용하는 방법

화면 전체를 캔버스로 사용하기 위해서는 몇 가지 여백과 스크롤 막대를 없애야 한다.

  <style>
    body {
      margin:0;			/* 여백 기본값을 0으로 설정 */
      overflow:hidden;		/* 스크롤 막대 숨기기 */
    }
    canvas {
      background-color:#ccc;
    }
  </style>

 

const canvas = document.querySelector('canvas');	/* canvas 태그 불러오기 */
    
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

 

getContext() 메서드로 렌더링 콘텍스트 생성하기

 

👨‍🏫 랜더링 콘텍스트란

렌더링 콘텍스트는 그래픽을 그리기 위한 상태와 환경을 담고 있는 객체입니다.
즉, "무엇을 그리고, 어떻게 그릴지"를 지정하는 작업 공간이라 할 수 있습니다.

 

쉽게 말해서

 

  • 캔버스(Canvas) = 도화지
  • 렌더링 콘텍스트 = 붓 + 색상 + 그리기 도구들 세트

canvas.getContext("2d")

 

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(10, 10, 50, 100);

 

캔버스의 좌표

 

캔버스의 원점은 왼쪽 상단이다.

오른쪽으로 갈수록 x 좌표가 커지고, 아래쪽으로 갈수록 y좌표가 커진다.

 

캔버스의 각도

각도는 라디안 값으로 표기합니다.

 

radians = (Math.PI / 180) * degree

 

수학 때 배운 것과는 다르게 시계방향이 정방향이다.

 

캔버스에 기본 도형 그리기

 

사각형

사각형 생성 메서드

메서드 기능
fillRect(x, y, width, height) (x, y)에서 시작해 지정한 너비와 높이만큼 색이 채워진 사각형을 생성, 색상 디폴트 = 검은색
strokeRect(x, y, width, height) (x, y)에서 시작해 지정한 너비와 높이만큼 테투리만 있는 사각형 생성, 선 색상 = 검은색
clearRect(x, y, width, height) (x, y)에서 시작해 지정한 너비와 높이만큼 사각형 영역을 지움

 

채우기 색과 선 색 지정

메서드 기능
fillStyle = "색상" 도형을 채우는 색상 지정
strokeStyle = "색상" 도형의 선 색상을 지정

 

삼각형

캔버스는 사각형 그리기만 제공하므로, 다른 도형을 그리려면 경로 그리기로 그려야 합니다.

 

👨‍🏫 경로 그리기 순서

1. beginPath()
→ 새로운 경로 시작

2. 원하는 경로 그리기

 1) moveTo(x, y)
  → 시작점 이동
 2) lineTo(x, y)
  → 선 그리기 (필요하면 여러 번 사용 가능)
 3) (필요 시) arc(), quadraticCurveTo(), bezierCurveTo() 등
  → 곡선, 원, 복잡한 도형 추가 가능

3. closePath()
→ 경로 닫기 (선택 사항, 보통 도형 마무리에 사용)

4. stroke() 또는 fill()
→ 외곽선 그리기 / 내부 색 채우기

 

경로 그리기의 시작과 끝

beginPath()

closePath()

 

// 경로 그리기 시작

// 경로 그리기 종료

 

직선 경로

lineTo(x, y)

 

// 시작점에서 (x, y)까지 직선 경로 생성, 경로는 생성하지만 화면에 나타나지는 않음

 

경로 그리기 및 색 채우기

stroke()

fill()

 

// 경로를 화면에 나타냄

// 닫힌 공간을 만들었으면 색을 채울 수 있음

 

위치 옮기기

moveTo(x,y)    

 

// 시작점을 (x, y)로 옮김

// 캔버스를 처음 만들면 시작점은 원점 (0, 0) 입니다. 

 

자, 그럼 시작점 (50, 50)부터 (200, 200)까지 직선을 그려보자!

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 200);
ctx.stroke();

 

내친김에 삼각형도 그려보자!

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

/* 경로를 시작합니다. */
ctx.beginPath();
/* 시작점을 (50,50) 위치로 이동시킵니다. */
ctx.moveTo(50, 50);
/* 시작점에서 (150, 100)까지 경로를 만듭니다. */
ctx.lineTo(150, 100);
/* 앞서 그린 경로 끝점에서 (50,150)까지 경로를 만듭니다. */
ctx.lineTo(50, 150);
/* 경로를 닫습니다. (닫힌 도형) */
ctx.closePath();
/* 지금까지 만든 경로를 선으로 그립니다. */
ctx.stroke();

/* 경로를 시작합니다. */
ctx.beginPath();
/* 시작점을 (150, 100) 위치로 이동시킵니다. */
ctx.moveTo(150, 100);
/* 시작점에서 (250, 50)까지 직선을 만듭니다. */
ctx.lineTo(250, 50);
/* 시작점에서 (250, 150)까지 직선을 만듭니다. */
ctx.lineTo(250, 150);
/* 경로를 닫습니다. (닫힌 도형) */
ctx.closePath();
/* 채우기 색을 rgb(0,200,0)으로 지정합니다. */
ctx.fillStyle = "rgb(0, 200, 0)";
/* 만들어진 (닫힌) 도형에 색을 채웁니다. */
ctx.fill();
/* 도형 외곽선을 그립니다. */
ctx.stroke();

 

원이나 호 그리기

 

arc(x, y, r, startAngle, endAngle [, counterClockwise])

 

원 생성

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.fillStyle = "yellow";
ctx.strokeStyle = "red";

ctx.beginPath()
ctx.arc(200, 150, 100, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.stroke();

 

반원과 호 그리기

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

/* 붉은색 채우기 설정 */
ctx.fillStyle = "red";

/* 첫 번째 반원: 반시계 방향 */
ctx.beginPath();
ctx.arc(120, 100, 50, 0, (Math.PI / 180) * 180, true);	/* 반시계 방향 */
ctx.arc(280, 100, 50, 0, (Math.PI / 180) * 180, false);	/* 시계 방향 */ 
ctx.fill();

/* 두 번째 반원: 시계 방향으로 선만 그리기 */
ctx.beginPath();
ctx.arc(120, 200, 50, (Math.PI / 180) * 90, (Math.PI / 180) * 270, false); 
ctx.closePath();
ctx.stroke();

/* 세 번째 호: 파란색 외곽선만 그리기 */
ctx.strokeStyle = "blue";
ctx.beginPath();
ctx.moveTo(200, 100);
ctx.arc(200, 200, 50, 0, (Math.PI / 180) * 60, false); 
ctx.stroke();

타원 그리기

ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle [, counterClockwise])

  • radiusX: 가로 반지름
  • radiusY: 세로 반지름
  • rotation: 타원 회전 크기, 라디안 값
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.strokeStyle = "red";
ctx.beginPath();
ctx.ellipse(200, 70, 80, 50, 0, 0, Math.PI * 2);
ctx.stroke();

ctx.strokeStyle = "blue";
ctx.beginPath();
ctx.ellipse(150, 200, 80, 50, (Math.PI / 180) * -30, 0, Math.PI * 2);
ctx.stroke();

 

원을 변형해서 타원 그리기

scale(x, y)

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

/* 원의 세로 길이를 축소해서 타원으로 그리기 */
ctx.strokeStyle = "blue";
ctx.scale(1, 0.7);  /* 가로 길이 유지, 세로 길이 축소 */
ctx.beginPath()
ctx.arc(200, 150, 80, 0, Math.PI * 2, true);
ctx.stroke();
ctx.beginPath()
ctx.arc(200, 150, 30, 0, Math.PI * 2, false);
ctx.stroke();
ctx.closePath();

곡선 그리기

2차 베지에 곡선 (Bezier Curve)

베지에 곡선은 시작점과 끝점 사이에 조절점을 통해 그린 곡선이다.

 

quadraticCurveTo(cpx, cpy, x, y)

  • cpx, cpy: 조절점 좌표

 

 

조절점 갯수에 따라 베지에 곡선의 차수가 달라진다.

  • 1차 베지에 곡선: 조절점 0개 (=직선)
  • 2차 베지에 곡선: 조절점 1개
  • 3차 베지에 곡선: 조절점 2개

조절점 1개로 곡선을 그려봅시다.

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.beginPath();
ctx.moveTo(50, 200);   /* 곡선 시작 위치 */
ctx.quadraticCurveTo(200, 50, 350, 200); /* 시작 위치부터 (350, 200)까지 곡선 그리기 */
ctx.stroke();

 

조절점 3개로 물결 곡선을 만들어 보자!

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.beginPath();
ctx.moveTo(50, 100);   /* 곡선 시작 위치 */
ctx.quadraticCurveTo(100, 50, 150, 100); 
ctx.quadraticCurveTo(200, 150, 250, 100); 
ctx.quadraticCurveTo(300, 50, 350, 100); 
ctx.stroke();

3차 베지에 곡선

조절점 2개를 사용해서 곡선을 그려봅시다.

 

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

 

  • cp1x, cp1y: 첫 번째 조절점 좌표
  • cp2x, cp2y: 두 번째 조절점 좌표
  • x, y: 곡선이 끝나는 점의 좌표
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");    

ctx.beginPath();
ctx.moveTo(50, 100);   /* 곡선 시작 위치 */
ctx.bezierCurveTo(90, 250, 310, 10, 350, 100); 
ctx.strokeStyle = "green";    
ctx.stroke();

Path2D

경로(도형의 윤곽)를 정의하고 재사용할 수 있게 해주는 객체

복잡한 도형을 미리 만들어 놓고, 캔버스에 그릴 때 간편하게 불러와 사용할 수 있습니다.

 

new Path2D()

new Path2D(경로)

 

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");  

let triangle = new Path2D();   /* 삼각형 경로 객체 */
triangle.moveTo(100, 100);
triangle.lineTo(300, 100);
triangle.lineTo(200, 260);
triangle.closePath();

let circle = new Path2D();    /* 원 경로 객체 */
circle.arc(200, 155, 50, 0, Math.PI * 2);

ctx.fillStyle = "green";
ctx.stroke(triangle);	/* 삼각형 그리기 */
ctx.fill(circle);	/* 원 그리기 */

캔버스에 텍스트 그리기

텍스트를 그리는 메서드

 

fillText(text, x, y [,maxWidth])            // 텍스트를 채움

strokeText(text, x, y [,maxWidth])     // 텍스트 선만 그림

  • text: 캔버스에 그릴 텍스트
  • x, y: 텍스트를 표시할 좌표
  • maxWidth: 텍스트를 표시할 최대 너비
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");

ctx.font = "60px Arial";		/* 글자 크기와 글꼴 설정은 쉼표, 공백 없이 */
ctx.fillText("HELLO", 50, 70);	/* 텍스트 채움 */
ctx.strokeText("HELLO", 50, 150);	/* 텍스트 선만 그림 */

캔버스의 이미지

이미지 표시

이미지 가져오기

let img = new Image();		/* 새로운 이미지 객체 생성 */
img.src = "spring.jpg";		/* 이미지 객체에 파일 경로 지정 */

 

이미지 그리기

drawImage(image, dx, dy)

  • image: 캔버스에 표시할 이미지 객체 지정
  • dx, dy: 캔버스 왼쪽 위 모서리로부터 얼마나 떨어져서 이미지를 표시할지 지정

👨‍🏫 drawImage는 context의 메서드입니다. onload 이벤트와 함께 함수를 실행

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");

let img = new Image();
img.onload = function() {		/* 이미지 객체의 load 이벤트 */
  ctx.drawImage(img, 0, 0);	/* Context 메서드 drawImage 사용 */
} 
img.src = "images/cat.jpg";

 

이미지 크기 조절

drawImage(image, dx, dy, dw, dh)

  • image: 캔버스에 표시할 이미지 객체 지정
  • dx, dy: 캔버스 왼쪽 위 모서리로부터 얼마나 떨어져서 이미지를 표시할지 지정
  • dw, dh: 캔버스에 표시할 이미지 크기 지정
ctx.drawImage(img, 0, 0, 300, 200);

 

캔버스 크기에 딱 맞게 하려면 아래와 같이 하면 된다.

ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

 

이미지 일부만 표시

이미지 잘라내서 표시하기

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

  • image: 캔버스에 표시할 이미지 객체 ㅈ지정
  • sx, sy: 이미지 왼쪽 위 모서리로부터 얼마나 떨어진 곳부터 자를지 (자를 이미지 좌상단 좌표)
  • sw, sh: 잘라낼 이미지의 너비와 높이
  • dx, dy: 캔버스의 왼쪽 위 모서리로 부터 얼마나 떨어진 곳에 이미지를 붙일지
  • dw, dh: 이미지의 너비와 높이
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");

let img = new Image();
img.onload = function() {
  ctx.drawImage(img, 100, 50, 280, 350, 160, 100, 140, 175);   
} 
img.src = "images/cat.jpg";

 

이미지 클리핑

👨‍🏫 클리핑이란?

경로를 그려 놓고 경로 밖은 감추는 것

 

clip()

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");

let img = new Image();
img.onload = function() {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);   // 캔버스 크기에 맞게 지정
} 
img.src = "images/bird.jpg";
ctx.beginPath();
ctx.arc(300, 200, 150, 0, Math.PI * 2, false);	/* 원 경로 만듦 */
ctx.clip();	/* 클리핑 */

 

'JavaScript' 카테고리의 다른 글

애니메이션  (0) 2025.05.15
캔버스의 그래픽 요소  (0) 2025.05.07
비동기 프로그래밍  (0) 2025.04.26
HTTP 통신과 JSON  (0) 2025.04.22
배열과 객체  (0) 2025.04.10