Canvas API는 자바스크립트로 2D 그래픽을 그릴 수 있는 저수준 API입니다. 차트 라이브러리(Chart.js), 게임 엔진(Phaser), 이미지 편집 도구의 기반이 되는 기술입니다.

기본 설정

HTML
<canvas id="canvas" width="600" height="400"></canvas>
JS
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

// 고해상도 디스플레이 대응
const dpr = window.devicePixelRatio || 1;
canvas.width = 600 * dpr;
canvas.height = 400 * dpr;
canvas.style.width = "600px";
canvas.style.height = "400px";
ctx.scale(dpr, dpr);

도형 그리기

JS
// 사각형
ctx.fillStyle = "#3498db";
ctx.fillRect(10, 10, 100, 80); // 채운 사각형

ctx.strokeStyle = "#e74c3c";
ctx.lineWidth = 3;
ctx.strokeRect(130, 10, 100, 80); // 테두리 사각형

ctx.clearRect(20, 20, 30, 30); // 영역 지우기

// 원
ctx.beginPath();
ctx.arc(300, 50, 40, 0, Math.PI * 2); // x, y, 반지름, 시작각, 끝각
ctx.fillStyle = "#2ecc71";
ctx.fill();
ctx.stroke();

// 선
ctx.beginPath();
ctx.moveTo(10, 150);
ctx.lineTo(100, 200);
ctx.lineTo(200, 160);
ctx.strokeStyle = "#9b59b6";
ctx.lineWidth = 2;
ctx.stroke();

// 삼각형 (경로로 그리기)
ctx.beginPath();
ctx.moveTo(300, 150);
ctx.lineTo(350, 230);
ctx.lineTo(250, 230);
ctx.closePath();
ctx.fillStyle = "#e67e22";
ctx.fill();

텍스트

JS
ctx.font = "bold 24px Arial";
ctx.fillStyle = "#2c3e50";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Hello Canvas!", 300, 300);

// 텍스트 윤곽선
ctx.strokeStyle = "#e74c3c";
ctx.lineWidth = 1;
ctx.strokeText("Outline Text", 300, 340);

// 텍스트 너비 측정
const metrics = ctx.measureText("Hello");
console.log("너비:", metrics.width);

그라디언트와 패턴

JS
// 선형 그라디언트
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, "#3498db");
gradient.addColorStop(1, "#e74c3c");
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);

// 원형 그라디언트
const radial = ctx.createRadialGradient(150, 150, 10, 150, 150, 80);
radial.addColorStop(0, "yellow");
radial.addColorStop(1, "red");
ctx.fillStyle = radial;
ctx.beginPath();
ctx.arc(150, 150, 80, 0, Math.PI * 2);
ctx.fill();

이미지 그리기

JS
const img = new Image();
img.src = "photo.jpg";
img.onload = () => {
  // 기본 그리기
  ctx.drawImage(img, 0, 0);

  // 크기 지정
  ctx.drawImage(img, 0, 0, 200, 150);

  // 이미지 잘라서 그리기 (소스 영역 → 캔버스 영역)
  ctx.drawImage(img, 50, 50, 100, 100, 0, 0, 200, 200);
};

간단한 막대 차트

JS
function drawBarChart(data, labels) {
  const chartWidth = 500;
  const chartHeight = 300;
  const barWidth = chartWidth / data.length - 10;
  const maxValue = Math.max(...data);

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  data.forEach((value, i) => {
    const barHeight = (value / maxValue) * chartHeight;
    const x = i * (barWidth + 10) + 50;
    const y = chartHeight - barHeight + 30;

    // 막대
    ctx.fillStyle = `hsl(${i * 60}, 70%, 50%)`;
    ctx.fillRect(x, y, barWidth, barHeight);

    // 값 표시
    ctx.fillStyle = "#333";
    ctx.font = "14px Arial";
    ctx.textAlign = "center";
    ctx.fillText(value, x + barWidth / 2, y - 10);

    // 라벨
    ctx.fillText(labels[i], x + barWidth / 2, chartHeight + 50);
  });
}

drawBarChart([120, 80, 200, 150, 90], ["월", "화", "수", "목", "금"]);

변환 (Transform)

JS
// 저장 / 복원
ctx.save(); // 현재 상태 저장

ctx.translate(200, 200); // 원점 이동
ctx.rotate(Math.PI / 4);  // 45도 회전
ctx.scale(1.5, 1.5);      // 1.5배 확대

ctx.fillRect(-25, -25, 50, 50); // 변환된 좌표계에서 그리기

ctx.restore(); // 이전 상태 복원

간단한 게임 — 공 튕기기

JS
class Ball {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.radius = 15;
    this.dx = 3;
    this.dy = 3;
    this.color = "#e74c3c";
  }

  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
  }

  update(width, height) {
    // 벽 충돌 감지
    if (this.x + this.radius > width || this.x - this.radius < 0) {
      this.dx = -this.dx;
    }
    if (this.y + this.radius > height || this.y - this.radius < 0) {
      this.dy = -this.dy;
    }
    this.x += this.dx;
    this.y += this.dy;
  }
}

const ball = new Ball(100, 100);

function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ball.update(600, 400);
  ball.draw(ctx);
  requestAnimationFrame(gameLoop);
}

gameLoop();

마우스 이벤트와 Canvas

JS
function getMousePos(canvas, event) {
  const rect = canvas.getBoundingClientRect();
  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  };
}

// 그리기 도구
let isDrawing = false;

canvas.addEventListener("mousedown", (e) => {
  isDrawing = true;
  const pos = getMousePos(canvas, e);
  ctx.beginPath();
  ctx.moveTo(pos.x, pos.y);
});

canvas.addEventListener("mousemove", (e) => {
  if (!isDrawing) return;
  const pos = getMousePos(canvas, e);
  ctx.lineTo(pos.x, pos.y);
  ctx.stroke();
});

canvas.addEventListener("mouseup", () => {
  isDrawing = false;
});

Canvas를 이미지로 내보내기

JS
// Data URL로 변환
const dataURL = canvas.toDataURL("image/png");

// Blob으로 변환 (다운로드용)
canvas.toBlob((blob) => {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = "canvas.png";
  a.click();
  URL.revokeObjectURL(url);
}, "image/png");

Canvas vs SVG

항목CanvasSVG
렌더링래스터 (픽셀)벡터
DOM 접근불가가능
이벤트 처리좌표 계산 필요요소별 이벤트
대량 객체우수느림
확대깨짐깨지지 않음
적합한 용도게임, 이미지 편집아이콘, 차트, 지도

**기억하기 **: Canvas는 픽셀 기반 그래픽으로, 게임이나 대량 데이터 시각화에 적합합니다. SVG는 벡터 기반으로 확대해도 깨지지 않고 DOM 이벤트를 사용할 수 있어 인터랙티브 차트에 적합합니다. 실무에서는 대부분 Chart.js나 D3.js 같은 라이브러리를 통해 사용합니다.

댓글 로딩 중...