[HTML/canvas] Basic animations(1/2)

mdn의 캔버스 튜토리얼 따라하기
참고 : 캔버스 튜토리얼



<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas Example</title>
    <style type="text/css">
        canvas {
          border: 1px solid black;
        }
      </style>
</head>
<body>
  <canvas id="canvas1" width="300" height="300"></canvas>
  <canvas id="canvas2" width="150" height="150">The current time</canvas>
  <script src="scripts/myCanvas2.js"></script>
</body>
</html>
var sun = new Image();
var moon = new Image();
var earth = new Image();

function init() {
    sun.src = "images/3nee_20.jpg";
    moon.src = "images/3nee_20.jpg";
    earth.src = "images/3nee_20.jpg";

    window.requestAnimationFrame(drawSolarSystem);
}

function drawSolarSystem() {
    var ctx = document.getElementById("canvas1").getContext("2d");

    /*
    * 애니메이션 장면 단계
    * 1. 캔버스 비우기(clearRect())
    * 2. 캔버스 상태 저장
    * 3. 장면 그리기
    * 4. 상태 복원
    * 
    * 애니메이션 제어
    * 정해진 시간마다 그리기 함수 실행
    * 1. 예정된 변경(window.setInterval(), window.setTimeout())
    */

    // 새로운 그림을 기존 그림 위에 그리는 방식
   ctx.globalCompositeOperation = "destination-over";

   ctx.clearRect(0,0,300,300); // 캔버스 비우기

   ctx.fillStyle = "rgb(0 0 0 / 40%)"; // 지구 그림자
   ctx.strokeStyle = "rgb(0 153 255 / 40%)";
   ctx.save();

   // 좌표 원점 캔버스 중앙으로 이동
   ctx.translate(150,150);

   // 지구
   var time = new Date();
   ctx.rotate(
    ((2*Math.PI) / 60) * time.getSeconds() + // 1초당 각도 계산
    ((2*Math.PI) / 60000)* time.getMilliseconds(), // 밀리초당 각도 계산
   );
   ctx.translate(105,0); // 지구 위치로 이동
   ctx.fillRect(0,-12,40,24); //지구 그림자 그리기
   ctx.drawImage(earth, -12, -12, 30, 30);

   // 달
   ctx.save();
   // 원점이 지구인 상태에서 각도 회전
   ctx.rotate(
    ((2*Math.PI) / 6) * time.getSeconds() +
    ((2*Math.PI) / 6000)* time.getMilliseconds(),
   );
   // 거리를 벌려 지구를 도는 것처럼 보이게
   ctx.translate(0, 28.5);
   ctx.drawImage(moon, -3.5, -3.5, 10, 10);
   ctx.restore(); // moon의 상태 복원

   ctx.restore(); // 전체 변환 상태 복원

   ctx.beginPath();
   ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // 지구궤도
   ctx.stroke();

   ctx.drawImage(sun,125,125,50,50);

   window.requestAnimationFrame(drawSolarSystem);
}
init();

function clock() {
    const now = new Date();
    var canvas = document.getElementById("canvas2");
    var ctx = canvas.getContext("2d");

    ctx.save();
    ctx.clearRect(0,0,150,150);
    ctx.translate(75,75);
    ctx.scale(0.4,0.4);
    ctx.rotate(-Math.PI / 2);
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = 8;
    ctx.lineCap = "round";

    // 시 세팅
    ctx.save();
    for(let i=0; i<12; i++) {
        ctx.beginPath();
        ctx.rotate(Math.PI / 6);
        ctx.moveTo(100, 0);
        ctx.lineTo(120, 0);
        ctx.stroke();
    }
    ctx.restore();

    // 분 세팅
    ctx.save();
    ctx.lineWidth = 5;
    for(let i=0; i<60; i++) {
        if(i%5 !== 0) {
            ctx.beginPath();
            ctx.moveTo(117, 0);
            ctx.lineTo(120, 0);
            ctx.stroke();
        }
        ctx.rotate(Math.PI / 30);
    }
    ctx.restore();

    // 현재 시간 세팅
    const sec = now.getSeconds();
    const min = now.getMinutes();
    const hr = now.getHours() % 12;

    ctx.fillStyle = "black";

    canvas.innerText = `The time is: ${hr}:${min}`;

    // 시침
    ctx.save();
    // 시간은 30도, 분은 6도, 초는 0.1도이므로 각 시분초에 해당 각을 곱하여 최종 시간각 계산
    // 시계바늘들이 서로 다른 속도로 회전, 분침이 시침보다 60배 초침이 분침보다 60배 빠르다
    ctx.rotate(
        (Math.PI / 6) * hr + (Math.PI / 360) * min + (Math.PI / 21600) * sec,
    );
    ctx.lineWidth = 14;
    ctx.beginPath();
    ctx.moveTo(-20, 0);
    ctx.lineTo(80,0);
    ctx.stroke();
    ctx.restore();

    // 분침
    ctx.save();
    ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec);
    ctx.lineWidth = 10;
    ctx.beginPath();
    ctx.moveTo(-28, 0);
    ctx.lineTo(112,0)
    ctx.stroke();
    ctx.restore();

    // 초침
    ctx.save();
    ctx.rotate((sec * Math.PI) / 30);
    ctx.strokeStyle = "#D40000";
    ctx.fillStyle = "#D40000";
    ctx.lineWidth = 6;
    ctx.beginPath();
    ctx.moveTo(-30, 0);
    ctx.lineTo(83,0);
    ctx.stroke();

    // 중앙 동그라미
    ctx.beginPath();
    ctx.arc(0,0,10,0,Math.PI*2, true);
    ctx.fill();

    // 초침 끝 동그라미
    ctx.beginPath();
    ctx.arc(95,0,10,0,Math.PI*2, true);
    ctx.stroke();

    // ctx.fillStyle = "rgb(0 0 0 / 0%)";
    // ctx.arc(0,0,3,0,Math.PI*2, true);
    // ctx.fill();
    ctx.restore();

    // 시계 틀
    ctx.beginPath();
    ctx.lineWidth = 14;
    ctx.strokeStyle = "#325FA2";
    ctx.arc(0,0,142,0,Math.PI*2, true);
    ctx.stroke();
    ctx.restore();

    window.requestAnimationFrame(clock);
}

window.requestAnimationFrame(clock);

짜려면 머리가 돌아가야하는데 0부터 만들라고하면 만들 수 있으려나... 🫠