[HTML Canvas] 오징어를 그려보자🦑

영근·2024년 7월 17일
0

HTML5 Canvas

목록 보기
1/1
post-thumbnail

Intro

HTML 캔버스 관련 MDN 문서를 보면서 삼각형, 원 등을 그려보며 너무 신기한 마음에 언니에게 자랑했더니 이런 대답을 받았습니다.

왜 오징어를 그려보라고 했는지는 모르지만,
"엇? 오징어? 재밌겠는데?" 하고 바로 도전해버렸습니다.



1. 스케치북 만들기

HTML

HTML 캔버스를 사용하기 위해서는 먼저, 그림을 그릴 스케치북을 준비해야 합니다.
요런 스케치북이 될 element를 먼저 준비해줍니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Canvas Playground !</title>
    <style type="text/css">
      canvas {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" width="720" height="480"></canvas> 
    <script src="./index.js"></script>
    <script src="./squid.js"></script>
  </body>
</html>

캔버스의 크기는 원하시는 대로 설정하시면 됩니다.
저는 가로 720px, 세로 480px의 스케치북을 준비했습니다.

JS

그리고 그림을 그릴 수 있게 컨텍스트를 만들어줍니다.
스케치북에 그림을 그려줘야(렌더링) 하기 때문입니다.

이 때, 브라우저에 따라 캔버스를 지원하지 않을 수 있습니다.
지원 여부는 하단 getContext 를 통해 확인할 수 있습니다.

const canvas = document.querySelector('canvas'); // canvas element를 가져옵니다.
const ctx = canvas.getContext('2d');

// 캔버스 지원여부 검사
if(!canvas.getContext){
    console.log('캔버스를 지원하지 않습니다 :(')
} else {
    console.log('캔버스!')
}

만들어 둔 스케치북을 확인할 수 있습니다.
제가 사용하는 크롬 브라우저에서는 캔버스를 지원하기 때문에, 콘솔에서 '캔버스!'를 확인할 수 있습니다.



2. 오징어 몸통 그리기

그리기 Basic

가장 먼저, 어떤 식으로 도형을 그리는지 그 원리를 간단히 알아보겠습니다.
종이에 도형을 그릴 때 먼저 펜으로 시작점을 찍고 시작하듯이, 캔버스에서도 시작 좌표를 설정해야 합니다.

  • 먼저, 시작한다는 사실을 알립니다.
ctx.beginPath()
  • 시작점을 설정합니다.
ctx.moveTo(100, 100); 
  • 선을 그립니다.(실제 그리는 것은 아닙니다.)
ctx.lineTo(200, 200);
  • 그린 선을 렌더링하여 화면에 나타냅니다.
ctx.stroke();
  • 선택 사항 : 선을 닫습니다.(시작점과 끝점을 일직선으로 연결합니다)
ctx.closePath();
// 이 때, 위에서 ctx.fill()로 채우기를 했다면 자동으로 닫히기 때문에 생략해도 됩니다.

이제 이 원리를 이용해 본격적으로 삼각형을 그려보겠습니다.

삼각형

ctx.beginPath();
ctx.moveTo(100, 100); // 시작점 설정
ctx.lineTo(200, 200); // 선 그리기
ctx.lineTo(0, 200); // 선 그리기
ctx.lineTo(100, 100); // 선 그리기
ctx.stroke(); // 렌더

이렇게 삼각형을 그렸습니다.

사각형 몸통

다음은 몸통인데, 오징어는 직사각형보다는 사다리꼴에 가까운 모양일 것 같아, 조금 비스듬히 그렸습니다.

ctx.beginPath();
ctx.moveTo(50, 200);
ctx.lineTo(40, 300);
ctx.lineTo(160, 300);
ctx.lineTo(150, 200);
ctx.stroke();

멋진 몸통이 완성되었습니다.

조금 허전하니 눈을 그려주겠습니다.

웃는 눈을 그리고 싶기 때문에 원을 그려야 했습니다.
캔버스에서 원은 arc() 메서드를 사용해 그릴 수 있습니다.
arc() 메서드는 다음과 같이 사용할 수 있습니다.

ctx.arc(70, 230, 10, Math.PI * 1, Math.PI * 0);
// x, y, 반지름, startAngle, endAngle, 시계방향(default : false - 시계방향)

천천히 알아보겠습니다.
먼저 x, y는 원을 그리는 기준이 되는 중심점의 좌표값이고, 반지름도 함께 설정해줍니다.
startAngle과 endAngle은 그리는 시작 각도와 끝 각도인데, 다음 이미지와 같습니다.

3시 기준이 0 PI로, 시계방향으로 돌면서 0.5PI 씩 커집니다.
이 때, Math.PI를 이용해 원주율을 곱해 표기해줘야 합니다.

그리고 마지막 파라미터는 optional한 값으로, 어느 방향으로 그릴지를 나타냅니다.(default - false)
위 코드에서는 지정해주지 않았기 때문에 시계방향으로 그리는 코드가 되겠습니다.

이러한 arc() 코드를 이용해 이렇게 눈을 그렸습니다.

좀 더 귀여워졌네요.

다음으로는, 대망의 다리를 그려보겠습니다.



오징어 다리 그리기

오징어 다리를 그냥 직선으로 표시할 수도 있었지만, 그래도 흐물흐물한 다리를 표현하기 위해 곡선을 그리기로 했습니다.

곡선을 그리는 여러 방법이 있지만, 여기서는 호를 그리는 arcTo() 메서드를 사용해 그려보겠습니다.

arcTo(x1, y1, x2, y2, radius)

x1, x2는 첫 번째 기준 좌표, x2, y2는 두 번째 기준 좌표, 그리고 radius는 반지름 입니다.

호를 그리는 원리는 이러합니다.

  1. 파란색 점 에서 시작
  2. 첫 번째 기준 좌표(우측 하단 빨간 점), 두 번째 기준 좌표(좌측 상단 빨간 점) 설정
  3. radius를 통해 그 안에 들어갈 원의 크기를 조절

이런식으로 조절하며 그리는 방법입니다.
MDN문서에 아주 자세히 설명되어 있으니, 한 번 읽어보시는 걸 추천드립니다.

아무튼 이 방식을 이용해 꼬불꼬불 다리를 그려줄텐데, 첫 번째 호와 두 번째 호가 자연스럽게 맞물려야 하기 때문에, 이런 식으로 그려주었습니다.

위 아래로 대칭되는 호를 그리는데, 이 때 기준이 되는 원의 반지름을 피타고라스의 정리를 활용해 구해줍니다.

그리고 그 결과, 다리를 이렇게 그릴 수 있었습니다.

하지만 오징어의 다리는 8개라서, 같은 모양의 다리가 8개 필요합니다.
다리를 그리는 코드를 함수화 하고, 반복문을 이용해 다리를 추가해주었습니다.

const legHalf = 40; // 다리(1/2)의 길이
const legGap = 15; // 다리와 다리 사이의 간격
let startX = 40;
let startY = 300;

const drawLeg = (idx) => {
  let currentX = startX + idx * legGap;
  let currentY = startY;
  // 1번 꼬불이
  ctx.beginPath();
  ctx.moveTo(currentX, currentY);
  ctx.arcTo(
    currentX - legHalf,
    currentY + legHalf,
    currentX,
    currentY + 2 * legHalf,
    Math.sqrt(legHalf ** 2 + legHalf ** 2)
  );
  ctx.stroke();

  // 기준점 이동
  currentX = currentX;
  currentY = currentY + 2 * legHalf;

  // 2번 꼬불이
  ctx.beginPath();
  ctx.moveTo(currentX, currentY);
  ctx.arcTo(
    currentX + legHalf,
    currentY + legHalf,
    currentX,
    currentY + 2 * legHalf,
    Math.sqrt(legHalf ** 2 + legHalf ** 2)
  );

  ctx.stroke();
};

for (let i = 0; i < 7; i++) {
  drawLeg(i);
}

따봉 다리

다리들이 완성되었습니다.
하지만 다리가 7개입니다. 왠지 마지막 다리는 다르게 표현하고 싶었습니다.
그래서 그동안 학습했던 여러 메서드를 활용해 따봉 다리를 만들어주었습니다.

// 따봉 다리
ctx.beginPath();
ctx.arc(160, 300, 20, Math.PI * 0, Math.PI * 1); // x, y, 반지름, startAngle, endAngle, 시계방향(default : false - 시계방향)
ctx.stroke();

ctx.beginPath();
ctx.moveTo(180, 300);
ctx.arcTo(180, 240, 240, 240, 20);
ctx.stroke();

// 따봉 엄지
ctx.beginPath();
ctx.moveTo(200, 240);
ctx.lineTo(200, 210);
ctx.stroke();

// 따봉 주먹
ctx.beginPath();
ctx.arc(200, 230, 10, Math.PI * 1.5, Math.PI * 0.5);
ctx.stroke();

완성!

보기엔 허접한 초딩 그림같지만, 그래도 순수 HTML + JS로 귀여운 그림을 그린 것에 만족하며, 포스팅을 마치겠습니다.
이 글을 읽는 분들께 따봉징어의 가호가 함께 하시길...

profile
Undefined JS developer

1개의 댓글