여러분이 사용하고 계신 브라우저는 HTML5를 지원하지 않기 때문에 몇몇 요소가 제대로 보이도록 JScript를 사용하고 있습니다. 하지만 여러분의 브라우저 설정에서 스크립트 기능이 꺼져있으므로, 현재 페이지를 제대로 확인하시려면 스크립트 기능을 켜주셔야 합니다. Canvas 시계 - 페이스

Canvas 시계 – 페이스

3주전 작성

HTML Canvas 시계 페이스

HTML Canvas를 사용하여 아날로그 시계의 페이스(문자판)를 만드는 방법을 알아본다. 이 튜토리얼에서는 원형 테두리, 숫자, 시간 표시 등 시계 페이스의 기본 구성 요소를 그리는 방법을 설명한다.

시계 페이스 기본 구조

시계 페이스는 다음과 같은 구성 요소로 이루어진다.

  • 외곽 원형 테두리
  • 내부 원형 배경
  • 시간 숫자 (1부터 12까지)
  • 시간 표시 점 또는 선
  • 중앙 점

기본 시계 페이스 그리기

가장 기본적인 시계 페이스를 만들어보자.

<canvas id="canvas1" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
drawClock();
function drawClock() {
drawFace(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();
}
</script>

이 코드는 기본적인 시계 페이스를 그린다. translate() 메서드를 사용하여 캔버스의 중심을 원점으로 이동시키고, 그라데이션을 사용하여 입체적인 테두리 효과를 만든다.

숫자가 있는 시계 페이스

시계 페이스에 1부터 12까지의 숫자를 추가해보자.

<canvas id="canvas2" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas2");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(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) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius * 0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } </script>[/code]

drawNumbers() 함수는 1부터 12까지의 숫자를 시계 페이스에 배치한다. 각 숫자는 30도(π/6 라디안)씩 회전하여 원형으로 배치된다.

시간 표시 마크가 있는 시계 페이스

숫자 외에 시간을 나타내는 작은 마크들을 추가해보자.

<canvas id="canvas3" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas3");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
drawClock();
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) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius * 0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } function drawTime(ctx, radius) { var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); hour = hour % 12; hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60)); drawHand(ctx, hour, radius * 0.5, radius * 0.07); minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60)); drawHand(ctx, minute, radius * 0.8, radius * 0.07); second = (second * Math.PI / 30); drawHand(ctx, second, radius * 0.9, radius * 0.02); } function drawHand(ctx, pos, length, width) { ctx.beginPath(); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.moveTo(0, 0); ctx.rotate(pos); ctx.lineTo(0, -length); ctx.stroke(); ctx.rotate(-pos); } </script>[/code]

이 예제에서는 현재 시간에 따라 시침, 분침, 초침을 그리는 기능을 추가했다. drawTime() 함수는 현재 시간을 가져와서 각 바늘의 각도를 계산하고, drawHand() 함수는 실제 바늘을 그린다.

개선된 시계 페이스

더 세련된 시계 페이스를 만들어보자. 시간 마크와 분 마크를 추가한다.

<canvas id="canvas4" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas4");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
setInterval(drawClock, 1000);
function drawClock() {
ctx.clearRect(-radius, -radius, radius * 2, radius * 2);
drawFace(ctx, radius);
drawNumbers(ctx, radius);
drawMarks(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) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius * 0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } function drawMarks(ctx, radius) { var ang; var mark; for (mark = 0; mark < 60; mark++) { ang = mark * Math.PI / 30; ctx.rotate(ang); ctx.translate(0, -radius * 0.93); ctx.rotate(-ang); if (mark % 5 === 0) { ctx.beginPath(); ctx.arc(0, 0, radius * 0.03, 0, 2 * Math.PI); ctx.fillStyle = '#333'; ctx.fill(); } else { ctx.beginPath(); ctx.arc(0, 0, radius * 0.015, 0, 2 * Math.PI); ctx.fillStyle = '#666'; ctx.fill(); } ctx.rotate(ang); ctx.translate(0, radius * 0.93); ctx.rotate(-ang); } } function drawTime(ctx, radius) { var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); hour = hour % 12; hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60)); drawHand(ctx, hour, radius * 0.5, radius * 0.07, '#333'); minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60)); drawHand(ctx, minute, radius * 0.8, radius * 0.07, '#333'); second = (second * Math.PI / 30); drawHand(ctx, second, radius * 0.9, radius * 0.02, 'red'); } function drawHand(ctx, pos, length, width, color) { ctx.beginPath(); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.strokeStyle = color; ctx.moveTo(0, 0); ctx.rotate(pos); ctx.lineTo(0, -length); ctx.stroke(); ctx.rotate(-pos); } </script>[/code]

