viewof chart = {
const width = 800, height = 500;
const margin = { top: 50, right: 30, bottom: 30, left: 100 };
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
const data = [{'year': '2008-2011', 'category': 'Domestic Affairs', 'value': 9.0},
{'year': '2008-2011', 'category': 'Economic Policy', 'value': 9.0},
{'year': '2008-2011', 'category': 'International Affairs', 'value': 34.0},
{'year': '2008-2011', 'category': 'Social Justice', 'value': 49.0},
{'year': '2012-2015', 'category': 'Domestic Affairs', 'value': 26.0},
{'year': '2012-2015', 'category': 'Economic Policy', 'value': 11.0},
{'year': '2012-2015', 'category': 'International Affairs', 'value': 21.0},
{'year': '2012-2015', 'category': 'Social Justice', 'value': 42.0},
{'year': '2016-2019', 'category': 'Domestic Affairs', 'value': 12.0},
{'year': '2016-2019', 'category': 'Economic Policy', 'value': 4.0},
{'year': '2016-2019', 'category': 'International Affairs', 'value': 46.0},
{'year': '2016-2019', 'category': 'Social Justice', 'value': 38.0},
{'year': '2020-2023', 'category': 'Domestic Affairs', 'value': 20.0},
{'year': '2020-2023', 'category': 'Economic Policy', 'value': 5.0},
{'year': '2020-2023', 'category': 'International Affairs', 'value': 39.0},
{'year': '2020-2023', 'category': 'Social Justice', 'value': 36.0}];
const years = [...new Set(data.map(d => d.year))];
const x = d3.scaleLinear().range([margin.left, width - margin.right]);
const y = d3.scaleBand().range([margin.top, height - margin.bottom]).padding(0.1);
const color = d3.scaleOrdinal(d3.schemeTableau10);
const g = svg.append("g");
const legend = svg.append("g")
.attr("transform", `translate(${width - 150}, ${margin.top})`);
function update(year) {
const yearLabel = svg.selectAll(".year-label")
.data([year]);
yearLabel.enter()
.append("text")
.attr("class", "year-label")
.attr("x", width - 50)
.attr("y", margin.top - 20)
.attr("font-size", "24px")
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.merge(yearLabel)
.text(`Year ${year}`);
const filteredData = data.filter(d => d.year === year);
filteredData.sort((a, b) => b.value - a.value);
x.domain([0, d3.max(filteredData, d => d.value)]);
y.domain(filteredData.map(d => d.category));
const bars = g.selectAll("rect").data(filteredData, d => d.category);
bars.enter()
.append("rect")
.attr("y", d => y(d.category))
.attr("height", y.bandwidth())
.attr("x", margin.left)
.attr("width", 0)
.attr("fill", d => color(d.category))
.merge(bars)
.transition().duration(4000)
.attr("y", d => y(d.category))
.attr("x", margin.left)
.attr("width", d => x(d.value) - margin.left);
bars.exit().transition().duration(4000).attr("width", 0).remove();
const labels = g.selectAll("text").data(filteredData, d => d.category);
const threshold = 180;
labels.enter()
.append("text")
.attr("y", d => y(d.category) + y.bandwidth() / 2)
.attr("x", margin.left)
.attr("dy", "0.35em")
.attr("fill", "black")
.merge(labels)
.transition().duration(4000)
.attr("y", d => y(d.category) + y.bandwidth() / 2)
.attr("x", d => {
const barEnd = x(d.value);
if (barEnd - margin.left < threshold) {
return barEnd + 5;
}
return barEnd - 20;
})
.attr("text-anchor",d => {
const barEnd = x(d.value);
if (barEnd - margin.left < threshold) {
return "start";
}
return "end";
})
.text(d => `(${d.value}%) ${d.category}`);
labels.exit().transition().duration(4000).attr("x", margin.left).remove();
}
let i = 0, animation;
function animate() {
if (i < years.length) {
update(years[i]);
i++;
animation = setTimeout(animate, 4000);
}
}
function replay() {
clearTimeout(animation);
i = 0;
animate();
}
const button = document.createElement("button");
button.textContent = "Replay";
button.style.margin = "10px";
button.style.padding = "8px 12px";
button.style.fontSize = "16px";
button.style.cursor = "pointer";
button.onclick = replay;
animate();
const container = document.createElement("div");
container.appendChild(button);
container.appendChild(svg.node());
return container;
}