## 삼각함수를 이용한 개선된 소스

<!DOCTYPE html>
<html>
<body>

<canvas id="canvas" width="400" height="400"
style="background-color:#333">
</canvas>

<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
setInterval(drawClock, 1000);

function drawClock() {
  drawFace(ctx, radius);
  drawNumbers(ctx, radius);
  drawTime(ctx, radius);
}

function drawFace(ctx, radius) {
  var grad;
  ctx.beginPath();
  ctx.arc(0, 0, radius, 0, 2*Math.PI);
  ctx.fillStyle = 'white';
  ctx.fill();
  grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
  grad.addColorStop(0, '#333');
  grad.addColorStop(0.5, 'white');
  grad.addColorStop(1, '#333');
  ctx.strokeStyle = grad;
  ctx.lineWidth = radius*0.1;
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
  ctx.fillStyle = '#333';
  ctx.fill();
}

function drawNumbers(ctx, radius) {
    ctx.font = radius*0.15 +"px arial";
    ctx.textBaseline="middle";
    ctx.textAlign="center";
   
    var pos = radius*0.85;
    for (var num = 1; num < 13; num++) {
        var x = pos * Math.cos(Math.PI* ((30 * num)-90)/ 180);
        var y = pos * Math.sin(Math.PI* ((30 * num)-90)/ 180);
 
        ctx.fillText(num.toString(), x, y);
    }
}
  
function drawTime(ctx, radius){
    var now =new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();
    var pos = radius*0.5;
     
    //hour
    x = pos* Math.cos(Math.PI* ((hour*30)- 90 + 30/60*minute + 30/60/60*second) / 180);
    y = pos* Math.sin(Math.PI* ((hour*30)- 90 + 30/60*minute + 30/60/60*second) / 180);
    drawHand(ctx, x, y, radius*0.07);
     
    //minute
    pos = radius*0.8;
    x = pos * Math.cos(Math.PI* ((minute * 6)- 90 + 6/60*second)/ 180);
    y = pos * Math.sin(Math.PI* ((minute * 6)- 90 + 6/60*second)/ 180);
    drawHand(ctx, x, y, radius*0.07);
     
    // second
    pos = radius*0.9;
    x = pos * Math.cos(Math.PI* ((second * 6)- 90)/ 180);
    y = pos * Math.sin(Math.PI* ((second * 6)- 90)/ 180);
    drawHand(ctx, x, y, radius*0.02);
}

function drawHand(ctx, x, y, width) {
    ctx.beginPath();
    ctx.lineWidth = width;
    ctx.lineCap ="round";
    ctx.moveTo(0,0);
    ctx.lineTo(x, y);
    ctx.stroke();
}


</script>

</body>
</html>

 

 

앞서 개요에 있는 w3schools의 예제는

rotate와 translate를 이용하여

좌표의 기준 축을 이동시켜서

각각의 위치에 시간을 표시했다.

 

여기서는 간단한 삼각함수를 이용하여 구현하는 방법을 정리한다.

먼저, 시계를 구현하기 위해 삼각함수가 필요한 이유는

다음 그림에서 첫 번째 그림을 참고하면 된다.

시간을 출력하기 위해서

각 시간의 X, Y 좌표 값을 계산한다.

예로 1시의 좌표는 그림에서 보듯이

시계 중앙에서 시작된 직삼각형을 이용할 수 있다.

 

먼저, X 좌표는 두 번째 그림의 b길이에 해당한다.

(b의 시작점은 0 이고 종료점이 길이 이기 때문에...)

a 값은 원의 반지름,

즉 앞서 예제에서는 radius가 된다.

각도는 1 / 12 * 360 이므로 30도로 계산된다.

즉, 한변과 각도(끼인각)을 이용하면 b를 계산할 수 있고

이때 사용하는 것이 삼각함수 cos 이고

공식은 다음과 같다.

cos 30 = b / a

=> b = cos 30 * a

다만, 라디안으로 구현해야 하므로

=> b = cos (30 / 180) * a

 

다음으로 Y좌표는

그림에서 보듯이 c 값을 구해야 한다.

각도와 a의 값을 알고 있으니

삼각함수 sin을 이용해서 계산한다.

sin 30 = c / a

=> c = sin 30 * a

=> c = sin (30 / 180) * a

 

정리하면 X, Y 좌표는

X = cos (30 / 180) * a

Y = sin (30 / 180) * a

으로 간단하게 구할 수 있다.

 

그런데 다음 그림과 같이 문제가 있다.

첫번째 그림과 같이 Canvas에서는 시작하는 각도는

12시 부분이 기준으로 0 (360)도가 된다.

삼각함수는 두 번째 그림과 같이

3시 부분이 기준으로 0 (360)도가 된다.

이 내용을 다시 다음 표로 정리했다.

시간

시간에 대한 각도

실제 각도

30  -60 

60  -30 
90 
120  30 
150  60 
180  90 
210  120 
240  150 
270  180 
10  300  210 
11  330  240 
12  360  270 

여기서 공식이 나오게 된다.

각 시간의 실제 각도 (시간 * 30)는

시간에 계산된 각도에서 90을 빼준 값(-90)이다.

즉, 끼인각은

(시간 * 30) - 90

이라는 공식으로 계산하게 된다.

이 공식을 앞서의 좌표와 합치면 다음과 같다.

X = cos (((시간 * 30) - 90) / 180) * a

Y = sin (((시간 * 30) - 90) / 180) * a

 

이것을 자바스크립트로 작성하면

다음 코드의 8과 9라인이 된다.

 

function drawNumbers(ctx, radius) {
    ctx.font = radius*0.15 +"px arial";
    ctx.textBaseline="middle";
    ctx.textAlign="center";
   
    var pos = radius*0.85;
    for (var num = 1; num < 13; num++) {
        var x = pos * Math.cos(Math.PI* ((30 * num)-90)/ 180);
        var y = pos * Math.sin(Math.PI* ((30 * num)-90)/ 180);
 
        ctx.fillText(num.toString(), x, y);
    }
}

 

공식에서 사용된 변수 a는 반지름을 의미하므로

radius값을 이용한 pos(시계보다 작은값 부여) 된다.

w3schools 예제에서는 fillText 함수의 좌표 값이 0, 0 이었지만

여기서는 계산된 좌표 값이 부여 되었다.

w3schools는 기준축을 이동시켰고

여기서는 기준축을 시계 중앙에 고정시키고

출력할 좌표 값을 변경하는 방식을 사용한 것이다.

 

 



출처: https://forest71.tistory.com/104?category=606376 [SW 개발이 좋은 사람]

 

 

+ Recent posts