Public
Edited
Apr 23, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const data = mkData();

var secondsOffset = 1;
while (true) {
secondsOffset += speed;
secondsOffset %= 100000;
const data = mkData(secondsOffset);
yield draw(data);

if (!animationToggle) break;
}

return draw(data);

function draw(data) {
return Plot.plot({
grid: true,
width: 600,
height: 600,
x: { nice: true },
y: { nice: true },
r: {
range: [2, 20],
transform: (x) => x ** 2
},
color: { legend: true, scheme: "blues" },
marks: [
// Cycles
Plot.dot(data, {
x: "x",
y: "y",
r: (d) => calenderLength - d.i,
fill: "date"
}),

// Texts
Plot.text(data, {
x: "x",
y: "y",
text: (d) =>
d.date === 1 ? d.date + "," + monthName[d.month] : d.date,
fill: (d) => (d.date < 15 ? "black" : "white")
}),

// Cycle
Plot.dot(data.slice(0, 1), {
x: (d) => -d.x / 2,
y: (d) => -d.y / 2,
r: 40,
fill: "date"
}),

// Text
Plot.text(data.slice(0, 1), {
x: (d) => -d.x / 2,
y: (d) => -d.y / 2,
fontSize: 15,
text: (d) => {
return (
getTimeString(d.obj) + "\n" + d.date + "," + monthName[d.month]
);
},
fill: (d) => (d.date < 15 ? "black" : "white")
})
]
});
}
}
Insert cell
getTimeString = (date) => {
const s2 = (d) => (d > 9 ? "" + d : "0" + d);
return `${s2(date.getHours())}:${s2(date.getMinutes())}:${s2(
date.getSeconds()
)}`;
}
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
data = mkData()
Insert cell
mkData = (offsetSeconds = 0) => {
const radiusRange = [30, 200],
circles = 5,
curveLength = d3.sum(radiusRange) * Math.PI * circles,
length = calenderLength, // days
scaleRadius = d3
.scalePow()
.exponent(0.5)
.domain([0, length])
.range(radiusRange),
__ = 0;

var lst = [],
startDate,
date,
theta,
_ = 1;

startDate = new Date();
startDate = new Date(
startDate.getTime() +
dateOffsets.oneSecond * offsetSeconds +
dateOffsets.oneHour * hoursOffset +
dateOffsets.oneDay * daysOffset
);

theta = d3
.scaleLinear()
.domain([24 * 60, 0])
.range([0, Math.PI * 2])(
startDate.getHours() * 60 + startDate.getMinutes()
);

for (let i = 0; i < length; ++i) {
date = new Date(startDate.getTime() + dateOffsets.oneDay * i);
lst.push({
i,
obj: date,
date: date.getDate(),
hour: date.getHours(),
day: date.getDay(),
month: date.getMonth(),
year: date.getFullYear(),
r: scaleRadius(i),
theta: theta
});

theta += curveLength / length / scaleRadius(i);
}

lst.map((d) => {
const { r, theta } = d,
x = r * Math.cos(theta),
y = r * Math.sin(theta);

Object.assign(d, { x, y });
});

return lst;
}
Insert cell
monthName= ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
Insert cell
dateOffsets = {
return {
oneDay: new Date(0).setUTCHours(24),
oneHour: new Date(0).setMinutes(60),
oneSecond: new Date(0).setMinutes(1)
};
}
Insert cell
Plot.plot({
grid: true,
height: width / 2,
y: {
domain: [0, 1, 2, 3, 4, 5, 6]
},
color: {
legend: true
},
marks: [
Plot.dot(mainDays, { x: "year", y: "day", fill: "type" }),
Plot.ruleX([2023])
]
})
Insert cell
mainDays = {
var days = [],
date;

for (let i = 0; i < 100; ++i) {
date = new Date();
date.setFullYear(i + 2000);
date.setMonth(4);
date.setDate(1);
days.push({
date: date,
year: date.getFullYear(),
day: date.getDay(),
type: "五一"
});

date.setMonth(9);
date.setDate(1);
days.push({
date: date,
year: date.getFullYear(),
day: date.getDay(),
type: "十一"
});
}

return days;
}
Insert cell
d3 = import("d3")
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