Published
Edited
Sep 10, 2020
2 forks
95 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
// 01:15 expressed in hours
const hours = 1.25;

// Create SVG that can fit a clock with the configured radius
const size = 2 * settings.radius;
const svgNode = DOM.svg(size, size);

// Add the clock and set the time
d3.select(svgNode)
.call(addClock)
.datum(hours)
.call(updateClock);

return svgNode;
}
Insert cell
Insert cell
Insert cell
{
const clocks = Object.values(hoursByOrientation);

// Create SVG that can fit all the clocks
const size = 2 * settings.radius;
const svgNode = DOM.svg(clocks.length * size, size);

// Add the clocks and set their times
d3.select(svgNode)
.selectAll("g")
.data(clocks)
.join("g")
.style("transform", (d, i) => `translate(${i * size}px, 0px)`)
.call(addClock)
.call(updateClock);

return svgNode;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
// Prepare SVG with width 1/5 of the viewport
const svgNode = svg`<svg width="${width / 5}"/>`;
// Draw the sprite for the digit "9"
updateSvg(svgNode, spriteGrids[9]);

return svgNode;
}
Insert cell
Insert cell
{
// Create SVG that can fit a single clock as before and yield it
const size = 2 * settings.radius;
const svgNode = DOM.svg(5 * size, size);
yield svgNode;

// Add a clock
d3.select(svgNode).call(addClock);

const counter = d3
.select(svgNode)
.append("text")
.style("font-size", `${settings.radius / 2}px`)
.style("transform", "translate(72px, 36px)");

// Set hours to transition between (01:15 => 10:30)
const hoursFrom = 1.25;
const hoursTo = 10.5;

const interval = 4000;
const delayBeforeRestart = 1000;

// Update the SVG 60 times per second
const framesPerSecond = 60;

// Start an "infinite" loop that is stopped when the cell is re-evaluated
let running = true;
invalidation.then(() => (running = false));

while (running) {
const intervalWithDelay = interval + delayBeforeRestart;
let normalizedTime = (new Date().getTime() % intervalWithDelay) / interval;
normalizedTime = Math.min(1, normalizedTime);
const hours = interpolateHours(hoursFrom, hoursTo, normalizedTime);
counter.text(`Normalized time: ${normalizedTime.toFixed(2)}`);

// Add the clocks and set their times
d3.select(svgNode)
.datum(hours)
.call(updateClock);

// Wait until it is time for the next frame
await Promises.tick(1000 / framesPerSecond);
}
}
Insert cell
Insert cell
{
// Prepare SVG with width 1/5 of the viewport
const svgNode = svg`<svg width="${width / 5}"/>`;
yield svgNode;

// Change to the next digit every 4000 milliseconds
const interval = 4000;

// Update the SVG 60 times per second
const framesPerSecond = 60;

// Start an "infinite" loop that is stopped when the cell is re-evaluated
let running = true;
invalidation.then(() => (running = false));

while (running) {
// Calculate current and next digit and normalized time
const time = new Date().getTime();
const digit = Math.floor(time / interval) % 10;
const nextDigit = (digit + 1) % 10;
const normalizedTime = (time % interval) / interval;

// Update with interpolation between current and next digit
updateSvg(
svgNode,
interpolateGrid(
spriteGrids[digit],
spriteGrids[nextDigit],
normalizedTime
)
);

// Wait until it is time for the next frame
await Promises.tick(1000 / framesPerSecond);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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