{
if (!selectedPurpose) return md`Select a purpose to see its distribution.`;
const aidForPurpose = aiddata.filter(d => d.purpose === selectedPurpose);
const receivedForPurposeByCountry = d3.rollup(
aidForPurpose,
v => d3.sum(v, d => d.amount),
d => corregirNombre(d.recipient)
);
const maxReceivedForPurpose = d3.max(Array.from(receivedForPurposeByCountry.values())) || 1;
const purposeColor = d3.scaleSequentialLog(d3.interpolateGreens)
.domain([1, maxReceivedForPurpose])
.clamp(true);
const geoDataForPurpose = (() => {
const features = geoJSON.features.map(feature => {
const name = feature.properties.ADMIN;
const receivedAmount = receivedForPurposeByCountry.get(name) || 0;
const totalDonatedByCountry = donadoPorPais.get(name) || 0;
const totalReceivedByCountry = recibidoPorPais.get(name) || 0;
return {
...feature,
properties: {
...feature.properties,
receivedAmountForPurpose: receivedAmount,
totalDonatedOverall: totalDonatedByCountry,
totalReceivedOverall: totalReceivedByCountry,
}
};
});
return { ...geoJSON, features };
})();
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("display", "block")
.style("margin", "0 auto")
.style("background", "#f0f0f0");
const g = svg.append("g");
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip-purpose") // Usar una clase diferente si quieres estilos distintos
.style("position", "absolute")
.style("background", "rgba(0,0,0,0.8)")
.style("color", "#fff")
.style("padding", "8px 12px")
.style("border-radius", "4px")
.style("font-size", "12px")
.style("pointer-events", "none")
.style("visibility", "hidden")
.style("line-height", "1.4");
g.selectAll("path")
.data(geoDataForPurpose.features)
.join("path")
.attr("d", path)
.attr("fill", d => {
const amount = d.properties.receivedAmountForPurpose;
return amount > 0 ? purposeColor(amount) : "#ccc";
})
.attr("stroke", "#333")
.attr("stroke-width", 0.5)
// .append("title") // Ya no usaremos el tooltip simple del navegador
// *** MODIFICACIÓN: Añadir eventos para el tooltip HTML ***
.on("mouseover", (event, d) => {
tooltip.style("visibility", "visible");
const props = d.properties;
let html = `<strong>${props.NAME || props.ADMIN}</strong>`;
html += `<br/>Purpose: ${selectedPurpose}`;
html += `<br/>Received for this purpose: ${d3.format("$,.0f")(props.receivedAmountForPurpose)} USD`;
html += `<hr style="margin: 4px 0; border-color: #555;">`; // Separador
html += `Overall Donated: ${d3.format("$,.0f")(props.totalDonatedOverall)} USD`;
html += `<br/>Overall Received: ${d3.format("$,.0f")(props.totalReceivedOverall)} USD`;
tooltip.html(html);
})
.on("mousemove", (event) => {
tooltip.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px");
})
.on("mouseout", () => {
tooltip.style("visibility", "hidden");
});
const zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom", (event) => {
g.attr("transform", event.transform);
});
svg.call(zoom);
const legendPurposeWidth = 200;
const legendHeightLocal = 12;
const legendPurposeX = margin.left + 20;
const legendPurposeY = height - margin.bottom - legendHeightLocal - 20;
const stepsLocal = 100;
const legendPurposeGroup = svg.append("g")
.attr("transform", `translate(${legendPurposeX}, ${legendPurposeY})`);
legendPurposeGroup.selectAll("rect.legend-purpose")
.data(d3.range(stepsLocal))
.enter()
.append("rect")
.attr("class", "legend-purpose")
.attr("x", (d, i) => (i / stepsLocal) * legendPurposeWidth) // Position each rect segment
.attr("y", 0)
.attr("width", legendPurposeWidth / stepsLocal) // Width of each segment
.attr("height", legendHeightLocal)
.attr("fill", d_idx => {
// Map index (0 to stepsLocal-1) to a value in the log scale domain [1, maxReceivedForPurpose]
const t = d_idx / (stepsLocal - 1); // Normalized position (0 to 1)
// To sample from a log scale linearly, interpolate in the log domain then exponentiate
if (maxReceivedForPurpose <= 1) return purposeColor(1); // Handle edge case if max is 1 or less
const value = Math.exp(Math.log(1) * (1-t) + Math.log(maxReceivedForPurpose) * t);
return purposeColor(value);
});
legendPurposeGroup.append("text")
.attr("x", 0)
.attr("y", legendHeightLocal + 14)
.style("font-size", "10px")
.style("text-anchor", "start")
.text(d3.format("$.0s")(1));
legendPurposeGroup.append("text")
.attr("x", legendPurposeWidth)
.attr("y", legendHeightLocal + 14)
.style("font-size", "10px")
.style("text-anchor", "end")
.text(d3.format("$.0s")(maxReceivedForPurpose));
legendPurposeGroup.append("text")
.attr("x", legendPurposeWidth / 2)
.attr("y", -5)
.style("font-size", "12px")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(`Amount Received for ${selectedPurpose}`);
return svg.node();
}