<!DOCTYPE html>
<html>
<head>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
position: relative;
width: 100vw;
height: 100vh;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
min-width: 1000px;
}
.light .clock-frame {
position: relative;
background: #f8f8f8;
border: 5px solid #181818;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.45) inset;
}
.light .graduations {
background: #666;
}
.light .hour-number {
color: #181818;
}
.light .minutes,
.light .hours {
background: #181818;
}
.dark .clock-frame {
position: relative;
background: #181818;
border: 5px solid #181818;
box-shadow: 0 0 15px rgba(255, 255, 255, 0.55) inset;
}
.dark .graduations {
background: #aaa;
}
.dark .hour-number {
color: #f2f2f2;
}
.dark .minutes,
.dark .hours {
background: #eee;
}
.light .clock-frame::before,
.dark .clock-frame::before {
content: "";
width: 20px;
height: 20px;
background: #ccc;
border-radius: 50%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 2px 4px -1px black;
z-index: 10;
}
</style>
</head>
<body>
<script>
const FONT_FAMILY = 'Audiowide'
const FONT_FAMILY_EMBED = `https://fonts.googleapis.com/css2?family=${FONT_FAMILY}&display=swap"`
const createElement = (tagName, properties) => Object.assign(document.createElement(tagName), {...properties})
const initArray = (length, f = (_, i) => i) => Array.from({length: length}, f)
const fontLink = createElement('link', {rel: 'stylesheet', href: FONT_FAMILY_EMBED})
const loop = () => {
const set = new Set
requestAnimationFrame(function run(time) {
set.forEach(f => f(time))
requestAnimationFrame(run)
})
return set
}
class AnalogClock {
themeLight = 'light'
themeDark = 'dark'
clockFrame = null
constructor({size = 600, theme = 'light', fontSize = 50, padding = 0, wrapper} = {}){
Object.assign(this, {size, theme, fontSize, padding, wrapper})
}
get _targetTheme(){
return this.theme === 'light' ? this.themeLight : this.themeDark
}
// 시계 프레임
get _clockFrame(){
return createElement('div', {className: 'clock-frame', style: `
position: relative;
width: ${this.size}px;
height: ${this.size}px;
padding: ${this.padding}px;
box-sizing: border-box;
border-radius: 50%;
`})
}
// 숫자 (시)
get _hourNumbers(){
return initArray(12, (_, i) => {
const currentDeg = (360/12) * (i+1);
const radius = (this.size/2) - this.fontSize - 10
const x = radius * Math.cos(Math.PI * ((currentDeg) - 90) / 180);
const y = radius * Math.sin(Math.PI * ((currentDeg) - 90) / 180);
const hour = createElement('div', {className: `hour-number`, style: `
font-family: ${FONT_FAMILY}, cursive;
font-size: ${this.fontSize}px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) translate(${x}px, ${y}px);
`})
hour.innerText = i+1
return hour
})
}
// 시계 눈금
get _graduations(){
return initArray(60, (_, i) => {
const currentDeg = (360/60) * i;
const height = 12
const radius = (this.size/2) - (height/2) - 5
const x = radius * Math.cos(Math.PI * ((currentDeg) - 90) / 180);
const y = radius * Math.sin(Math.PI * ((currentDeg) - 90) / 180);
const border = i % 5 === 0 ? `width: 6px; height: ${height}px;` : `width: 1px; height: ${height}px;`
const graduations = createElement('div', {className: `graduations`, style: `
${border}
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) translate(${x}px, ${y}px) rotate(${currentDeg}deg);
`})
return graduations
})
}
// 시계 그리기
render(currentTheme = this._targetTheme){
this.clockFrame = this._clockFrame
this._hourNumbers.forEach(el => this.clockFrame.appendChild(el))
this._graduations.forEach(el => this.clockFrame.appendChild(el))
this.wrapper.appendChild(fontLink)
this.wrapper.appendChild(this.clockFrame)
this.wrapper.classList.add(currentTheme)
}
// 시계 작동
start(){
this.render()
const timeBox = createElement('div', {className: 'current-time', style: `
text-align: center;
font-family: ${FONT_FAMILY}, cursive;
font-size: ${this.fontSize}px;
width: 100%;
`})
const secondsHand = createElement('div', {className: 'seconds', style: `
width: 1px;
height: ${(this.size/2) - this.fontSize}px;
position: absolute;
left: 50%;
bottom: 50%;
transform-origin: bottom;
transform: translate(-50%, 0) rotate(0);
background: #FF0000;
`})
const minutesHand = createElement('div', {className: 'minutes', style: `
width: 5px;
height: ${(this.size/2) - this.fontSize - 30}px;
position: absolute;
left: 50%;
bottom: 50%;
transform-origin: bottom;
transform: translate(-50%, 0) rotate(0);
z-index: 1;
`})
const hoursHand = createElement('div', {className: 'hours', style: `
width: 5px;
height: ${(this.size/2) - this.fontSize - 80}px;
position: absolute;
left: 50%;
bottom: 50%;
transform-origin: bottom;
transform: translate(-50%, 0) rotate(0);
z-index: 1;
`})
this.clockFrame.appendChild(secondsHand)
this.clockFrame.appendChild(minutesHand)
this.clockFrame.appendChild(hoursHand)
this.clockFrame.parentNode.appendChild(timeBox)
const set = loop();
set.add(() => {
const now = new Date()
const h = now.getHours()
const m = now.getMinutes()
const s = now.getSeconds()
const ms = now.getMilliseconds()
const currentTime = `${(h < 10) ? '0'+ h : h}:${(m < 10) ? '0'+ m : m}:${(s < 10) ? '0'+ s : s}`
const hDeg = h*30 // (h%12) * (360/12)
const mDeg = m*6 // (m%60) * (360/60)
const sDeg = s*6 // (s%60) * (360/60)
const msDeg = ms*(6/1000)
timeBox.innerText = currentTime
secondsHand.style.transform = `translate(-50%, 0) rotate(${msDeg + sDeg}deg)`
minutesHand.style.transform = `translate(-50%, 0) rotate(${mDeg + (sDeg/360) * (360/60)}deg)`
hoursHand.style.transform = `translate(-50%, 0) rotate(${hDeg + (mDeg/360) * (360/12)}deg)`
})
}
}
const analogClock = new AnalogClock({
size: 500,
theme: 'dark',
fontSize: 36,
wrapper: document.body
})
analogClock.start()
// const now = new Date()
// const h = now.getHours()
// const m = now.getMinutes()
// const s = now.getSeconds()
// const current = `${(h < 10) ? '0'+ h : h}:${(m < 10) ? '0'+ m : m}:${(s < 10) ? '0'+ s : s}`
// timeBox.innerText = current
// const then = new Date(now.getFullYear(),now.getMonth(),now.getDate(),0,0,0)
// const diffInMil = (now.getTime() - then.getTime())
// const hour = (diffInMil/(1000*60*60))
// const min = (hour*60)
// const second = (min*60)
// secondsHand.style.transform = `translate(-50%, 0) rotate(${(second*6) - 180}deg)`
// minutesHand.style.transform = `translate(-50%, 0) rotate(${(min*6) - 180}deg)`
// hoursHand.style.transform = `translate(-50%, 0) rotate(${(hour * 30) + (hour / 2) - 180}deg)`
</script>
</body>
</html>
출처 : https://github.com/JIHYE-P/analog-clock/blob/master/src/main.css
'프론트엔드 개발 놀이터 > Javascript' 카테고리의 다른 글
.clone() - 선택한 요소를 복제하는 메서드 (0) | 2020.07.17 |
---|---|
자바스크립트 {...} [...] 문법 (비구조화 할당/구조분해 할당) (0) | 2020.07.16 |
javascript 아날로그시계 소스 - 분석4 (0) | 2020.07.07 |
javascript 아날로그시계 소스 - 분석3 (0) | 2020.07.07 |
javascript 아날로그시계 소스 - 분석2 (0) | 2020.07.07 |