chart = {
const w = gridWidth * cellSize + 2 * svgPadding;
const h = gridHeight * cellSize + 2 * svgPadding;
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, w, h])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("background", "white");
const g = svg
.append("g")
.attr("transform", `translate(${svgPadding}, ${svgPadding})`);
g.append("g").call(legend);
g.append("text")
.attr("x", w - svgPadding)
.attr("y", h - svgPadding)
.attr("dy", "-1em")
.attr("text-anchor", "end")
.text(d3.timeFormat("%x %X")(new Date(president.meta.timestamp)));
const cell = g
.append("g")
.selectAll("g")
.data(parsed)
.join("g")
.attr("transform", ([statecode]) => {
const [i, j] = position.get(statecode);
return `translate(${i * cellSize},${j * cellSize})`;
});
const inner = cell
.append("g")
.attr("class", "cell-inner")
.attr("transform", `translate(${cellPadding}, ${cellPadding})`);
inner
.append("rect")
.attr("width", cellInner)
.attr("height", cellInner)
.attr("fill", "#eee")
.attr("opacity", 0.5);
inner
.append("text")
.attr("pointer-events", "none")
.attr("text-anchor", "start")
.attr("x", 2)
.attr("y", 3)
.attr("dy", "0.71em")
.attr("font-size", cellInner / 4)
.text(([statecode]) => statecode);
inner
.append("path")
.attr("stroke", ([, { ninety }]) => color(ninety))
.attr("stroke-width", 1.75)
.attr("fill", "none")
.attr("d", ([, { ts }]) => line(ts));
inner
.filter(d => d[1].call)
.append("circle")
.attr("r", callCircleRadius)
.attr("cx", ([, { call }]) => x(call.time))
.attr("cy", ([, { call }]) => y(call[yType]))
.attr("fill", ([, { ninety }]) => color(ninety));
return svg.node();
}