|
|
|
function forceEdgeColors() { |
|
console.log("Forcibly updating all edge colors to match their target nodes"); |
|
|
|
|
|
let nodeColors = {}; |
|
sigmaInstance.iterNodes(function(node) { |
|
nodeColors[node.id] = node.color || '#aaa'; |
|
}); |
|
|
|
|
|
sigmaInstance.iterEdges(function(edge) { |
|
const targetColor = nodeColors[edge.target]; |
|
if (targetColor) { |
|
edge.color = targetColor; |
|
console.log(`Updated edge ${edge.id} color to ${targetColor} from target ${edge.target}`); |
|
} else { |
|
console.log(`Could not find color for edge ${edge.id}'s target node ${edge.target}`); |
|
} |
|
}); |
|
|
|
sigmaInstance.refresh(); |
|
console.log("Edge colors have been forcibly updated"); |
|
} |
|
|
|
|
|
function logNodeColors() { |
|
if (!sigmaInstance) return; |
|
|
|
console.log("Current node colors by type:"); |
|
let typeColors = {}; |
|
|
|
|
|
sigmaInstance.iterNodes(function(node) { |
|
if (node.type) { |
|
if (!typeColors[node.type]) { |
|
typeColors[node.type] = { |
|
configColor: (config.nodeTypes && config.nodeTypes[node.type]) |
|
? config.nodeTypes[node.type].color |
|
: (nodeTypes[node.type] ? nodeTypes[node.type].color : 'none'), |
|
nodeCount: 0, |
|
colorCounts: {} |
|
}; |
|
} |
|
|
|
typeColors[node.type].nodeCount++; |
|
|
|
if (!typeColors[node.type].colorCounts[node.color]) { |
|
typeColors[node.type].colorCounts[node.color] = 0; |
|
} |
|
typeColors[node.type].colorCounts[node.color]++; |
|
} |
|
}); |
|
|
|
|
|
for (const type in typeColors) { |
|
console.log(`Node type: ${type}`); |
|
console.log(` Config color: ${typeColors[type].configColor}`); |
|
console.log(` Node count: ${typeColors[type].nodeCount}`); |
|
console.log(' Actual colors used:'); |
|
for (const color in typeColors[type].colorCounts) { |
|
console.log(` ${color}: ${typeColors[type].colorCounts[color]} nodes`); |
|
} |
|
} |
|
} |
|
|
|
|
|
function forceNodeColorsFromConfig() { |
|
console.log("Forcibly applying node colors from config settings"); |
|
|
|
if (!sigmaInstance) { |
|
console.error("Cannot apply node colors, sigma instance not initialized"); |
|
return; |
|
} |
|
|
|
|
|
let configNodeTypes = config.nodeTypes || nodeTypes; |
|
|
|
|
|
sigmaInstance.iterNodes(function(node) { |
|
if (node.type && configNodeTypes[node.type]) { |
|
|
|
const configColor = configNodeTypes[node.type].color; |
|
console.log(`Setting node ${node.id} color to ${configColor} based on type ${node.type}`); |
|
node.color = configColor; |
|
|
|
|
|
if (configNodeTypes[node.type].size) { |
|
node.size = configNodeTypes[node.type].size; |
|
} |
|
} |
|
}); |
|
|
|
|
|
sigmaInstance.refresh(); |
|
|
|
|
|
setTimeout(function() { |
|
forceEdgeColors(); |
|
|
|
logNodeColors(); |
|
}, 100); |
|
|
|
console.log("Node colors have been forcibly applied from config"); |
|
} |
|
|
|
|
|
function initializeGraph(data) { |
|
graph = data; |
|
console.log("Initializing graph with nodes:", graph.nodes.length, "edges:", graph.edges.length); |
|
|
|
try { |
|
|
|
sigmaInstance = sigma.init(document.getElementById('sigma-canvas')); |
|
|
|
|
|
sigmaInstance.mouseProperties({ |
|
maxRatio: 32, |
|
minRatio: 0.5, |
|
mouseEnabled: true, |
|
mouseInertia: 0.8 |
|
}); |
|
|
|
console.log("Sigma mouse properties configured"); |
|
|
|
|
|
for (let i = 0; i < graph.nodes.length; i++) { |
|
let node = graph.nodes[i]; |
|
sigmaInstance.addNode(node.id, { |
|
label: node.label || node.id, |
|
x: node.x || Math.random() * 100, |
|
y: node.y || Math.random() * 100, |
|
size: node.size || 1, |
|
color: node.color || (node.type && config.nodeTypes && config.nodeTypes[node.type] ? |
|
config.nodeTypes[node.type].color : nodeTypes[node.type]?.color || '#666'), |
|
type: node.type |
|
}); |
|
} |
|
|
|
|
|
for (let i = 0; i < graph.edges.length; i++) { |
|
let edge = graph.edges[i]; |
|
|
|
|
|
let targetNodeColor = '#aaa'; |
|
sigmaInstance.iterNodes(function(node) { |
|
if (node.id == edge.target) { |
|
targetNodeColor = node.color; |
|
console.log(`Setting edge ${edge.id} color to match target node ${node.id}: ${targetNodeColor}`); |
|
} |
|
}); |
|
|
|
sigmaInstance.addEdge(edge.id, edge.source, edge.target, { |
|
size: edge.size || 1, |
|
color: targetNodeColor |
|
}); |
|
} |
|
|
|
|
|
sigmaInstance.drawingProperties({ |
|
labelThreshold: config.sigma?.drawingProperties?.labelThreshold || 8, |
|
defaultLabelColor: config.sigma?.drawingProperties?.defaultLabelColor || '#000', |
|
defaultLabelSize: config.sigma?.drawingProperties?.defaultLabelSize || 14, |
|
defaultEdgeType: config.sigma?.drawingProperties?.defaultEdgeType || 'curve', |
|
defaultHoverLabelBGColor: config.sigma?.drawingProperties?.defaultHoverLabelBGColor || '#002147', |
|
defaultLabelHoverColor: config.sigma?.drawingProperties?.defaultLabelHoverColor || '#fff', |
|
borderSize: 2, |
|
nodeBorderColor: '#fff', |
|
defaultNodeBorderColor: '#fff', |
|
defaultNodeHoverColor: '#fff', |
|
edgeColor: 'target', |
|
defaultEdgeColor: '#f00' |
|
}); |
|
|
|
|
|
sigmaInstance.graphProperties({ |
|
minNodeSize: config.sigma?.graphProperties?.minNodeSize || 1, |
|
maxNodeSize: config.sigma?.graphProperties?.maxNodeSize || 8, |
|
minEdgeSize: config.sigma?.graphProperties?.minEdgeSize || 0.5, |
|
maxEdgeSize: config.sigma?.graphProperties?.maxEdgeSize || 2, |
|
sideMargin: 50 |
|
}); |
|
|
|
|
|
sigmaInstance.draw(2, 2, 2, 2); |
|
|
|
|
|
forceNodeColorsFromConfig(); |
|
|
|
|
|
forceEdgeColors(); |
|
|
|
console.log("Sigma instance created and configured:", sigmaInstance); |
|
|
|
|
|
applyNodeStyles(); |
|
|
|
|
|
forceEdgeColors(); |
|
|
|
|
|
initFilters(); |
|
|
|
|
|
bindEvents(); |
|
} catch (e) { |
|
console.error("Error initializing sigma instance:", e); |
|
} |
|
} |
|
|
|
|
|
function applyNodeStyles() { |
|
if (!sigmaInstance) return; |
|
try { |
|
|
|
sigmaInstance.iterNodes(function(node) { |
|
|
|
if (node.type && config.nodeTypes && config.nodeTypes[node.type]) { |
|
|
|
node.color = config.nodeTypes[node.type].color; |
|
node.size = config.nodeTypes[node.type].size; |
|
} else if (node.type && nodeTypes[node.type]) { |
|
|
|
node.color = nodeTypes[node.type].color; |
|
node.size = nodeTypes[node.type].size; |
|
} |
|
}); |
|
|
|
|
|
sigmaInstance.iterEdges(function(edge) { |
|
sigmaInstance.iterNodes(function(node) { |
|
if (node.id == edge.target) { |
|
edge.color = node.color; |
|
} |
|
}); |
|
}); |
|
|
|
sigmaInstance.refresh(); |
|
} catch (e) { |
|
console.error("Error applying node styles:", e); |
|
} |
|
} |
|
|
|
|
|
function colorNodesByAttribute(attribute) { |
|
if (!sigmaInstance) return; |
|
|
|
console.log("Coloring nodes by attribute:", attribute); |
|
|
|
let values = {}; |
|
let valueCount = 0; |
|
|
|
sigmaInstance.iterNodes(function(n) { |
|
let value = n[attribute] || 'unknown'; |
|
if (!values[value]) { |
|
values[value] = true; |
|
valueCount++; |
|
} |
|
}); |
|
|
|
|
|
let valueColors = {}; |
|
let i = 0; |
|
let palette = config.colorPalette || colors; |
|
|
|
for (let value in values) { |
|
valueColors[value] = palette[i % palette.length]; |
|
i++; |
|
} |
|
|
|
|
|
sigmaInstance.iterNodes(function(n) { |
|
let value = n[attribute] || 'unknown'; |
|
n.originalColor = valueColors[value]; |
|
n.color = valueColors[value]; |
|
}); |
|
|
|
|
|
sigmaInstance.iterEdges(function(edge) { |
|
sigmaInstance.iterNodes(function(node) { |
|
if (node.id == edge.target) { |
|
edge.originalColor = node.color; |
|
edge.color = node.color; |
|
} |
|
}); |
|
}); |
|
|
|
sigmaInstance.refresh(); |
|
|
|
|
|
updateColorLegend(valueColors); |
|
} |
|
|
|
|
|
function nodeActive(nodeId) { |
|
console.log("nodeActive called with id:", nodeId); |
|
|
|
|
|
var node = null; |
|
sigmaInstance.iterNodes(function(n) { |
|
if (n.id == nodeId) { |
|
node = n; |
|
} |
|
}); |
|
|
|
if (!node) { |
|
console.error("Node not found:", nodeId); |
|
return; |
|
} |
|
|
|
console.log("Node found:", node); |
|
sigmaInstance.detail = true; |
|
selectedNode = node; |
|
|
|
|
|
var neighbors = {}; |
|
sigmaInstance.iterEdges(function(e) { |
|
if (e.source == nodeId || e.target == nodeId) { |
|
neighbors[e.source == nodeId ? e.target : e.source] = { |
|
name: e.label || "", |
|
color: e.color |
|
}; |
|
|
|
e.originalColor = e.color; |
|
} |
|
}); |
|
|
|
console.log("Neighbors found:", Object.keys(neighbors).length); |
|
|
|
|
|
sigmaInstance.iterNodes(function(n) { |
|
if (n.id == nodeId) { |
|
n.originalColor = n.color; |
|
n.size = n.size * 1.5; |
|
} else if (neighbors[n.id]) { |
|
n.originalColor = n.color; |
|
} else { |
|
n.originalColor = n.originalColor || n.color; |
|
n.color = greyColor; |
|
} |
|
}); |
|
|
|
|
|
sigmaInstance.iterEdges(function(e) { |
|
if (e.source == nodeId || e.target == nodeId) { |
|
|
|
e.originalColor = e.color; |
|
} else { |
|
e.originalColor = e.originalColor || e.color; |
|
e.color = greyColor; |
|
} |
|
}); |
|
|
|
|
|
sigmaInstance.refresh(); |
|
|
|
|
|
var connectionList = []; |
|
for (var id in neighbors) { |
|
var neighbor = null; |
|
sigmaInstance.iterNodes(function(n) { |
|
if (n.id == id) { |
|
neighbor = n; |
|
} |
|
}); |
|
|
|
if (neighbor) { |
|
connectionList.push('<li><a href="#" data-node-id="' + id + '">' + (neighbor.label || id) + '</a></li>'); |
|
} |
|
} |
|
|
|
|
|
try { |
|
console.log("Displaying attribute pane"); |
|
|
|
$('#attributepane').show().css('display', 'block'); |
|
|
|
|
|
$('.nodeattributes .name').text(node.label || node.id); |
|
|
|
let dataHTML = ''; |
|
for (let attr in node) { |
|
if (attr !== 'id' && attr !== 'x' && attr !== 'y' && attr !== 'size' && attr !== 'color' && |
|
attr !== 'label' && attr !== 'originalColor' && attr !== 'hidden' && |
|
typeof node[attr] !== 'function' && attr !== 'displayX' && attr !== 'displayY' && |
|
attr !== 'displaySize') { |
|
dataHTML += '<div><strong>' + attr + ':</strong> ' + node[attr] + '</div>'; |
|
} |
|
} |
|
|
|
if (dataHTML === '') { |
|
dataHTML = '<div>No additional attributes</div>'; |
|
} |
|
|
|
$('.nodeattributes .data').html(dataHTML); |
|
$('.nodeattributes .link ul').html(connectionList.length ? connectionList.join('') : '<li>No connections</li>'); |
|
|
|
|
|
$('.nodeattributes .link ul li a').click(function(e) { |
|
e.preventDefault(); |
|
var id = $(this).data('node-id'); |
|
nodeActive(id); |
|
}); |
|
|
|
console.log("Attribute pane updated with node details"); |
|
} catch (e) { |
|
console.error("Error updating attribute pane:", e); |
|
} |
|
} |
|
|
|
|
|
function nodeNormal() { |
|
console.log("nodeNormal called"); |
|
if (sigmaInstance) { |
|
sigmaInstance.detail = false; |
|
selectedNode = null; |
|
|
|
|
|
sigmaInstance.iterNodes(function(node) { |
|
node.color = node.originalColor || node.color; |
|
|
|
if (node.type && config.nodeTypes && config.nodeTypes[node.type]) { |
|
node.size = config.nodeTypes[node.type].size; |
|
} else if (node.type && nodeTypes[node.type]) { |
|
node.size = nodeTypes[node.type].size; |
|
} |
|
}); |
|
|
|
|
|
sigmaInstance.iterEdges(function(edge) { |
|
edge.color = edge.originalColor || edge.color; |
|
}); |
|
|
|
|
|
$('#attributepane').css('display', 'none'); |
|
sigmaInstance.refresh(); |
|
|
|
|
|
forceEdgeColors(); |
|
} |
|
} |