// Variables globales var svg, sankey, width, height, margin; var color = d3.scaleOrdinal(d3.schemeCategory20); var currentGraph = null; var isTooltipVisible = false; // Añadido para controlar visibilidad del tooltip var lastMouseX = 0; // Añadido para posición del mouse var lastMouseY = 0; // Añadido para posición del mouse // Inicializar gráfico function initChart() { console.log("Inicializando gráfico..."); // Limpiar SVG existente d3.select("#my_dataviz").select("svg").remove(); d3.select("#my_dataviz .loading").style("display", "block"); // Obtener dimensiones del contenedor var container = document.getElementById('my_dataviz'); width = container.clientWidth; height = container.clientHeight; margin = {top: 20, right: 20, bottom: 20, left: 20}; // Crear SVG svg = d3.select("#my_dataviz") .append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Ajustar dimensiones para cálculos internos width = width - margin.left - margin.right; height = height - margin.top - margin.bottom; // Configurar Sankey sankey = d3.sankey() .nodeWidth(20) .nodePadding(10) .size([width, height]); // Cargar datos loadData(); } // Cargar datos function loadData() { d3.json("https://resquivel0810.github.io/resquivel/data/data_sankey.json", function(error, graph) { if (error) { console.error("Error cargando datos:", error); showError("Error loading data: " + error); return; } if (!graph) { showError("No data received"); return; } // Normalizar datos var normalizedData = normalizeData(graph); if (!normalizedData) { showError("Invalid data structure"); return; } currentGraph = normalizedData; createSankey(normalizedData); }); } // Normalizar datos para Sankey function normalizeData(graph) { try { if (graph.nodes && graph.links) { return processSankeyData(graph); } if (Array.isArray(graph)) { return getSampleData(); } var nodes = graph.Nodes || graph.nodelist || graph.data || []; var links = graph.Links || graph.linklist || graph.edges || []; if (nodes.length > 0 || links.length > 0) { return processSankeyData({nodes: nodes, links: links}); } return null; } catch (error) { console.error("Error normalizando datos:", error); return null; } } // Procesar datos en formato Sankey function processSankeyData(data) { var nodes = []; var links = []; // Procesar nodos if (Array.isArray(data.nodes)) { nodes = data.nodes.map(function(node, index) { var name = "Node " + (index + 1); if (typeof node === 'string') { name = node; } else if (typeof node === 'object') { if (node.name !== undefined) name = String(node.name); else if (node.Name !== undefined) name = String(node.Name); else if (node.id !== undefined) name = String(node.id); else if (node.ID !== undefined) name = String(node.ID); else if (node.label !== undefined) name = String(node.label); else if (node.LABEL !== undefined) name = String(node.LABEL); else if (node.title !== undefined) name = String(node.title); } var value = 0; if (typeof node === 'object') { if (node.value !== undefined) value = parseFloat(node.value) || 0; else if (node.Value !== undefined) value = parseFloat(node.Value) || 0; else if (node.size !== undefined) value = parseFloat(node.size) || 0; else if (node.val !== undefined) value = parseFloat(node.val) || 0; } return { id: index, name: name, value: value, original: node }; }); } // Procesar enlaces if (Array.isArray(data.links)) { links = data.links.map(function(link, index) { var source = link.source; var target = link.target; if (typeof source === 'object' && source !== null) { source = source.index || source.id || 0; } if (typeof target === 'object' && target !== null) { target = target.index || target.id || 0; } source = parseInt(source) || 0; target = parseInt(target) || 0; var value = parseFloat(link.value || link.Value || link.size || 0) || 0; return { source: source, target: target, value: value, original: link }; }).filter(function(link) { return link.source >= 0 && link.target >= 0 && link.source < nodes.length && link.target < nodes.length && link.value > 0; }); } // Calcular valores de nodos si no están definidos nodes.forEach(function(node) { if (node.value === 0) { var incoming = links.filter(function(l) { return l.target === node.id; }); var outgoing = links.filter(function(l) { return l.source === node.id; }); var totalIn = d3.sum(incoming, function(d) { return d.value; }); var totalOut = d3.sum(outgoing, function(d) { return d.value; }); node.value = Math.max(totalIn, totalOut) || 1; } }); return { nodes: nodes, links: links }; } // Crear gráfico Sankey function createSankey(graph) { try { // Ocultar loading d3.select("#my_dataviz .loading").style("display", "none"); if (graph.nodes.length === 0) { showError("No hay nodos para mostrar"); return; } // Aplicar layout Sankey sankey .nodes(graph.nodes) .links(graph.links) .layout(32); // Crear enlaces var link = svg.append("g") .selectAll(".link") .data(graph.links) .enter().append("path") .attr("class", "link") .attr("d", sankey.link()) .style("stroke-width", function(d) { return Math.max(1, d.dy || 3); }) .style("stroke", function(d) { var sourceNode = graph.nodes[d.source]; return color(sourceNode ? sourceNode.name : "Unknown"); }) .style("stroke-opacity", 0.4) .on("mouseover", function(event, d) { var sourceNode = graph.nodes[d.source]; var targetNode = graph.nodes[d.target]; var sourceName = sourceNode ? sourceNode.name : "Source"; var targetName = targetNode ? targetNode.name : "Target"; showTooltip(event, '
' + message + '
' + '' + '