Public
Edited
Dec 7, 2022
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
yearsWithCount
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
{
document.getElementById("div-1").innerHTML = "";

const div1 = d3.select("#div-1").append("div"),
div2 = d3
.select("#div-1")
.append("div")
.attr("style", "margin-top: 20px; height: 500px; overflow-y: scroll"),
div3 = d3.select("#div-1").append("div");

// Years
{
const div = div1;
div.append("h2").text("Years");

const texts = div
.append("div")
.attr(
"style",
`
display: flex; flex-flow: wrap; background-color: ${backgroundColor}
`
)
.selectAll("div")
.data(yearsWithCount)
.join("div")
.attr("style", "padding: 5px")
.append("span")
.attr(
"style",
(d) => `
color: ${d.color}; font-family: monospace; font-size: larger
`
)
.text((d) => d.year);

texts.on("click", (e, d) => {
const magicOffset = document.getElementById(
`detail-year-${yearsWithCount[0].year}`
).offsetTop;

const node = div2.node(),
dom = document.getElementById(`detail-year-${d.year}`);
node.scrollTo(0, dom.offsetTop - magicOffset + 40);
});
}

// Detail
{
const div = div2;

const divs = div
.selectAll("div")
.data(yearsWithCount)
.join("div")
.attr("id", (d) => `detail-year-${d.year}`);

divs.append("hr");

divs
.append("div")
.attr(
"style",
`
border-top: solid gray;
border-bottom: solid gray;
width: 600px;
padding: 10px;
text-align: center;
`
)
.append("h3")
.text((d) => d.year);

function makeInnerHTML(msg) {
var html = msg;

if (selectedWords.length < rawWords.length) {
words.map((word) => {
html = html.replace(
word,
`
<span style="color: red">${word}</span>
`
);
});
}

return "<div>" + html + "</div>";
}

divs
.append("div")
.attr(
"style",
`
width: 600px;
`
)
.append("ul")
.selectAll("li")
.data((d) => selectEventsByYear(d.year))
.join("li")
.append("span")
.html((event) => makeInnerHTML(event.event));
}

// Floating div
{
div3.attr(
"style",
`
position: absolute;
left: ${650}px;
top: ${div1.node().offsetHeight + 40}px;
width: ${500}px;
height: ${500}px;
text-align: center;
// border: 1px solid black
`
);

div3
.append("canvas")
.attr("id", "canvas-1")
.attr(
"style",
`
width: ${0.9 * 500}px;
height: ${0.9 * 500}px;
`
);

div3.append("div").attr("id", "scroll-div-1").text("-- | -- | --");
}

function drawCanvas(year = 1949) {
var canvas = document.getElementById("canvas-1");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = true;
var img = document.createElement("img");

function paintText() {
ctx.font = "48px serif";
ctx.fillStyle = reverseBackgroundColor;
ctx.fillText("" + year, 30, 50);
}
paintText();

img.onload = function () {
var alpha = 0;
const t = this;

console.log(img.width, img.height);

function loop() {
alpha += 0.005;
ctx.globalAlpha = alpha;
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);

ctx.save();
ctx.scale(
img.width / canvas.clientWidth,
img.height / canvas.clientHeight
);
ctx.drawImage(t, 0, 0, canvas.clientWidth, canvas.clientHeight);
ctx.restore();

if (alpha <= 0.5) {
requestAnimationFrame(loop);
} else {
paintText();
}
}

loop();

// ctx.globalAlpha = alpha;
// ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
// ctx.drawImage(this, 0, 0, canvas.clientWidth, canvas.clientHeight);

paintText();
};

img.src = "https://source.unsplash.com/random/?city/?seed=" + year;
}
}

drawCanvas();

var currentYear = -1;

// Bound with scrolling
{
const dividers = yearsWithCount.map((d, i) => {
return document.getElementById(`detail-year-${d.year}`).offsetTop;
});

div2.on("scroll", (e) => {
const s = e.target.scrollTop,
befores = dividers.filter((d) => d < s + 400),
n = befores.length,
select = yearsWithCount[n - 1];

document.getElementById("scroll-div-1").innerText =
s + " | " + n + " | " + select.year;

if (select.year !== currentYear) {
currentYear = select.year;
drawCanvas(select.year);
}
});
}
}
Insert cell
yearsWithCount = {
const years = new Array(...new Set(selectedEvents.map((d) => d.year)));

const data = years.map((year) => {
return { year, n: selectEventsByYear(year).length };
});

const scale = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.n))
.range([0, 1]);

data.map((d) => {
d.r = scale(d.n);
d.color = d3.color(colorMap(d.r)).hex();
});

return data;
}
Insert cell
colorMap = d3[`interpolate${palette}`]
Insert cell
years = new Array(...new Set(selectedEvents.map((d) => d.year)))
Insert cell
words = new Array(...new Set(selectedWords.map((d) => d.word)))
Insert cell
selectEventsByYear = (year) => {
return selectedEvents.filter((d) => d.year === year);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3")
Insert cell
rawWords
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
rawEvents
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
rawEvents = FileAttachment("long_table.csv").csv()
Insert cell
rawWords = FileAttachment("words.csv").csv()
Insert cell
palettes = [
"RdBu",
"PuOr",
"Viridis",
"Inferno",
"Turbo",
"Magma",
"Plasma",
"Cividis",
"Warm",
"Cool",
"CubehelixDefault",
"BuPu",
"BuGn",
"GnBu",
"PuBu",
"PuRd",
"RdPu",
"PuBuGn",
"OrRd",
"YlGnBu",
"YlGn",
"YlOrRd",
"YlOrBr"
]
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