chart = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, gridWidth * cellSize, gridHeight * cellSize])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("background", "white");
svg.append("g").call(legend);
svg
.append("text")
.attr("x", gridWidth * cellSize - 2)
.attr("y", gridHeight * cellSize - 2)
.attr("dy", "-1em")
.attr("text-anchor", "end")
.attr("font-size", 5)
.text(d3.timeFormat("%x %X")(new Date(president.meta.timestamp)));
const cell = svg
.append("g")
.selectAll("g")
.data(parsed)
.join("g")
.attr("transform", ([statecode]) => {
const [i, j] = position.get(statecode);
return `translate(${i * cellSize},${j * cellSize})`;
});
cell
.append("text")
.attr("pointer-events", "none")
.attr("y", 3)
.attr("dy", "0.71em")
.text(([statecode]) => statecode);
const inner = cell
.append("g")
.attr("transform", `translate(${cellPadding}, ${cellPadding})`);
inner
.append("path")
.attr("d", `M ${triangle.A} ${triangle.B} ${triangle.C} Z`)
.attr("fill", "#eee")
.attr("stroke", "#eee")
.attr("stroke-width", 0.5);
inner
.append("path")
.attr("d", `M ${triangle.AB} ${triangle.B} ${triangle.BC} Z`)
.attr("fill", red)
.attr("opacity", ([, { winner }]) => (winner === "dem" ? 0 : 1))
.attr("fill-opacity", ([, { winner }]) =>
winner === "rep" ? 1 : winner === "dem" ? 0.1 : 0.1
);
inner
.append("path")
.attr("d", `M ${triangle.AC} ${triangle.C} ${triangle.BC} Z`)
.attr("fill", blue)
.attr("opacity", ([, { winner }]) => (winner === "rep" ? 0 : 1))
.attr("fill-opacity", ([, { winner }]) =>
winner === "dem" ? 1 : winner === "rep" ? 0.1 : 0.1
);
inner
.append("path")
.attr("stroke", "black")
.attr("stroke-width", 0.5)
.attr("fill", "none")
.attr("d", ([, { pathData }]) => line(pathData));
return svg.node();
}