stackedBarChart = {
const margin = { top: 60, right: 30, bottom: 60, left: 70 };
const width = 800 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
const g = svg
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
svg
.append("text")
.attr("x", (width + margin.left + margin.right) / 2)
.attr("y", margin.top / 2)
.attr("text-anchor", "middle")
.attr("font-size", "20px")
.attr("font-weight", "bold")
.text("Top 10 Clubs: Player Positions and Values");
const data = [
{
club: "Atlético Madrid",
Defender: 164850000,
Forward: 131100000,
Goalkeeper: 88975000,
Midfielder: 205450000
},
{
club: "Borussia Dortmund",
Defender: 117325000,
Forward: 140710000,
Goalkeeper: 39320000,
Midfielder: 234970000
},
{
club: "FC Barcelona",
Defender: 206250000,
Forward: 298800000,
Goalkeeper: 99350000,
Midfielder: 264900000
},
{
club: "FC Bayern München",
Defender: 162500000,
Forward: 236100000,
Goalkeeper: 41175000,
Midfielder: 249000000
},
{
club: "Juventus",
Defender: 160875000,
Forward: 252600000,
Goalkeeper: 63300000,
Midfielder: 258700000
},
{
club: "Liverpool",
Defender: 184100000,
Forward: 236700000,
Goalkeeper: 72650000,
Midfielder: 214200000
},
{
club: "Manchester City",
Defender: 193200000,
Forward: 264500000,
Goalkeeper: 83350000,
Midfielder: 258000000
},
{
club: "Manchester United",
Defender: 147375000,
Forward: 220350000,
Goalkeeper: 78025000,
Midfielder: 218400000
},
{
club: "Paris Saint-Germain",
Defender: 182950000,
Forward: 338000000,
Goalkeeper: 63300000,
Midfielder: 196950000
},
{
club: "Real Madrid",
Defender: 184350000,
Forward: 266400000,
Goalkeeper: 94500000,
Midfielder: 247500000
}
];
// Positions
const positions = ["Defender", "Forward", "Goalkeeper", "Midfielder"];
// Stack the data by positions
const stack = d3.stack().keys(positions)(data);
// X axis: Clubs
const x = d3
.scaleBand()
.domain(data.map((d) => d.club))
.range([0, width])
.padding([0.2]);
// Y axis: Total value in EUR
const y = d3
.scaleLinear()
.domain([
0,
d3.max(data, (d) => d.Defender + d.Forward + d.Goalkeeper + d.Midfielder)
])
.range([height, 0]);
// Colors for each position
const color = d3
.scaleOrdinal()
.domain(positions)
.range(["#ff7f0e", "#1f77b4", "#2ca02c", "#d62728"]);
// Add X axis
g.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x));
// Add X axis label
g.append("text")
.attr("text-anchor", "middle")
.attr("x", width / 2)
.attr("y", height + margin.bottom - 15)
.attr("class", "axis-label")
.text("Club");
// Add Y axis
g.append("g").call(d3.axisLeft(y));
// Add Y axis label
g.append("text")
.attr("text-anchor", "middle")
.attr("x", -height / 2)
.attr("y", -margin.left + 20)
.attr("transform", "rotate(-90)")
.attr("class", "axis-label")
.text("Total Value (EUR)");
// Create stacked bars
g.selectAll("g.stack")
.data(stack)
.enter()
.append("g")
.attr("fill", (d) => color(d.key))
.selectAll("rect")
.data((d) => d)
.enter()
.append("rect")
.attr("x", (d) => x(d.data.club))
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
.attr("width", x.bandwidth());
// Tooltip for better interaction
const tooltip = d3
.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0)
.style("position", "absolute")
.style("background", "lightsteelblue")
.style("padding", "5px")
.style("border-radius", "5px")
.style("pointer-events", "none");
g.selectAll("rect")
.on("mouseover", (event, d) => {
tooltip.transition().duration(200).style("opacity", 0.9);
tooltip
.html(
`Club: ${d.data.club}<br>Position: ${
positions[stack.indexOf(d)]
}<br>Value: €${d[1] - d[0]}`
)
.style("left", event.pageX + 5 + "px")
.style("top", event.pageY - 28 + "px");
})
.on("mouseout", () => {
tooltip.transition().duration(500).style("opacity", 0);
});
// Legend for player positions
const legend = svg
.append("g")
.attr("transform", `translate(${width - 150}, ${margin.top})`);
positions.forEach((pos, i) => {
legend
.append("rect")
.attr("x", 0)
.attr("y", i * 20)
.attr("width", 10)
.attr("height", 10)
.style("fill", color(pos));
legend
.append("text")
.attr("x", 20)
.attr("y", i * 20 + 9)
.text(pos)
.attr("alignment-baseline", "middle")
.style("font-size", "12px");
});
return svg.node();
}