@@ -121,6 +121,7 @@ const imageFileValidExtnames = new Set(['jpg', 'jpeg', 'png']);
121
121
/** @type {d3.Selection<SVGLineElement, Link, SVGElement, any> } */
122
122
elts . links = svgSub
123
123
. append ( 'g' )
124
+ . attr ( 'class' , 'links-group' )
124
125
. selectAll ( 'line' )
125
126
. data ( data . edges )
126
127
. enter ( )
@@ -395,34 +396,34 @@ function generatePathCoordinatesWithBorder(numSegments, diameter, borderSize) {
395
396
*/
396
397
397
398
function getNodeNetwork ( nodeId ) {
398
- const edges = graph . edges ( nodeId ) ;
399
-
400
399
const node = elts . nodes . filter ( ( { key } ) => key === nodeId ) ;
401
- const links = elts . links . filter ( ( { key } ) => edges . includes ( key ) ) ;
402
-
403
- return {
404
- node,
405
- links,
406
- } ;
400
+ // Links related to this node will be handled by highlight/unlight functions
401
+ return { node } ;
407
402
}
408
403
409
- function setNodesDisplaying ( nodeIds ) {
410
- const toDisplay = nodeIds ;
411
- const toHide = Array . from ( d3 . difference ( allNodeIds , toDisplay ) ) ;
404
+ function setNodesDisplaying ( nodeIdsToShow ) {
405
+ const nodesToShowSet = new Set ( nodeIdsToShow ) ;
406
+ allNodeIds . forEach ( nodeId => {
407
+ const shouldShow = nodesToShowSet . has ( nodeId ) ;
408
+ // Use Graphology attribute for node state
409
+ graph . setNodeAttribute ( nodeId , 'hidden' , ! shouldShow ) ;
410
+ } ) ;
411
+
412
+ // Update the D3 node elements based on the Graphology attribute
413
+ elts . nodes . style ( 'display' , d => graph . getNodeAttribute ( d . key , 'hidden' ) ? 'none' : null ) ;
414
+ elts . labels . style ( 'display' , d => graph . getNodeAttribute ( d . key , 'hidden' ) ? 'none' : null ) ; // Also hide/show labels
412
415
413
- displayNodes ( toDisplay ) ;
414
- hideNodes ( toHide ) ;
416
+ updateLinkVisibilityBasedOnFiltersAndNodes ( ) ;
417
+ setCounters ( ) ; // Update counters after nodes change
415
418
}
416
419
417
420
graph . on ( 'nodeAttributesUpdated' , function ( { key, attributes } ) {
418
421
const { links, node } = getNodeNetwork ( key ) ;
419
422
420
423
if ( attributes . hidden ) {
421
424
node . node ( ) . classList . add ( 'hide' ) ;
422
- links . nodes ( ) . forEach ( ( elt ) => elt . classList . add ( 'hide' ) ) ;
423
425
} else {
424
426
node . node ( ) . classList . remove ( 'hide' ) ;
425
- links . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'hide' ) ) ;
426
427
}
427
428
} ) ;
428
429
@@ -445,13 +446,56 @@ function displayNodes(nodeIds) {
445
446
}
446
447
447
448
function displayNodesAll ( ) {
448
- graph . updateEachNodeAttributes ( ( node , attr ) => ( {
449
- ...attr ,
450
- hidden : false ,
451
- } ) ) ;
449
+ allNodeIds . forEach ( nodeId => {
450
+ graph . setNodeAttribute ( nodeId , 'hidden' , false ) ;
451
+ } ) ;
452
+ elts . nodes . style ( 'display' , null ) ;
453
+ elts . labels . style ( 'display' , null ) ; // Also show labels
454
+
455
+ // Update link visibility after showing all nodes
456
+ updateLinkVisibilityBasedOnFiltersAndNodes ( ) ;
457
+ setCounters ( ) ;
458
+ }
459
+
460
+ // --- Manage Link Visibility ---
461
+
462
+ // Keep track of which link types are currently active based on checkboxes
463
+ let activeLinkTypes = new Set ( Object . keys ( linkTypeList ) ) ; // Initially all active
464
+
465
+ // Function called by filter.js when link checkboxes change
466
+ function updateLinkVisibility ( newActiveLinkTypes ) {
467
+ activeLinkTypes = newActiveLinkTypes ;
468
+ updateLinkVisibilityBasedOnFiltersAndNodes ( ) ;
469
+ }
470
+
471
+ // Central function to update link visibility based on *both* filters and node visibility
472
+ function updateLinkVisibilityBasedOnFiltersAndNodes ( ) {
473
+ console . log ( "updating link visibility" )
474
+ if ( ! linksDisplayToggle ) { // Skip if links are globally toggled off
475
+ console . log ( "early return because links toggled off" )
476
+ elts . links . style ( 'display' , 'none' ) ;
477
+ elts . linkLabels . style ( 'display' , 'none' ) ;
478
+ return ;
479
+ }
480
+
481
+ elts . links . style ( 'display' , d => {
482
+ const typeIsActive = activeLinkTypes . has ( d . attributes . type || 'undefined' ) ;
483
+ const sourceIsVisible = ! graph . getNodeAttribute ( d . source . key , 'hidden' ) ;
484
+ const targetIsVisible = ! graph . getNodeAttribute ( d . target . key , 'hidden' ) ;
485
+ return typeIsActive && sourceIsVisible && targetIsVisible ? null : 'none' ;
486
+ } ) ;
452
487
453
- elts . nodes . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'hide' ) ) ;
454
- elts . links . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'hide' ) ) ;
488
+ if ( ! linkLabelsDisplayToggle ) { // Skip if labels are globally toggled off
489
+ elts . linkLabels . style ( 'display' , 'none' ) ;
490
+ } else {
491
+ elts . linkLabels . style ( 'display' , d => {
492
+ const typeIsActive = activeLinkTypes . has ( d . attributes . type || 'undefined' ) ;
493
+ const sourceIsVisible = ! graph . getNodeAttribute ( d . source . key , 'hidden' ) ;
494
+ const targetIsVisible = ! graph . getNodeAttribute ( d . target . key , 'hidden' ) ;
495
+ return typeIsActive && sourceIsVisible && targetIsVisible ? null : 'none' ;
496
+ } ) ;
497
+ }
498
+ // Note: No need to update counters for links usually, unless you add a link counter UI element.
455
499
}
456
500
457
501
let highlightedNodes = [ ] ;
@@ -467,7 +511,7 @@ function highlightNodes(nodeIds) {
467
511
. forEach ( ( nodeId ) => {
468
512
const { links, node } = getNodeNetwork ( nodeId ) ;
469
513
node . node ( ) . classList . add ( 'highlight' ) ;
470
- links . nodes ( ) . forEach ( ( elt ) => elt . classList . add ( 'highlight' ) ) ;
514
+ elts . links . nodes ( ) . forEach ( ( elt ) => elt . classList . add ( 'highlight' ) ) ;
471
515
} ) ;
472
516
473
517
highlightedNodes = highlightedNodes . concat ( nodeIds ) ;
@@ -487,7 +531,7 @@ function unlightNodes() {
487
531
. forEach ( ( nodeId ) => {
488
532
const { links, node } = getNodeNetwork ( nodeId ) ;
489
533
node . node ( ) . classList . remove ( 'highlight' ) ;
490
- links . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'highlight' ) ) ;
534
+ elts . links . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'highlight' ) ) ;
491
535
} ) ;
492
536
493
537
highlightedNodes = [ ] ;
@@ -498,12 +542,10 @@ function unlightNodes() {
498
542
* @param {boolean } isChecked - 'checked' value send by a checkbox input
499
543
*/
500
544
545
+ let linksDisplayToggle = true ; // Keep track of global link toggle state
501
546
window . linksDisplayToggle = function ( isChecked ) {
502
- if ( isChecked ) {
503
- elts . links . nodes ( ) . forEach ( ( elt ) => elt . classList . remove ( 'hide' ) ) ;
504
- } else {
505
- elts . links . nodes ( ) . forEach ( ( elt ) => elt . classList . add ( 'hide' ) ) ;
506
- }
547
+ linksDisplayToggle = isChecked ;
548
+ updateLinkVisibilityBasedOnFiltersAndNodes ( ) ; // Update visibility when toggled
507
549
} ;
508
550
509
551
/**
@@ -519,12 +561,10 @@ window.labelDisplayToggle = function (isChecked) {
519
561
}
520
562
} ;
521
563
564
+ let linkLabelsDisplayToggle = true ; // Keep track of global label toggle state
522
565
window . linkLabelDisplayToggle = function ( isChecked ) {
523
- if ( isChecked ) {
524
- elts . linkLabels . style ( 'display' , null ) ;
525
- } else {
526
- elts . linkLabels . style ( 'display' , 'none' ) ;
527
- }
566
+ linkLabelsDisplayToggle = isChecked ;
567
+ updateLinkVisibilityBasedOnFiltersAndNodes ( ) ; // Update visibility when toggled
528
568
} ;
529
569
530
570
/**
@@ -660,10 +700,9 @@ hotkeys('c', (e) => {
660
700
export {
661
701
svg ,
662
702
svgSub ,
663
- hideNodes ,
664
- displayNodes ,
665
703
displayNodesAll ,
666
704
setNodesDisplaying ,
705
+ updateLinkVisibility ,
667
706
highlightNodes ,
668
707
unlightNodes ,
669
708
translate ,
0 commit comments