🩵 canvas는 HTML5에서 도입된 요소로, 픽셀 기반의 그래픽을 동적으로 그릴 수 있는 영역을 제공한다. 2D와 3D 그래픽을 그리기 위한 API를 지원하고, JavaScript를 사용해 그림을 그리거나 애니메이션을 구현할 수 있다.
📍canvas mdn 바로가기
🩵 canvas는 각 픽셀을 개별적으로 제어하며 복잡한 도형, 애니메이션, 이미지 등 다양한 시각적 요소를 렌더링 할 수 있다.
🩵 JavaScript의 2d(context)나 3d(WebGL) 을 이용해 그래픽을 그리거나 조작할 수 있다.
🩵 캔버스에서 그려지는 그래픽은 화면 해상도와 관계없이 독립적으로 동작하여 고해상도의 그래픽을 구현할 수 있으며, canvas.width/canvas.height 속성으로 크기를 조정할 수 있다.
🩵 그림을 그리는 도구들(선, 원, 사각형 등)을 사용하여 복잡한 도형을 그릴 수 있다. 또한, 이미지를 캔버스에 그린 후 필터 효과(예: 회전, 크기 조정, 색상 변경 등)를 적용할 수 있다.
🩵 주로, 2d 게임에서의 캐릭터 및 배경을 그릴 때, 차트 및 그래프를 구현할 때, 인터랙션을 구현할 때 등 사용된다.
🔹 <canvas id="myCanvas" width="500" height="500"></canvas>
🔸 HTML 문서에 canvas 태그를 추가하고, 기본 크기(width/height)를 지정하여 그래픽을 그릴 수 있는 공간을 설정한다. (코드 가독성을 위해 인라인으로 명시하는 편)
🔹 const canvas = document.querySelector('canvas');
🔹 const ctx = canvas.getContext('2d');
🔸 ctx(=context) : canvas에서 그리기 작업을 처리할 수 있는 객체, 일종의 브러쉬라고 생각하면 이해가 쉽다.
🔸 getContext() : 캔버스의 context를 얻고 2d와 3d(WebGL) 옵션이 있다. (대문자 D아니고 소문자 d!)
🔹 canvas.width=800;
🔹 canvas.height=800;
🔸 css로 설정해준 canvas 크기와 별개로 JS에서 한 번더 설정해야한다.
즉, 아래와 같이 작성하는 것이 기초 셋팅!
<script>
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width=800;
canvas.height=800;
</script>
🔸 rect(x, y, width, height) : 그림을 그릴 좌표(x, y)와 도형 크기(width, height)를 설정
🔹 rect()는 단순히 허공에 그리는 셈. 도형, 선을 그릴 때 항상 stroke 또는 fill로 선 그리기, 채우기를 해주어야 도형이 정상적으로 그려진다.
🔸 fillRect(x, y, width, height) : rect()와 fill() 함수를 동시에 동작! 즉, 도형을 그림과 동시에 색을 채움.
🔸 strokeRect(x, y, width, height) : rect()와 stroke() 함수를 동시에 동작! 즉, 도형을 그림과 동시에 선을 그림.
🔸 context는 순서를 가지기 때문에 style을 먼저 설정 후, 그리기를 진행해야한다.
🔹 ctx.lineWidth=2; : 선 굵기
🔹 ctx.strokeColor="#ddd"; : 선 색상
🔹 ctx.fillStyle="pink"; : 채우기 색상
🔸 예제) rect 속성으로 사각형 그리기

<script>
// canvas 기본세팅
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
ctx.fillStyle = "skyblue";
ctx.rect(50,50,100,100); // 첫 번째 도형
ctx.rect(150,150,100,100); // 두 번째 도형
ctx.rect(250,250,100,100); // 세 번째 도형
ctx.fill(); // 배경색 채우기
// ctx.stroke(); // 선으로 그리기
</script>
🔸 moveTo(), lineTo(), stroke() 메서드를 사용하여 직선을 그린다.
🔹 ctx.moveTo(x, y); : 그리기를 시작할 지점으로 좌표 이동(x축, y축). 즉, 브러쉬를 이동하는 개념이라고 생각하면 이해하기 쉽다.
🔹 ctx.lineTo(x, y); : 선을 그으면서 좌표 이동(x축, y축)
🔹 ctx.stroke(); : 경로를 따라 선 그리기. 해당코드를 반드시 써줘야 선을 그릴 수 있음!
🔹 ctx.fill(); : 직선으로 그린 도형을 채우고 싶다면 fill 속성으로 배경색을 채울 수 있다.
🔹 ctx.lineCap="round"; : 선 끝 모양을 설정 (butt, round, square)
🔸 context는 순서를 가지기 때문에 style을 먼저 설정 후, 그리기를 진행해야한다.
🔹 ctx.lineWidth=2; : 선 굵기
🔹 ctx.strokeColor="#ddd"; : 선 색상
🔹 ctx.fillStyle="pink"; : 채우기 색상
🔸 예제) 직선으로 사각형 그리기 (stroke)

