Built with blockbuilder.org
forked from lbrucel's block: concentric clock d3.js
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body {
margin: 0;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgb(92, 94, 96);
}
</style>
</head>
<body>
<script>
let margin = { top: 0, right: 0, bottom: 0, left: 0 }
let width = window.innerWidth - margin.left - margin.right
let height = window.innerHeight - margin.top - margin.bottom
const fields = [
{
value: 12,
size: 12,
label: ':',
update: function(date) {
return addZeroBefore(date.getHours() % 12)
},
},
{
value: 60,
size: 60,
label: ':',
update: function(date) {
return addZeroBefore(date.getMinutes())
},
},
{
value: 60,
size: 60,
label: '',
update: function(date) {
return addZeroBefore(date.getSeconds())
},
},
]
//add the time in text
function addZeroBefore(time) {
return (time < 10 ? '0' : '') + time
}
//given minutes or seconds and radius, return X,Y
xyFromBase60 = function(baseTime, radius) {
let radians = (baseTime * 360) / 60
radians = (radians * Math.PI) / 180
radians = radians - Math.PI / 2
return [Math.cos(radians) * radius, Math.sin(radians) * radius]
}
xyFromBase12 = function(baseTime, radius) {
let radians = (baseTime * 360) / 12
radians = (radians * Math.PI) / 180
radians = radians - Math.PI / 2
return [Math.cos(radians) * radius, Math.sin(radians) * radius]
}
let svg = d3
.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
// faceRadius is 95% of smaller(width, height)
let outterRadius = (Math.min(width,height) / 2) * 0.95
const hourLineWidth = 10,
minuteLineWidth = 6,
secondLineWidth = 2
const faceR = outterRadius
const hourR = faceR * 0.75
const minR = faceR * 0.5
const secR = faceR * 0.25
let date = new Date()
let hours = date.getHours() % 12
let minutes = date.getMinutes()
let seconds = date.getSeconds()
//clock face is the maximum circle in the viewport, centered
let faceCenter = [width / 2, height / 2]
let clockFaceCircle = svg
.append('circle')
.style('fill', 'lightgray')
.attr('cx', faceCenter[0])
.attr('cy', faceCenter[1])
.attr('r', faceR)
const cx = width / 2
const cy = height / 2
//hour circle
let hRadius = faceR - hourR
let hCenter = xyFromBase12(hours, hRadius)
hCenter[0] += faceCenter[0]
hCenter[1] += faceCenter[1]
let cHours = svg
.append('circle')
.style('fill', 'none')
.style('stroke', 'black')
.style('stroke-width', hourLineWidth)
.attr('cx', hCenter[0])
.attr('cy', hCenter[1])
.attr('r', hourR)
let hourDot = svg
.append('circle')
.style('fill', 'black')
.style('stroke', 'black')
.style('stroke-width', hourLineWidth)
.attr('cx', hCenter[0])
.attr('cy', hCenter[1])
.attr('r', hourLineWidth)
//minute circle
let mRadius = hourR - minR
let mCenter = xyFromBase60(minutes, mRadius)
mCenter[0] += hCenter[0]
mCenter[1] += hCenter[1]
let cMinutes = svg
.append('circle')
.style('fill', 'none')
.style('stroke', 'black')
.style('stroke-width', minuteLineWidth)
.attr('cx', mCenter[0])
.attr('cy', mCenter[1])
.attr('r', minR)
let minuteDot = svg
.append('circle')
.style('fill', 'black')
.style('stroke', 'black')
.style('stroke-width', minuteLineWidth)
.attr('cx', hCenter[0])
.attr('cy', hCenter[1])
.attr('r', minuteLineWidth)
//seconds circle
let sRadius = minR - secR
sCenter = xyFromBase60(seconds, sRadius)
sCenter[0] += mCenter[0]
sCenter[1] += mCenter[1]
let cSeconds = svg
.append('circle')
.style('fill', 'none')
.style('stroke', 'black')
.style('stroke-width', secondLineWidth)
.attr('cx', sCenter[0])
.attr('cy', sCenter[1])
.attr('r', secR)
let secondDot = svg
.append('circle')
.style('fill', 'black')
.style('stroke', 'black')
.style('stroke-width', secondLineWidth)
.attr('cx', mCenter[0])
.attr('cy', mCenter[1])
.attr('r', 2)
let field = svg
.selectAll('.field')
.data(fields)
.enter()
.append('g')
.attr('transform', function(d, i) {
return 'translate(' + (i * 30 + 20) + ',' + 0 + ')'
})
.attr('class', 'field')
let label = field
.append('text')
.attr('x', 5)
.attr('y', height - 20)
.attr('font-size', '20px')
.attr('font-family', 'sans-serif')
.style('fill', 'rgb(92, 94, 96)')
.attr('class', 'label')
;(function updateTime() {
let now = new Date()
field.each(function(d) {
;(d.previous = d.value), (d.value = d.update(now))
})
label.text(function(d) {
return d.value + d.label
})
label
.transition(d3.easeLinear)
.style('fill', 'white')
.duration(10000)
hours = now.getHours() % 12
minutes = now.getMinutes()
seconds = now.getSeconds()
hCenter = xyFromBase12(hours, hRadius)
hCenter[0] += faceCenter[0]
hCenter[1] += faceCenter[1]
cHours
.transition(d3.easeLinear)
.duration(100)
.attr('cx', hCenter[0])
.attr('cy', hCenter[1])
hourDot
.transition(d3.easeLinear)
.duration(1000)
.attr('cx', hCenter[0])
.attr('cy', hCenter[1])
mCenter = xyFromBase60(minutes, mRadius)
mCenter[0] += hCenter[0]
mCenter[1] += hCenter[1]
cMinutes
.transition(d3.easeLinear)
.duration(100)
.attr('cx', mCenter[0])
.attr('cy', mCenter[1])
minuteDot
.transition(d3.easeLinear)
.duration(1000)
.attr('cx', mCenter[0])
.attr('cy', mCenter[1])
sCenter = xyFromBase60(seconds, sRadius)
sCenter[0] += mCenter[0]
sCenter[1] += mCenter[1]
cSeconds
.transition(d3.easeLinear)
.duration(1000)
.attr('cx', sCenter[0])
.attr('cy', sCenter[1])
secondDot
.transition(d3.easeLinear)
.duration(1000)
.attr('cx', sCenter[0])
.attr('cy', sCenter[1])
setTimeout(updateTime, 1000 - (now % 1000))
})()
</script>
</body>
https://d3js.org/d3.v4.min.js