[D3.js] 아날로그 시계 만들기
[D3.js] 아날로그 시계 만들기
오늘은 실험 할 내용이 없는지 알아보기 위해서 D3.js 튜토리얼을 구경하다가 우연히 아날로그 시계를 튜토리얼로 만든 post가 있더군요. 대충 이미지와 arc()함수를 사용한 것만 보고 아날로그 시계를 직접 만든 다면 어떻게 코딩 할까 상상하면서 arc()함수를 사용하여 만들어 보는 실험을 하였습니다. 그러면 어떻게 만들었는지 알아봅시다.
1. 아날로그 시계 초 동작
아날로그 시계를 만든다면 최소 필요한 것들이 뭐가 있을까요. 시,분,초 이렇게 3개의 바늘이 필요 하겠죠. 여기서, 초 바늘 이미지만 어떻게 움직이게 하면 시, 분은 유사 동작이니 얼추 시계를 표현 할 수 있을거라 생각합니다.
그러면, 초를 움직여 봅시다.
1) arc() 함수로 초 이미지 만들기
d3.arc()
.innerRadius(안쪽반경)
.outerRadius(바깥쪽반경)
.startAngle(시작각)
.endAngle(끝각);
대충 이런식으로 구성 되어 있습니다.
출력을 할때는
svg.append("path")
.attr("class", "arc")
.attr("d", sec)
path태그에서 d로 d3.arc()값을 전달 해주면 됩니다. 실제 결과를 시험해 보죠.
[소스]
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 200)
.append("g")
.attr("transform", "translate(100,100)"); //그릴 위치
var sec = d3.arc()
.innerRadius(0)
.outerRadius(100)
.startAngle(0)
.endAngle(3.14);
svg.append("path")
.attr("class", "arc")
.attr("d", sec)
.attr("fill","blue")
</script>
</body>
[결과]
![](https://steemitimages.com/640x0/https://i.imgur.com/5JqqWJo.jpg)
2) 초 바늘 그리기
var sec = d3.arc()
.innerRadius(0)
.outerRadius(100)
.startAngle(0)
.endAngle(0.02);
길이가 100정도 되는데 폭각이 0.02가 됩니다.
![](https://steemitimages.com/640x0/https://i.imgur.com/01V4x2H.jpg)
위 그림처럼 그려 집니다.
3) 초 바늘 움직이게 하기
arc()함수에서 움직이는 초 이미지는 다음 값들 입니다.
var sec = d3.arc()
.innerRadius(0)
.outerRadius(100)
.startAngle(d_sec)
.endAngle(d_sec+0.02);
바로, startAngle과 endAngle의 값입니다. d_sec라는 값이 바뀌면 초 이미지의 위치가 움직이게 됩니다.
1초 움직이기 위해서는 원의 전체의 길이를 알아야 합니다. 반원이 3.14이고 전체의 원은 6.28가 되겠죠. 1초의 움직임은 6.28을 1/60로 나눈 값으로 하면 됩니다.
var sec_val = 3.14*2/60;
1초 단위로 이미지가 움직이게 하려면 실시간 데이터 갱신함수 setInterval() 함수를 이용하면 됩니다.
var time_sec=0;
var sec_val = 3.14*2/60;
function update(){
time_sec=sec_val+time_sec;
if(time_sec>=3.14*2){
time_sec=0;
}
render(time_sec); //초이미지 그리기 부분을 render()함수로 묶음
}
setInterval(update, 1000);
위 코딩을 보면 1초 단위로 update가 호출이 됩니다. 그럴 때 update() 동작은 1초의 움직이는 각도를 만들어 주면 되겠죠.
time_sec=sec_val+time_sec;
if(time_sec>=3.14*2){ //60초가 되면 0으로 리셋
time_sec=0;
}
[소스]
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var time_sec=0;
var sec_val = 3.14*2/60;
var svg = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 200)
.append("g")
.attr("transform", "translate(100,100)");
function render(d_sec){
d3.selectAll(".arc").remove(); //이전 이미지 지우기
var sec = d3.arc()
.innerRadius(0)
.outerRadius(100)
.startAngle(d_sec)
.endAngle(d_sec+0.02);
svg.append("path")
.attr("class", "arc")
.attr("d", sec)
.attr("fill","blue")
}
function update(){
time_sec=sec_val+time_sec;
if(time_sec>=3.14*2){
time_sec=0;
}
render(time_sec);
}
setInterval(update, 1000);
</script>
</body>
위 코딩에서 remove()함수로 이전 이미지를 지워야 합니다. 그래서 아래 코딩을 추가 코딩 했네요.
d3.selectAll(".arc").remove(); //이전 이미지 지우기
[결과]
한바퀴 돌면 1분이 걸리는 몇초만 움직이는 장면을 찍었습니다.
![](https://steemitimages.com/0x0/https://i.imgur.com/PT5kPuB.gif)
2. 아날로그 시계 시/분/초 동작
위에서 초를 움직이게 했었습니다. 그 원리를 이용하여 시/분/초를 움직이게 하려면 어떻게 해야 할까요.
실제 시계의 움직임을 알아야 합니다.
1초 = 60초
1분 = 60분
1시간 = 12시간
위 조건에서 60초 후면 1분이 움직이고 60분 후면 1시간이 움직이게 하면 됩니다.
1초 움직이는 곳에서 1분과 1시간이 움직이게 코딩을 하면 됩니다.
function update(){
time_sec=sec_val+time_sec; //1초증가
if(time_sec>=3.14*2){ //60초인가?
time_sec=0;
time_min=min_val+time_min; //1분증가
if(time_min>=3.14*2){ //60분인가?
time_min=0;
time_hour=hour_val+time_hour; //1시간증가
if(time_hour>=3.14*2){ //12시간인가?
time_hour=0
}
}
}
render(time_sec,time_min,time_hour);
}
setInterval(update, 1);
위 코딩처럼 대충 간단히 코딩해 봤네요. 주석을 달아 놓았으니깐 보시면 됩니다. 아두이노 코딩을 할 때 7-Segment Display로 시계값을 출력할 때 실험했던 원리의 코딩을 여기서 써먹네요.
render()함수에서 시/분/초 값을 넘겨줘서 초이미지, 분이미지, 시간이미지를 새롭게 만들어서 각각 이미지를 1초 단위로 그려주면 됩니다.
[종합소스]
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var time_sec=0;
var time_min=0;
var time_hour=0;
var sec_val = 3.14*2/60;
var min_val = 3.14*2/60;
var hour_val = 3.14*2/12;
var svg = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 200)
.append("g")
.attr("transform", "translate(100,100)");
var circle = svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 100)
.attr("fill","yellow")
function render(d_sec,d_min,d_hour){
d3.selectAll(".arc").remove(); //이전 시/분/초이미지들 모두 지우기
var sec = d3.arc() //초이미지
.innerRadius(0)
.outerRadius(100)
.startAngle(d_sec)
.endAngle(d_sec+0.02);
var min = d3.arc() //분이미지
.innerRadius(0)
.outerRadius(70)
.startAngle(d_min)
.endAngle(d_min+0.10);
var hour = d3.arc() //시간이미지
.innerRadius(0)
.outerRadius(50)
.startAngle(d_hour)
.endAngle(d_hour+0.15);
svg.append("path") //초이미지출력
.attr("class", "arc")
.attr("d", sec)
.attr("fill","blue")
svg.append("path") //분이미지출력
.attr("class", "arc")
.attr("d", min)
.attr("fill","red")
svg.append("path") //시간이미지출력
.attr("class", "arc")
.attr("d", hour)
.attr("fill","green")
}
function update(){
time_sec=sec_val+time_sec; //1초증가
if(time_sec>=3.14*2){ //60초인가?
time_sec=0;
time_min=min_val+time_min; //1분증가
if(time_min>=3.14*2){ //60분인가?
time_min=0;
time_hour=hour_val+time_hour; //1시간증가
if(time_hour>=3.14*2){ //12시간인가?
time_hour=0
}
}
}
render(time_sec,time_min,time_hour);
}
setInterval(update, 1000);
</script>
</body>
위 코딩은 시계 모양으로 circle(원) 배경을 만들었고 그위에 시/분/초를 개별적으로 출력 시킨 코딩입니다.
[결과]
시간까지 움직이는 걸 보려면 너무 오래 걸려서 갱신 간격을 아래와 같이 줄였네요.
setInterval(update, 1);
![](https://steemitimages.com/0x0/https://i.imgur.com/LPwe844.gif)
마무리
오늘은 저도 아날로그 시계를 직접 코딩해 봤네요. 튜토리얼에서 유연히 본 아날로그 이미지와 핵심 arc()함수를 사용한 것만 보고 제가 직접 arc() 함수를 이용해서 제 나름대로 상상해서 직접 코딩을 해보았습니다. 어떻게 하면 이미지를 만들까? 어떻게 하면 움직이게 할까? 어떻게 하면 시/분/초를 같이 움직이게 할까?로 하나씩 코딩해 봤네요.
아쉬운점은 깔끔하게 코딩이 되지 못했네요. 생각나는데로 길게 코딩을 늘어놓고 코딩을 하다 보니 불필요한 중복 부분과 대충 일괄적으로 외부 변수로 뺀 점과 시간 눈금을 안만든 점과 코딩이 약간 부자연스러움 등이 남아 있어서 불완전한 코딩입니다.
순간 코딩을하고 post를 작성하다 보니깐 다듬는 시간이 부족한 한계인 것 같네요.
![](https://steemitimages.com/640x0/https://i.imgur.com/tWr3JBD.jpg)
Sponsored ( Powered by dclick )
오묘한 조화, 추어탕과 순대!
메인 사진은 순대이지만, 사실 오늘 소개할 음식은 추어탕입니다ㅎㅎ 최근 과도한 업무때문에 연일...
![logo](https://steemitimages.com/200x100/https://cdn.steemitimages.com/DQmbjkrc5UT4GgZXygAnS3mLrboAy7Y8gr7R7guB8HG3f5n/logopad500.png)
이 글은 스팀 기반 광고 플랫폼
dclick 에 의해 작성 되었습니다.
전 텍스트로 그림을 움직이게 하는게 신기 할뿐 입니다.
늘 움직이는 건 프로그램을 써 그림을 움직이게 하는게 다라서....
신기 방기^^
댓글이미지용으로 좋을 듯 싶네요. ^^
^^ 보클하고 갑니다~
오늘은 제대로 카운트 되길 기원합니다. (오묘한 조화~ 누릅니다)
오늘은 확인 할 방법이 없네요. ^^
여러명이 해줬네요.
해줄만한분 숫자와 클릭 횟수에는 아직 차이가 있긴하지만요. ^^
가장 정확한 클릭은 아마 자신 디클릭 로그인 상태를 확인하고 클릭하면 백프로 인 것 같아요.