<script>
// canvas 기본세팅
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
function onDrawLine(){
// 선 굵기, 색상 등 style 먼저 설정하기
ctx.lineWidth=3;
ctx.strokeStyle="red";
ctx.moveTo(50,50); // (50, 50) 좌표로 이동 (출발점 설정)
ctx.lineTo(150, 50); // (50,50) → (150,50) 좌표 이동하면서 선 그리기(윗변)
ctx.lineTo(150, 150); // (150,50) → (150,150) 좌표 이동하면서 선 그리기(우변)
ctx.lineTo(50, 150); // (150,150) → (50,150) 좌표 이동하면서 선 그리기(밑변)
ctx.lineTo(50, 50); // (50,150) → (50,50) 좌표 이동하면서 선 그리기 (시작점으로 돌아옴)
ctx.stroke(); //선 그리기
}
canvas.addEventListener("click", onDrawLine);
</script>
🔸 예제) 직선으로 사각형 그리기 + 색상 채우기 (fill)

<script>
// canvas 기본세팅
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
function onDrawLine(){
// 선 굵기, 색상 등 style 먼저 설정하기
ctx.lineWidth=3;
ctx.fillStyle="pink";
ctx.moveTo(50,50); // (50, 50) 좌표로 이동 (출발점 설정)
ctx.lineTo(150, 50); // (50,50) → (150,50) 좌표 이동하면서 선 그리기(윗변)
ctx.lineTo(150, 150); // (150,50) → (150,150) 좌표 이동하면서 선 그리기(우변)
ctx.lineTo(50, 150); // (150,150) → (50,150) 좌표 이동하면서 선 그리기(밑변)
ctx.lineTo(50, 50); // (50,150) → (50,50) 좌표 이동하면서 선 그리기 (시작점으로 돌아옴)
ctx.fill(); //선 채우기
}
canvas.addEventListener("click", onDrawLine);
</script>
🔸 예제) 도형 그리기(stroke) + 도형 색 채우기(fill)
🔹 ctx.beginPath(); : 하나의 context에서 그려지는 path를 분리시키기 위한 속성. 서로 다른 style을 지정하거나 독립시킬 때 사용! 이전 경로(path)가 초기화 되기 때문에 moveTo()를 먼저 사용해야 한다. 그렇지 않으면 새로운 경로의 시작점이 설정되지 않아서 lineTo()가 정상적으로 작동하지 않는다.
🔹 beginPath()를 쓰지 않았다면, 모든 도형이 빨간색으로 채워진다. 이유는 그림 모두가 같은 경로의 일부이기 때문!

<script>
// canvas 기본세팅
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
// 1, 2, 3 stroke 도형
ctx.rect(50,50,100,100);
ctx.rect(150,150,100,100);
ctx.rect(250,250,100,100);
ctx.stroke(); //위 그림에 선으로 채우기
// 빨간색 fill 도형
ctx.beginPath(); // path를 분리하여 새 그림을 그림
ctx.rect(350,350,100,100);
ctx.fillStyle="red";
ctx.fill();
</script>
🔸 예제) 원 그리기
🔹 ctx.arc(x, y, radius(반지름), starting angle, ending angle);
🔹 2Math.PI : 완벽한 원을 만드는 공식
🔸 ctx.arc(x, y, radius(반지름), 0, 2Math.PI); : 시작점 0, 끝점 2*Math.PI이 가장 완벽한 원을 만드는 공식!
🔸 ctx.arc(260, 80, 8, 1Math.PI, 2Math.PI); : 반원을 만드는 공식!

🩵 ctx.font = "48px serif"; : 폰트 관련 style 설정 (fontWeight, fontSize, fontFamily)
🩵 ctx.save() : ctx의 기존 상태, 색상, 스타일 등 모든 것을 저장
🩵 ctx.restore() : save()와 restore() 사이에 일시적으로 변경할 코드를 쓰고 restore()을 호출하면 수정이 완료된다. 즉, 기존 설정된 스타일과 다른 스타일을 주고 싶을 때 save()와 restore() 사이에서 설정해줌
<script>
if(text !== ""){
ctx.save(); // ctx의 현재 상태, 색상, 스타일 등 모든 것을 저장
ctx.lineWidth=1;
ctx.font = "48px serif"; // weight, size, font-family를 지정
ctx.restore(); // 수정 완료. save와 restore사이의 코드는 변수에 저장되지 않음(임시적이라는..)
}
</script>