Public
Edited
May 16, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
year = {
const clockRadius = 200,
margin = 25,
w = (clockRadius + margin) * 2,
h = (clockRadius + margin) * 2,
hourHandLength = (2 * clockRadius) / 3,
minuteHandLength = clockRadius,
secondHandLength = clockRadius - 12,
secondHandBalance = 30,
secondTickStart = clockRadius,
secondTickLength = -10,
hourTickStart = clockRadius,
hourTickLength = -18,
secondLabelRadius = clockRadius + 16,
secondLabelYOffset = 5,
hourLabelRadius = clockRadius - 40,
hourLabelYOffset = 7,
radians = Math.PI / 180;

const seven = d3
.scaleLinear()
.range([90, -270])
.domain([0, 7]);

const sevenrotate = d3
.scaleLinear()
.range([0, 360])
.domain([0, 7]);

const handData = [
{
type: "second",
value: 0,
length: -secondHandLength,
scale: seven,
balance: secondHandBalance
}
];

function drawClock() {
// create all the clock elements
updateData(); //draw them in the correct starting position
const face = svg
.append("g")
.attr("id", "year-face")
.attr("transform", `translate(${[w / 2, h / 2]})`);

// add marks for seconds
face
.selectAll(".second-tick")
.data(d3.range(0, 7))
.enter()
.append("line")
.attr("class", "second-tick")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", secondTickStart)
.attr("y2", secondTickStart + secondTickLength)
.attr("transform", d => `rotate(${sevenrotate(d)})`);

// and labels...
face
.selectAll(".second-label")
.data(d3.range(0, 7))
.enter()
.append("text")
.attr("class", "second-label")
.attr("text-anchor", "middle")
.attr("x", d => secondLabelRadius * Math.sin(seven(d) * radians))
.attr(
"y",
d =>
secondLabelRadius * Math.cos(seven(d) * radians) + secondLabelYOffset
)
.text(d => ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"][d]);

const hands = face.append("g").attr("id", "year-hands-final");

hands
.selectAll("line")
.data(handData)
.enter()
.append("line")
.attr("class", d => d.type + "-hand")
.attr("x1", 0)
.attr("y1", d => d.balance || 0)
.attr("x2", 0)
.attr("y2", d => d.length)
.attr("transform", d => `rotate(${d.scale(d.value)})`);

face
.append("g")
.attr("id", "face-overlay")
.append("circle")
.attr("class", "hands-cover")
.attr("x", 0)
.attr("y", 0)
.attr("r", clockRadius / 20);
}

function moveHands() {
const sel = d3
.select("#year-hands-final")
.selectAll("line")
.data(handData)
.transition();

sel.attr("transform", d => `sevenrotate(${d.scale(d.value)})`);
}

function updateData() {
const t = new Date();
handData[0].value = (t.getDay() + 6) % 7 + (t.getHours() + (t.getMinutes() + (t.getSeconds() + t.getMilliseconds() / 1000 ) / 60) / 60) / 24;
}

const svg = d3
.create("svg")
.attr("viewBox", [0, 0, w, h])
.style("max-width", "500px")
.attr("id", "clock");

drawClock();

// Animation
const interval = setInterval(
() => {
updateData();
moveHands();
},
1000
);
invalidation.then(() => clearInterval(interval));

return svg.node();
}
Insert cell
Math.sin(-180 * radians)
Insert cell
radians = Math.PI / 180
Insert cell
twelve = d3
.scaleLinear()
.range([0, 360])
.domain([0, 12])
Insert cell
sixty = d3
.scaleLinear()
.range([0, 360])
.domain([0, 60])
Insert cell
fancySecondsON = true
Insert cell
w = 300
Insert cell
h = w
Insert cell
d3 = require("d3@6")
Insert cell
t = new Date()
Insert cell
t.getHours()
Insert cell
t.getHours() + (t.getMinutes() + (t.getSeconds() + t.getMilliseconds() / 1000 ) / 60) / 60
Insert cell
t.getDay()
Insert cell
(t.getDay() + 6) % 7
Insert cell
d3.range(0, 7).map(d => (d + 6) % 7)
Insert cell
style = html`<style>

#clock {
stroke: #000;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}

#clock #rim {
fill: none;
stroke: #999;
stroke-width: 3px;
}

#clock .second-hand {
stroke-width:3;
}

#clock .minute-hand {
stroke-width:8;
stroke-linecap:round;
}

#clock .hour-hand {
stroke-width:12;
stroke-linecap:round;
}

#clock .hands-cover {
stroke-width:3;
fill:#fff;
}

#clock .second-tick {
stroke-width:3;
fill:#000;
}

#clock .hour-tick {
stroke-width:8; // same as the minute hand
}

#clock .second-label {
font-size: 12px;
}

#clock .hour-label {
font-size: 24px;
}


</style>`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more