Published
Edited
Sep 26, 2021
Insert cell
Insert cell
Insert cell
calendar = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height * years.length])
.attr("id", "calendar")
.attr("font-family", "sans-serif")
.attr("font-size", 10);

const mouseOverFunction = function (event, d) {
const div = d3.select("#hover").style("opacity", 0);
div
.transition()
.duration(500)
.style("opacity", 0.9)
.attr("class", "tooltip show");
var markup = `<p>${d3.timeFormat("%B %-d")(d.date)}<br>${d.headline}</p>`;
if (d.headlines.length > 1) {
for (var i = 1; i < d.headlines.length; i++) {
markup += `<p>${d.headlines[i]}</p>`;
}
}
div
.html(markup)
.style("left", event.pageX + 5 + "px")
.style("top", event.pageY - 120 + "px");
};
const mouseOutFunction = function (event, d) {
const div = d3.select("#hover");
div
.transition()
.duration(500)
.style("opacity", 0)
.attr("class", "tooltip hide");
};

const year = svg
.selectAll("g")
.data(years)
.join("g")
.attr(
"transform",
(d, i) => `translate(40.5,${height * i + cellSize * 1.5})`
);

year
.append("text")
.attr("x", -5)
.attr("y", -5)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(([key]) => key);

year
.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(d3.range(7))
.join("text")
.attr("x", -5)
.attr("y", (i) => (countDay(i) + 0.5) * cellSize)
.attr("dy", "0.31em")
.text(formatDay);

year
.append("g")
.selectAll("rect")
.data(([, values]) => values)
.join("rect")
.attr("width", cellSize - 1)
.attr("height", cellSize - 1)
.attr("class", "cell")
.attr(
"x",
(d) => timeWeek.count(d3.timeYear(d.date), d.date) * cellSize + 0.5
)
.attr("y", (d) => countDay(d.date.getDay()) * cellSize + 0.5)
.attr("fill", (d) => color(d.value))
.on("click", (event, d) => {
console.log(d.url);
window.open(d.url, "test");
})
.on("mouseover", mouseOverFunction)
.on("mouseout", mouseOutFunction);
/*
.append("title")
.text((d) => {
//console.log(d);
return `${d3.timeFormat("%Y-%m-%d")(d.date)}\n${d.value} items`;
});
*/

const month = year
.append("g")
.selectAll("g")
.data(([, values]) =>
d3.timeMonths(
d3.timeMonth(values[values.length - 1].date),
d3.timeMonth(values[0].date)
)
)
.join("g");

month
.filter((d, i) => i)
.append("path")
.attr("fill", "none")
.attr("stroke", "#efefef")
.attr("stroke-width", 3)
.attr("d", pathMonth);

month
.append("text")
.attr(
"x",
(d) => timeWeek.count(d3.timeYear(d), timeWeek.ceil(d)) * cellSize + 2
)
.attr("y", -5)
.text(formatMonth);

return svg.node();
}
Insert cell
Insert cell
color = {
//const max = d3.quantile(years, 0.80, ([,values]) => values[0][1].length);
const max = d3.max(years, (v) => d3.max(v[1], (d) => d.value));
return scale(d3.interpolateRdPu).domain([0, max]);
}
Insert cell
dateReducer = (d) => {
// group by date
const groups = d3.groups(d, (v) => new Date(v.date)).reverse();

// count items per date
return groups.map(([date, items]) => ({
date: date,
value: items.length,
url: items[0].url,
headline: items[0].headline,
urls: items.map((i) => i.url),
headlines: items.map((i) => i.headline)
}));
}
Insert cell
years = d3.rollups(data, dateReducer, (d) => d.date.split("-")[0]).reverse()
Insert cell
years_details = d3
.groups(
data,
(d) => d.date.split("-")[0],
(d) => new Date(d3.timeFormat("%Y-%m-%d")(d.date))
)
.reverse()
Insert cell
scale = d3.scaleSequential
Insert cell
height = 135
Insert cell
//countDay = weekday === "sunday" ? (i) => i : (i) => (i + 6) % 7
countDay = (i) => i
Insert cell
formatDay = (i) => "SMTWTFS"[i]
Insert cell
//timeWeek = weekday === "sunday" ? d3.timeSunday : d3.timeMonday
timeWeek = d3.timeMonday
Insert cell
function pathMonth(t) {
//const n = weekday === "weekday" ? 5 : 7;
const n = 7;
const d = Math.max(0, Math.min(n, countDay(t.getDay())));
const w = timeWeek.count(d3.timeYear(t), t);
return `${
d === 0
? `M${w * cellSize},0`
: d === n
? `M${(w + 1) * cellSize},0`
: `M${(w + 1) * cellSize},0V${d * cellSize}H${w * cellSize}`
}V${n * cellSize}`;
}
Insert cell
Insert cell
calendarViews = [
{ value: "weekday", text: "Weekdays only" },
{ value: "sunday", text: "Sunday-based weeks" },
{ value: "monday", text: "Monday-based weeks" }
]
Insert cell
Insert cell
data = FileAttachment("data@5.csv").csv()
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