Analog Clock
Experience a smooth, animated analog clock built with LemonadeJS that updates in real-time. Watch as the hour, minute, and second hands move fluidly across the clock face with mathematical precision.
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<div id='root'></div>
<script>
function Clock() {
const self = this;
const updateClock = () => {
const now = new Date();
self.second = now.getSeconds() * 6;
self.minute = now.getMinutes() * 6 + now.getSeconds() * 0.1;
self.hour = now.getHours() * 30 + now.getMinutes() * 0.5;
}
let marks = [];
for (let i = 0; i < 12; i++) {
marks.push({ index: i*30 });
}
self.marks = marks;
updateClock();
setInterval(updateClock, 1000);
return `<div class="clock">
<div class="face">
<div class="marks" :loop="self.marks">
<div class="mark" style="transform: rotate({{self.index}}deg)"></div>
</div>
<div class="hand hour" style="transform: rotate({{self.hour}}deg)"></div>
<div class="hand minute" style="transform: rotate({{self.minute}}deg)"></div>
<div class="hand second" style="transform: rotate({{self.second}}deg)"></div>
</div>
</div>`;
}
lemonade.render(Clock, document.getElementById('root'));
</script>
<style>
.clock {
width: 300px;
height: 300px;
margin: 40px auto;
}
.face {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
border: 4px solid #0891b2;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
}
.face::after {
content: '';
position: absolute;
width: 12px;
height: 12px;
background: #0891b2;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
.marks {
position: relative;
width: 100%;
height: 100%;
}
.mark {
position: absolute;
width: 100%;
height: 100%;
}
.mark::after {
content: '';
position: absolute;
width: 3px;
height: 15px;
background: #6b7280;
left: 50%;
transform: translateX(-50%);
border-radius: 2px;
}
.hand {
position: absolute;
bottom: 50%;
left: 50%;
transform-origin: bottom;
border-radius: 10px;
}
.hour {
width: 6px;
height: 25%;
background: #111827;
margin-left: -3px;
}
.minute {
width: 4px;
height: 35%;
background: #374151;
margin-left: -2px;
}
.second {
width: 2px;
height: 40%;
background: #0891b2;
margin-left: -1px;
}
</style>
</html>
import lemonade from 'lemonadejs';
export default function Clock() {
const self = this;
const updateClock = () => {
const now = new Date();
self.second = now.getSeconds() * 6;
self.minute = now.getMinutes() * 6 + now.getSeconds() * 0.1;
self.hour = now.getHours() * 30 + now.getMinutes() * 0.5;
}
let marks = [];
for (let i = 0; i < 12; i++) {
marks.push({ index: i*30 });
}
self.marks = marks;
updateClock();
setInterval(updateClock, 1000);
return `<div class="clock">
<div class="face">
<div class="marks" :loop="self.marks">
<div class="mark" style="transform: rotate({{self.index}}deg)"></div>
</div>
<div class="hand hour" style="transform: rotate({{self.hour}}deg)"></div>
<div class="hand minute" style="transform: rotate({{self.minute}}deg)"></div>
<div class="hand second" style="transform: rotate({{self.second}}deg)"></div>
</div>
</div>`;
}
import React, { useState, useEffect } from 'react';
import './Clock.css';
export default function Clock() {
const [time, setTime] = useState({
second: 0,
minute: 0,
hour: 0
});
const marks = Array.from({ length: 12 }, (_, i) => i * 30);
useEffect(() => {
const updateClock = () => {
const now = new Date();
setTime({
second: now.getSeconds() * 6,
minute: now.getMinutes() * 6 + now.getSeconds() * 0.1,
hour: now.getHours() * 30 + now.getMinutes() * 0.5
});
};
updateClock();
const interval = setInterval(updateClock, 1000);
return () => clearInterval(interval);
}, []);
return (
<div className="clock">
<div className="face">
<div className="marks">
{marks.map((rotation, index) => (
<div key={index} className="mark" style={{ transform: `rotate(${rotation}deg)` }}></div>
))}
</div>
<div className="hand hour" style={{ transform: `rotate(${time.hour}deg)` }}></div>
<div className="hand minute" style={{ transform: `rotate(${time.minute}deg)` }}></div>
<div className="hand second" style={{ transform: `rotate(${time.second}deg)` }}></div>
</div>
</div>
);
}
<template>
<div class="clock">
<div class="face">
<div class="marks">
<div v-for="(rotation, index) in marks" :key="index"
class="mark" :style="{ transform: `rotate(${rotation}deg)` }"></div>
</div>
<div class="hand hour" :style="{ transform: `rotate(${time.hour}deg)` }"></div>
<div class="hand minute" :style="{ transform: `rotate(${time.minute}deg)` }"></div>
<div class="hand second" :style="{ transform: `rotate(${time.second}deg)` }"></div>
</div>
</div>
</template>
<script>
export default {
name: 'Clock',
data() {
return {
time: {
second: 0,
minute: 0,
hour: 0
},
marks: Array.from({ length: 12 }, (_, i) => i * 30),
interval: null
}
},
mounted() {
this.updateClock();
this.interval = setInterval(this.updateClock, 1000);
},
beforeUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
},
methods: {
updateClock() {
const now = new Date();
this.time = {
second: now.getSeconds() * 6,
minute: now.getMinutes() * 6 + now.getSeconds() * 0.1,
hour: now.getHours() * 30 + now.getMinutes() * 0.5
};
}
}
}
</script>
<style scoped>
.clock {
width: 300px;
height: 300px;
margin: 40px auto;
}
.face {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
border: 4px solid #0891b2;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
}
.face::after {
content: '';
position: absolute;
width: 12px;
height: 12px;
background: #0891b2;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
.marks {
position: relative;
width: 100%;
height: 100%;
}
.mark {
position: absolute;
width: 100%;
height: 100%;
}
.mark::after {
content: '';
position: absolute;
width: 3px;
height: 15px;
background: #6b7280;
left: 50%;
transform: translateX(-50%);
border-radius: 2px;
}
.hand {
position: absolute;
bottom: 50%;
left: 50%;
transform-origin: bottom;
border-radius: 10px;
}
.hour {
width: 6px;
height: 25%;
background: #111827;
margin-left: -3px;
}
.minute {
width: 4px;
height: 35%;
background: #374151;
margin-left: -2px;
}
.second {
width: 2px;
height: 40%;
background: #0891b2;
margin-left: -1px;
}
</style>