Commit
·
1df1529
1
Parent(s):
7c3814c
node highlighting is fixed
Browse files- config.json +8 -0
- css/style.css +21 -0
- index.html +2 -2
- js/main.js +88 -35
config.json
CHANGED
|
@@ -28,6 +28,14 @@
|
|
| 28 |
"defaultColorAttribute": "type",
|
| 29 |
"labelThreshold": 8
|
| 30 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
"informationPanel": {
|
| 32 |
"groupByEdgeDirection": false,
|
| 33 |
"imageAttribute": false
|
|
|
|
| 28 |
"defaultColorAttribute": "type",
|
| 29 |
"labelThreshold": 8
|
| 30 |
},
|
| 31 |
+
"highlighting": {
|
| 32 |
+
"nodeOpacity": 0.2,
|
| 33 |
+
"edgeOpacity": 0.05,
|
| 34 |
+
"selectedNodeSizeFactor": 1.5,
|
| 35 |
+
"highlightConnections": true,
|
| 36 |
+
"highlightedEdgeColor": "#000000",
|
| 37 |
+
"highlightedEdgeSizeFactor": 5
|
| 38 |
+
},
|
| 39 |
"informationPanel": {
|
| 40 |
"groupByEdgeDirection": false,
|
| 41 |
"imageAttribute": false
|
css/style.css
CHANGED
|
@@ -495,4 +495,25 @@ canvas#sigma_bg_1 {
|
|
| 495 |
|
| 496 |
.col {
|
| 497 |
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
}
|
|
|
|
| 495 |
|
| 496 |
.col {
|
| 497 |
margin-bottom: 20px;
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
#attributepane .text .nodeattributes {
|
| 501 |
+
display: block;
|
| 502 |
+
padding: 10px;
|
| 503 |
+
color: #333;
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
#attributepane .text .returntext {
|
| 507 |
+
color: #007AFF;
|
| 508 |
+
cursor: pointer;
|
| 509 |
+
margin: 10px 0;
|
| 510 |
+
padding: 10px 10px 5px 10px;
|
| 511 |
+
font-weight: bold;
|
| 512 |
+
border-bottom: 1px solid #ddd;
|
| 513 |
+
}
|
| 514 |
+
|
| 515 |
+
#attributepane .text .nodeattributes .nodetype {
|
| 516 |
+
font-style: italic;
|
| 517 |
+
color: #666;
|
| 518 |
+
margin-bottom: 8px;
|
| 519 |
}
|
index.html
CHANGED
|
@@ -72,16 +72,16 @@
|
|
| 72 |
|
| 73 |
<div id="attributepane">
|
| 74 |
<div class="text">
|
| 75 |
-
<div class="
|
| 76 |
<div class="nodeattributes">
|
| 77 |
<div class="name">Select a node to see details</div>
|
|
|
|
| 78 |
<div class="data"></div>
|
| 79 |
<div class="p">Connections:</div>
|
| 80 |
<div class="link">
|
| 81 |
<ul></ul>
|
| 82 |
</div>
|
| 83 |
</div>
|
| 84 |
-
<div class="returntext">Return to the full network</div>
|
| 85 |
</div>
|
| 86 |
</div>
|
| 87 |
|
|
|
|
| 72 |
|
| 73 |
<div id="attributepane">
|
| 74 |
<div class="text">
|
| 75 |
+
<div class="returntext">Return to the full network</div>
|
| 76 |
<div class="nodeattributes">
|
| 77 |
<div class="name">Select a node to see details</div>
|
| 78 |
+
<div class="nodetype"></div>
|
| 79 |
<div class="data"></div>
|
| 80 |
<div class="p">Connections:</div>
|
| 81 |
<div class="link">
|
| 82 |
<ul></ul>
|
| 83 |
</div>
|
| 84 |
</div>
|
|
|
|
| 85 |
</div>
|
| 86 |
</div>
|
| 87 |
|
js/main.js
CHANGED
|
@@ -362,64 +362,111 @@ function nodeActive(nodeId) {
|
|
| 362 |
n.attr.originalColor = n.color;
|
| 363 |
|
| 364 |
if (n.id === nodeId) {
|
| 365 |
-
// Make selected node slightly larger
|
| 366 |
n.attr.originalSize = n.size;
|
| 367 |
-
|
|
|
|
| 368 |
} else if (!neighbors[n.id]) {
|
| 369 |
// For non-neighbor nodes, we use a custom attribute to track they should be dimmed
|
| 370 |
// (Sigma v0.1 doesn't support opacity directly)
|
| 371 |
n.attr.dimmed = true;
|
| 372 |
-
// Apply a transparent version of the original color
|
| 373 |
var rgb = getRGBColor(n.color);
|
| 374 |
-
|
|
|
|
| 375 |
}
|
| 376 |
});
|
| 377 |
|
| 378 |
// Apply the same to edges
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
sigmaInstance.iterEdges(function(e) {
|
|
|
|
| 380 |
e.attr = e.attr || {};
|
| 381 |
|
| 382 |
-
// First, store the original color
|
| 383 |
-
if (
|
| 384 |
e.attr.originalColor = e.color;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
}
|
| 386 |
|
| 387 |
-
//
|
| 388 |
-
let
|
| 389 |
|
| 390 |
-
//
|
| 391 |
if (typeof e.source === 'object' && e.source !== null) {
|
| 392 |
-
|
| 393 |
-
} else
|
| 394 |
-
|
| 395 |
}
|
| 396 |
|
| 397 |
-
//
|
| 398 |
if (typeof e.target === 'object' && e.target !== null) {
|
| 399 |
-
|
| 400 |
-
} else
|
| 401 |
-
|
| 402 |
}
|
| 403 |
|
| 404 |
-
// For
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 405 |
if (isConnected) {
|
| 406 |
-
|
| 407 |
-
"Source:", (typeof e.source === 'object' ? e.source.id : e.source),
|
| 408 |
-
"Target:", (typeof e.target === 'object' ? e.target.id : e.target));
|
| 409 |
-
|
| 410 |
-
// IMPORTANT: Make sure the color is the original (non-dimmed) color
|
| 411 |
-
// In Sigma.js v0.1, we need to completely reset the color property
|
| 412 |
-
e.color = e.attr.originalColor;
|
| 413 |
} else {
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
}
|
| 418 |
});
|
| 419 |
|
|
|
|
|
|
|
| 420 |
// Force redraw
|
| 421 |
sigmaInstance.draw(2, 2, 2, 2);
|
| 422 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
// Show node details panel and populate it
|
| 424 |
try {
|
| 425 |
$('#attributepane')
|
|
@@ -430,16 +477,16 @@ function nodeActive(nodeId) {
|
|
| 430 |
'opacity': '1'
|
| 431 |
});
|
| 432 |
|
|
|
|
| 433 |
$('.nodeattributes .name').text(selected.label || selected.id);
|
| 434 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 435 |
let dataHTML = '';
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
attr !== 'label' && attr !== 'hidden' && attr !== 'attr' &&
|
| 439 |
-
typeof selected[attr] !== 'function' && attr !== 'displayX' && attr !== 'displayY' &&
|
| 440 |
-
attr !== 'displaySize' && !attr.startsWith('_')) {
|
| 441 |
-
dataHTML += '<div><strong>' + attr + ':</strong> ' + selected[attr] + '</div>';
|
| 442 |
-
}
|
| 443 |
}
|
| 444 |
|
| 445 |
if (dataHTML === '') dataHTML = '<div>No additional attributes</div>';
|
|
@@ -508,10 +555,16 @@ function nodeNormal() {
|
|
| 508 |
// Restore original edge colors
|
| 509 |
sigmaInstance.iterEdges(function(e) {
|
| 510 |
e.attr = e.attr || {};
|
| 511 |
-
|
|
|
|
| 512 |
e.color = e.attr.originalColor;
|
| 513 |
delete e.attr.originalColor;
|
| 514 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 515 |
});
|
| 516 |
|
| 517 |
// Reset selected node
|
|
|
|
| 362 |
n.attr.originalColor = n.color;
|
| 363 |
|
| 364 |
if (n.id === nodeId) {
|
| 365 |
+
// Make selected node slightly larger based on config
|
| 366 |
n.attr.originalSize = n.size;
|
| 367 |
+
const sizeFactor = config.highlighting?.selectedNodeSizeFactor ?? 1.5;
|
| 368 |
+
n.size = n.size * sizeFactor;
|
| 369 |
} else if (!neighbors[n.id]) {
|
| 370 |
// For non-neighbor nodes, we use a custom attribute to track they should be dimmed
|
| 371 |
// (Sigma v0.1 doesn't support opacity directly)
|
| 372 |
n.attr.dimmed = true;
|
| 373 |
+
// Apply a transparent version of the original color using configured opacity
|
| 374 |
var rgb = getRGBColor(n.color);
|
| 375 |
+
const opacity = config.highlighting?.nodeOpacity ?? 0.2;
|
| 376 |
+
n.color = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacity + ')';
|
| 377 |
}
|
| 378 |
});
|
| 379 |
|
| 380 |
// Apply the same to edges
|
| 381 |
+
let debugCounts = { connected: 0, notConnected: 0 };
|
| 382 |
+
let edgeCount = 0;
|
| 383 |
+
|
| 384 |
+
console.log("Starting edge processing for node:", nodeId);
|
| 385 |
+
|
| 386 |
sigmaInstance.iterEdges(function(e) {
|
| 387 |
+
edgeCount++;
|
| 388 |
e.attr = e.attr || {};
|
| 389 |
|
| 390 |
+
// First, ensure we store the original color (only once)
|
| 391 |
+
if (typeof e.attr.originalColor === 'undefined') {
|
| 392 |
e.attr.originalColor = e.color;
|
| 393 |
+
console.log("Storing original color for edge:", e.id, "Color:", e.color);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
// Store original size for edges (only once)
|
| 397 |
+
if (typeof e.attr.originalSize === 'undefined') {
|
| 398 |
+
e.attr.originalSize = e.size || 1;
|
| 399 |
}
|
| 400 |
|
| 401 |
+
// Get the actual source and target IDs from the edge
|
| 402 |
+
let sourceId, targetId;
|
| 403 |
|
| 404 |
+
// Handle source ID extraction
|
| 405 |
if (typeof e.source === 'object' && e.source !== null) {
|
| 406 |
+
sourceId = e.source.id;
|
| 407 |
+
} else {
|
| 408 |
+
sourceId = String(e.source);
|
| 409 |
}
|
| 410 |
|
| 411 |
+
// Handle target ID extraction
|
| 412 |
if (typeof e.target === 'object' && e.target !== null) {
|
| 413 |
+
targetId = e.target.id;
|
| 414 |
+
} else {
|
| 415 |
+
targetId = String(e.target);
|
| 416 |
}
|
| 417 |
|
| 418 |
+
// For safe comparison, convert nodeId to string as well
|
| 419 |
+
const selectedNodeId = String(nodeId);
|
| 420 |
+
|
| 421 |
+
// Check if this edge is connected to the selected node
|
| 422 |
+
const isConnected = (sourceId === selectedNodeId || targetId === selectedNodeId);
|
| 423 |
+
|
| 424 |
+
// Track counts for debugging
|
| 425 |
if (isConnected) {
|
| 426 |
+
debugCounts.connected++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
} else {
|
| 428 |
+
debugCounts.notConnected++;
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
// Apply different styles based on connection status
|
| 432 |
+
if (isConnected) {
|
| 433 |
+
// Connected edge: make black and increase size
|
| 434 |
+
const highlightColor = config.highlighting?.highlightedEdgeColor ?? '#000000';
|
| 435 |
+
const sizeFactor = config.highlighting?.highlightedEdgeSizeFactor ?? 2;
|
| 436 |
+
e.color = highlightColor;
|
| 437 |
+
e.size = (e.attr.originalSize) * sizeFactor;
|
| 438 |
+
console.log("Edge highlighted:", e.id, "Source:", sourceId, "Target:", targetId, "Color set to:", e.color);
|
| 439 |
+
} else {
|
| 440 |
+
// For non-connected edges, use a very light gray that's almost invisible
|
| 441 |
+
// RGBA doesn't seem to work consistently in Sigma.js v0.1
|
| 442 |
+
e.color = '#ededed'; // Very light gray
|
| 443 |
+
e.size = e.attr.originalSize * 0.5; // Make non-connected edges thinner
|
| 444 |
}
|
| 445 |
});
|
| 446 |
|
| 447 |
+
console.log("Edge processing complete. Total edges:", edgeCount, "Connected:", debugCounts.connected, "Not connected:", debugCounts.notConnected);
|
| 448 |
+
|
| 449 |
// Force redraw
|
| 450 |
sigmaInstance.draw(2, 2, 2, 2);
|
| 451 |
|
| 452 |
+
// Add debug check after redraw to verify edge colors
|
| 453 |
+
setTimeout(function() {
|
| 454 |
+
console.log("Verifying edge colors after redraw:");
|
| 455 |
+
let colorCount = { black: 0, transparent: 0, other: 0 };
|
| 456 |
+
|
| 457 |
+
sigmaInstance.iterEdges(function(e) {
|
| 458 |
+
if (e.color === '#000000') {
|
| 459 |
+
colorCount.black++;
|
| 460 |
+
} else if (e.color.includes('rgba')) {
|
| 461 |
+
colorCount.transparent++;
|
| 462 |
+
} else {
|
| 463 |
+
colorCount.other++;
|
| 464 |
+
}
|
| 465 |
+
});
|
| 466 |
+
|
| 467 |
+
console.log("Edge color counts:", colorCount);
|
| 468 |
+
}, 100);
|
| 469 |
+
|
| 470 |
// Show node details panel and populate it
|
| 471 |
try {
|
| 472 |
$('#attributepane')
|
|
|
|
| 477 |
'opacity': '1'
|
| 478 |
});
|
| 479 |
|
| 480 |
+
// Set the node name/title
|
| 481 |
$('.nodeattributes .name').text(selected.label || selected.id);
|
| 482 |
|
| 483 |
+
// Display the node type
|
| 484 |
+
$('.nodeattributes .nodetype').text(selected.type ? 'Type: ' + selected.type : '');
|
| 485 |
+
|
| 486 |
+
// Simplify data display to only show degree
|
| 487 |
let dataHTML = '';
|
| 488 |
+
if (typeof selected.degree !== 'undefined') {
|
| 489 |
+
dataHTML = '<div><strong>Degree:</strong> ' + selected.degree + '</div>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
}
|
| 491 |
|
| 492 |
if (dataHTML === '') dataHTML = '<div>No additional attributes</div>';
|
|
|
|
| 555 |
// Restore original edge colors
|
| 556 |
sigmaInstance.iterEdges(function(e) {
|
| 557 |
e.attr = e.attr || {};
|
| 558 |
+
// Restore color with explicit check for undefined
|
| 559 |
+
if (typeof e.attr.originalColor !== 'undefined') {
|
| 560 |
e.color = e.attr.originalColor;
|
| 561 |
delete e.attr.originalColor;
|
| 562 |
}
|
| 563 |
+
// Restore size with explicit check for undefined
|
| 564 |
+
if (typeof e.attr.originalSize !== 'undefined') {
|
| 565 |
+
e.size = e.attr.originalSize;
|
| 566 |
+
delete e.attr.originalSize;
|
| 567 |
+
}
|
| 568 |
});
|
| 569 |
|
| 570 |
// Reset selected node
|