이 개선된 버전에서는 다음과 같은 기능이 추가되었다.

  • 60개의 분 마크 (5분 간격으로 큰 점, 나머지는 작은 점)
  • setInterval()을 사용한 실시간 업데이트
  • 초침을 빨간색으로 표시
  • clearRect()를 사용한 화면 지우기

사용자 정의 스타일 시계 페이스

다양한 색상과 스타일을 적용한 시계 페이스를 만들어보자.

<canvas id="canvas5" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas5");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
setInterval(drawClock, 1000);
function drawClock() {
ctx.clearRect(-radius, -radius, radius * 2, radius * 2);
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 = '#f0f0f0';
ctx.fill();
grad = ctx.createRadialGradient(0, 0, radius * 0.95, 0, 0, radius * 1.05);
grad.addColorStop(0, '#2c3e50');
grad.addColorStop(0.5, '#34495e');
grad.addColorStop(1, '#2c3e50');
ctx.strokeStyle = grad;
ctx.lineWidth = radius * 0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius * 0.05, 0, 2 * Math.PI);
ctx.fillStyle = '#e74c3c';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#2c3e50";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius * 0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } function drawTime(ctx, radius) { var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); hour = hour % 12; hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60)); drawHand(ctx, hour, radius * 0.5, radius * 0.07, '#2c3e50'); minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60)); drawHand(ctx, minute, radius * 0.8, radius * 0.07, '#34495e'); second = (second * Math.PI / 30); drawHand(ctx, second, radius * 0.9, radius * 0.02, '#e74c3c'); } function drawHand(ctx, pos, length, width, color) { ctx.beginPath(); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.strokeStyle = color; ctx.moveTo(0, 0); ctx.rotate(pos); ctx.lineTo(0, -length); ctx.stroke(); ctx.rotate(-pos); } </script>[/code]

이 예제에서는 현대적인 색상 팔레트를 사용하여 더 세련된 시계 페이스를 만들었다.

💡 시계 페이스 제작 팁:
• 삼각함수를 사용하여 원형 배치를 계산한다. 각도는 라디안 단위로 변환해야 한다
• translate()와 rotate()를 사용하여 좌표계를 조작하면 원형 배치가 쉬워진다
• setInterval()을 사용하여 실시간으로 시계를 업데이트할 수 있다
• 성능을 위해 clearRect()로 이전 그림을 지우고 다시 그리는 것이 좋다

디지털 시계 스타일

아날로그 시계 페이스 위에 디지털 시간 표시를 추가해보자.

<canvas id="canvas6" width="400" height="400" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas6");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
setInterval(drawClock, 1000);
function drawClock() {
ctx.clearRect(-radius, -radius, radius * 2, radius * 2);
drawFace(ctx, radius);
drawNumbers(ctx, radius);
drawTime(ctx, radius);
drawDigitalTime(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) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius * 0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } function drawTime(ctx, radius) { var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); hour = hour % 12; hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60)); drawHand(ctx, hour, radius * 0.5, radius * 0.07, '#333'); minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60)); drawHand(ctx, minute, radius * 0.8, radius * 0.07, '#333'); second = (second * Math.PI / 30); drawHand(ctx, second, radius * 0.9, radius * 0.02, 'red'); } function drawHand(ctx, pos, length, width, color) { ctx.beginPath(); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.strokeStyle = color; ctx.moveTo(0, 0); ctx.rotate(pos); ctx.lineTo(0, -length); ctx.stroke(); ctx.rotate(-pos); } function drawDigitalTime(ctx, radius) { var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); var timeString = (hour < 10 ? "0" : "") + hour + ":" + (minute < 10 ? "0" : "") + minute + ":" + (second < 10 ? "0" : "") + second; ctx.font = radius * 0.1 + "px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "black"; ctx.fillText(timeString, 0, radius * 0.6); } </script>[/code]

이 예제에서는 아날로그 시계 페이스에 디지털 시간 표시를 추가하여 두 가지 형태의 시간 표시를 함께 보여준다.

Canvas를 사용한 시계 페이스 제작은 원형 좌표계, 삼각함수, 그리고 애니메이션의 기본 개념을 익히는 데 매우 유용하다. 이러한 기술들은 다양한 데이터 시각화나 게임 개발에도 응용할 수 있다.

참고
Mingg`s Diary
밍구
공부 목적 블로그