svgFinalOutput = {
const svgSelection = d3.select(svgNode);
const tooltip = d3.select(tooltipContainerSimple);
if (tooltip.empty()){
console.error("Simple tooltip container selection failed!");
return svgNode;
}
let minX = 0, minY = 0, svgWidth = 550, svgHeight = 990;
const viewBoxAttr = svgNode.getAttribute("viewBox");
if (viewBoxAttr) {
try {
const parts = viewBoxAttr.split(" ").map(Number);
if (parts.length === 4 && parts.every(n => !isNaN(n))) {
[minX, minY, svgWidth, svgHeight] = parts;
} else throw new Error("Invalid viewBox value format");
} catch (e) {
console.error("Error parsing viewBox:", e, "Using fallback dimensions.");
}
} else {
console.warn("SVG viewBox attribute missing, using fallback dimensions.");
}
const centerX = minX + svgWidth / 2;
svgSelection.append("line")
.attr("class", "split-line")
.attr("x1", centerX - 1)
.attr("y1", minY)
.attr("x2", centerX - 1)
.attr("y2", minY + svgHeight) // End at viewBox bottom
.attr("stroke", "black")
.attr("stroke-width", 1) // Thin line
.attr("stroke-dasharray", "3,3"); // Dashed pattern
// --- Text Labels AT THE TOP ---
const labelYPosition = minY + 15; // Y position near the top (adjust padding as needed)
const labelFontSize = "12px"; // Smaller font size might fit better at top
// 2. Female Label (Left Top)
svgSelection.append("text")
.attr("class", "side-label female-label")
.attr("x", minX + 15) // Pad from left edge
.attr("y", labelYPosition) // Set Y position
.attr("text-anchor", "start") // Align text start to X
.attr("dominant-baseline", "hanging") // Align TOP of text to Y position
.style("font-size", labelFontSize)
.style("font-weight", "bold")
.text("Female");
// 3. Male Label (Right Top)
svgSelection.append("text")
.attr("class", "side-label male-label")
.attr("x", minX + svgWidth - 15) // Pad from right edge
.attr("y", labelYPosition) // Set Y position
.attr("text-anchor", "end") // Align text end to X
.attr("dominant-baseline", "hanging") // Align TOP of text to Y position
.style("font-size", labelFontSize)
.style("font-weight", "bold")
.text("Male");
// === Dynamic Styling and Events ===
// (This part remains the same - applying defaults then iterating through data)
// 1. Apply Default Style and Remove Old Listeners first
svgSelection.selectAll("path[id]")
.style("fill", "#d3d3d3").style("cursor", "default")
.on("pointerover", null).on("pointermove", null).on("pointerout", null);
// 2. Iterate through processed data
transformedData.forEach(d => {
const selector = `#${d.label}`;
const pathElement = svgSelection.select(selector);
if (!pathElement.empty()) {
// Apply Styles
pathElement.style("fill", colorScale(d.value)).style("cursor", "pointer");
// Attach Events
pathElement
.on("pointerover", function(event) { /* ... tooltip show ... */ tooltip.html(`${d.label}: ${d.value.toFixed(2)}`).style("left", (event.pageX + 10) + "px").style("top", (event.pageY - 15) + "px").style("visibility", "visible"); d3.select(this).style("stroke", "black").style("stroke-width", "2px").raise(); })
.on("pointermove", function(event) { /* ... tooltip move ... */ tooltip.style("left", (event.pageX + 10) + "px").style("top", (event.pageY - 15) + "px"); })
.on("pointerout", function() { /* ... tooltip hide ... */ tooltip.style("visibility", "hidden"); d3.select(this).style("stroke", null).style("stroke-width", null); });
}
});
// === Apply Zoom Transition based on mutable selectedView === <<< NEW SECTION >>>
const currentViewKey = mutable selectedView; // Get the current state
const targetViewBoxParams = viewDefinitions[currentViewKey]; // Look up the parameters
if (targetViewBoxParams && targetViewBoxParams.length === 4) {
// Apply the transition TO THE CLONE (svgSelection)
svgSelection
.transition("zoom_transition") // Named transition
.duration(750) // Animation duration
.attr("viewBox", targetViewBoxParams.join(" ")); // Set target viewBox
} else {
console.warn(`Zoom: Invalid view definition for "${currentViewKey}" in svgFinalOutput cell.`);
// Optional: You could apply the default 'overview' viewBox here as a fallback
// const overviewParams = viewDefinitions['overview'];
// if (overviewParams) {
// svgSelection.attr("viewBox", overviewParams.join(" ")); // Set directly, no transition
// }
}
// === Return the finished SVG node ===
// The node is returned immediately, the transition runs on it afterwards.
return svgNode;
}