chart = {
const svg = d3
.create("svg")
.attr("width", width + marginLeft + marginRight)
.attr("height", height + marginTop + marginBottom);
const g = svg
.append("g")
.attr("transform", `translate(${[marginLeft, marginTop]})`);
svg
.append("g")
.attr("transform", `translate(${marginLeft},${height - marginBottom * 2})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
const yearG = svg.append("g");
const indicatorG = svg.append("g");
const loadingG = svg.append("g");
indicatorG
.selectAll("text")
.data([indicatorId], () => "indicatorId")
.join("text")
.attr("class", "title")
.text((d) => indicatorIdToNames.get(d))
.attr("font-size", "2rem")
.attr("x", 50)
.attr("y", 50);
const { dataByYears, bestProgress, worstProgress, isHighlighted } = chartData;
const update = (y) => {
const yearData = dataByYears.get(y);
g.selectAll("circle")
.data(yearData, (x) => x.data.geoUnit)
.join("circle")
.transition()
.duration(y === yearExtent[0] ? 0 : 250)
.attr("fill", (b) =>
bestProgress.has(b.data.geoUnit)
? "#016b3d"
: worstProgress.has(b.data.geoUnit)
? "#d4212c"
: "#ddd"
)
.attr("fill-opacity", (b) =>
bestProgress.has(b.data.geoUnit) ? 0.8 : 0.8
)
.attr("title", (b) => b.data.geoUnit)
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.attr("r", (d) =>
bestProgress.has(d.data.geoUnit) || worstProgress.has(d.data.geoUnit)
? 5
: 3
);
const progressData = yearData.filter((x) => isHighlighted(x.data));
g.selectAll("text")
.data(progressData, (x) => x.data.geoUnit)
.join("text")
.transition()
.duration(y === yearExtent[0] ? 0 : 250)
.attr("fill", (b) =>
isHighlighted(b.data) ? color(b.data.geoUnit) : "#eee"
)
.attr("font-family", "sans-serif")
.attr("font-size", "small")
.attr("title", (b) => b.data.geoUnit)
.attr("x", (d) => d.x - 20)
.attr("y", (d) => d.y - 20)
.text((b) => b.data.geoUnit);
yearG
.selectAll("text")
.data([y], () => "year")
.join("text")
.attr("class", "title")
.text(y)
.attr("font-size", "3rem")
.attr("fill", "#bbb")
.attr("x", 50)
.attr("y", 100);
};
const setLoading = (text) => {
loadingG
.selectAll("text")
.data([text], (x) => "text")
.join("text")
.text((d) => d)
.attr("x", width - 100)
.attr("y", 24);
};
update(yearExtent[0]);
return Object.assign(svg.node(), { update, setLoading });
}