
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() 메서드를 사용하여 캔버스의 중심을 원점으로 이동시켰다.
숫자 배치 기본 원리
시계 숫자를 원형으로 배치하기 위해서는 다음과 같은 수학적 원리를 이해해야 한다.
- 시계는 360도를 12등분하므로 각 숫자 사이의 각도는 30도(π/6 라디안)이다
- 숫자 1은 90도(π/2 라디안) 위치에서 시작한다
- rotate()와 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() 함수는 다음과 같이 작동한다.
- 각 숫자에 대해 30도씩 회전한다 (ang = num * Math.PI / 6)
- 회전된 좌표계에서 위쪽으로 이동한다 (translate(0, -radius * 0.85))
- 텍스트가 똑바로 보이도록 다시 회전한다 (rotate(-ang))
- 숫자를 그린다
- 원래 상태로 되돌린다
다양한 폰트 스타일 적용
숫자에 다양한 폰트 스타일을 적용해보자.
<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);
}
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 = "bold " + radius * 0.15 + "px Times New Roman";
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); } } </script>[/code]
이 예제에서는 굵은 Times New Roman 폰트를 사용하고 색상을 진한 파란색으로 변경했다.
로마 숫자 사용
로마 숫자를 사용한 클래식한 시계 페이스를 만들어보자.
<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;
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 = '#f8f9fa';
ctx.fill();
grad = ctx.createRadialGradient(0, 0, radius * 0.95, 0, 0, radius * 1.05);
grad.addColorStop(0, '#8b4513');
grad.addColorStop(0.5, '#daa520');
grad.addColorStop(1, '#8b4513');
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 = '#8b4513';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
var romanNumerals = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"];
ctx.font = "bold " + radius * 0.15 + "px serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#8b4513";
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(romanNumerals[num], 0, 0); ctx.rotate(ang); ctx.translate(0, radius * 0.85); ctx.rotate(-ang); } } </script>[/code]
이 예제에서는 로마 숫자 배열을 사용하여 클래식한 시계 페이스를 만들었다. 색상도 골드와 브라운 톤으로 변경하여 고급스러운 느낌을 연출했다.
숫자 위치 조정
숫자의 위치를 더 정밀하게 조정해보자.
<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;
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";
ctx.fillStyle = "black";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; ctx.rotate(ang); var distance = radius * 0.85; if (num === 12 || num === 6) { distance = radius * 0.82; } ctx.translate(0, -distance); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, distance); ctx.rotate(-ang); } } </script>[/code]
이 예제에서는 12시와 6시 위치의 숫자를 약간 안쪽으로 이동시켜 더 균형잡힌 배치를 만들었다.
그림자 효과가 있는 숫자
숫자에 그림자 효과를 추가하여 입체감을 만들어보자.
<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;
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 = "bold " + radius * 0.15 + "px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.shadowColor = "rgba(0,0,0,0.3)";
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 3;
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); } ctx.shadowColor = "transparent"; } </script>[/code]
이 예제에서는 shadowColor, shadowOffsetX, shadowOffsetY, shadowBlur 속성을 사용하여 숫자에 그림자 효과를 추가했다.
다양한 크기의 숫자
중요한 시간(12, 3, 6, 9시)을 더 크게 표시해보자.
<canvas id="canvas7" width="400" height="400" style="border:1px solid #d3d3d3;">브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas7");
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.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
for (num = 1; num < 13; num++) { ang = num * Math.PI / 6; if (num % 3 === 0) { ctx.font = "bold " + radius * 0.18 + "px Arial"; ctx.fillStyle = "#e74c3c"; } else { ctx.font = radius * 0.15 + "px Arial"; ctx.fillStyle = "black"; } 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]
이 예제에서는 3의 배수인 숫자(3, 6, 9, 12)를 더 크게 표시하고 빨간색으로 강조했다.
💡 시계 숫자 배치 팁:
• 각도 계산 시 라디안 단위를 사용한다 (도 × π / 180)
• textAlign과 textBaseline을 "center"와 "middle"로 설정하면 정확한 중앙 배치가 가능하다
• rotate()와 translate()를 사용한 후에는 반드시 원래 상태로 되돌려야 한다
• 폰트 크기는 반지름에 비례하여 설정하면 다양한 크기의 시계에 적용할 수 있다
애니메이션 효과가 있는 숫자
숫자가 나타나는 애니메이션 효과를 추가해보자.
<canvas id="canvas8" width="400" height="400" style="border:1px solid #d3d3d3;">브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var canvas = document.getElementById("canvas8");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
var currentNumber = 0;
var animationId = setInterval(function() {
if (currentNumber < 12) { currentNumber++; drawClock(); } else { clearInterval(animationId); } }, 200); function drawClock() { ctx.clearRect(-radius * 1.1, -radius * 1.1, radius * 2.2, radius * 2.2); 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"; ctx.fillStyle = "black"; for (num = 1; num <= currentNumber; 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]
이 예제에서는 숫자가 1부터 12까지 순서대로 나타나는 애니메이션 효과를 구현했다. setInterval()을 사용하여 200밀리초마다 다음 숫자를 표시한다.
Canvas를 사용한 시계 숫자 배치는 원형 좌표계와 삼각함수의 실용적인 활용 예시이다. 이러한 기법들은 원형 메뉴, 차트, 게임 인터페이스 등 다양한 웹 애플리케이션에서 응용할 수 있다.