{
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 40, left: 50 };
const data = [
{ pais: "Brasil", valor: 50, hombres: 35, mujeres: 15 },
{ pais: "Uruguay", valor: 40, hombres: 5, mujeres: 35 },
{ pais: "Argentina", valor: 35, hombres: 15, mujeres: 20 },
{ pais: "Chile", valor: 28, hombres: 22, mujeres: 6 },
{ pais: "Paraguay", valor: 22, hombres: 20, mujeres: 2 }
];
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
const x = d3.scaleBand()
.domain(data.map(d => d.pais))
.range([margin.left, width - margin.right])
.padding(0.1);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.valor)])
.range([height - margin.bottom, margin.top]);
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));
// Agregar eje Y (izquierdo)
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));
// Variable que indica qué país está seleccionado actualmente (o null)
let seleccionada = null;
// Función principal que renderiza el gráfico en función de los datos y la selección
function render(data, seleccionada) {
// Unimos los datos a grupos SVG, uno por país
const groups = svg.selectAll(".barra-grupo")
.data(data, d => d.pais) // Usamos el nombre del país como clave
.join("g") // Maneja automáticamente enter/update/exit: crea nuevos <g> si es necesario, actualiza los existentes, y elimina los que ya no están
.attr("class", "barra-grupo")
.attr("transform", d => `translate(${x(d.pais)},0)`); // Posicionamos el grupo
// Limpiamos el contenido previo de cada grupo antes de redibujar
groups.selectAll("*").remove();
// Para cada grupo (país), dibujamos la barra simple o la barra apilada
groups.each(function(d) {
const g = d3.select(this); // Seleccionamos el grupo actual
const barWidth = x.bandwidth(); // Ancho de cada barra
// Si el país está seleccionado → mostrar como barra apilada
if (d.pais === seleccionada) {
const total = d.valor; // Valor total
const h = d.hombres;
const m = d.mujeres;
const yH = y(h); // Y del tope del segmento hombres
const yM = y(h + m); // Y del tope del segmento mujeres
const heightH = y(0) - yH; // Altura de hombres
const heightM = y(0) - y(m); // Altura de mujeres
// Rectángulo inferior: hombres
g.append("rect")
.attr("class", "apilada")
.attr("y", yH)
.attr("width", barWidth)
.attr("height", heightH)
.attr("fill", "#f1a1bc") // Rosa suave
.on("click", () => manejarClick(d)); // Permite deselección con clic
// Porcentaje centrado para hombres
g.append("text")
.attr("x", barWidth / 2)
.attr("y", yH + heightH / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("font-size", "12px")
.style("fill", "black")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-weight", "bold") // Negrita
.text(Math.round((h / total) * 100) + "%");
// Rectángulo superior: mujeres
g.append("rect")
.attr("class", "apilada")
.attr("y", yM)
.attr("width", barWidth)
.attr("height", heightM)
.attr("fill", "#7bbfa7") // Verde azulado
.on("click", () => manejarClick(d));
// Porcentaje centrado para mujeres
g.append("text")
.attr("x", barWidth / 2)
.attr("y", yM + heightM / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("font-size", "12px")
.style("fill", "black")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-weight", "bold") // Negrita
.text(Math.round((m / total) * 100) + "%");
// Si el país no está seleccionado → mostrar barra simple
} else {
g.append("rect")
.attr("class", "barra")
.attr("y", y(d.valor))
.attr("width", barWidth)
.attr("height", y(0) - y(d.valor))
.attr("fill", "steelblue")
// Hover interacciones (solo si no está seleccionada)
.on("mouseover", function() {
if (seleccionada !== d.pais)
d3.select(this).attr("fill", "orange");
})
.on("mouseout", function() {
if (seleccionada !== d.pais)
d3.select(this).attr("fill", "steelblue");
})
.on("click", () => manejarClick(d)); // Clic para seleccionar
}
});
}
// Función que gestiona el clic en una barra (selección/deselección)
function manejarClick(d) {
if (seleccionada === d.pais) {
seleccionada = null; // Si estaba seleccionada → deseleccionamos
} else {
seleccionada = d.pais; // Si no → seleccionamos
}
render(data, seleccionada); // Siempre redibujamos el gráfico luego de un click
}
// Primer renderizado
render(data, seleccionada);
// Devolvemos el nodo SVG para visualizar
return svg.node();
}