@@ -37,6 +37,18 @@ const initGUI = () => {
3737 . onChange ( v => {
3838 graph . d3VelocityDecay ( 1 - v ) ;
3939 } ) ;
40+ const selectionFolder = gui . addFolder ( 'Selection' ) ;
41+
42+ selectionFolder
43+ . add ( model . selection , 'neighborDepth' , 1 , 5 )
44+ . step ( 1 )
45+ . name ( 'Neighbor Depth' )
46+ . onFinishChange ( ( ) => {
47+ update ( m => m ) ;
48+ } ) ;
49+
50+ selectionFolder . add ( model . selection , 'enableRefocus' ) . name ( 'Refocus Enable' ) ;
51+ selectionFolder . add ( model . selection , 'enableZoom' ) . name ( 'Zoom Enable' ) ;
4052
4153 return {
4254 /**
@@ -131,11 +143,38 @@ let model = {
131143 link : 30 ,
132144 velocityDecay : 0.4 ,
133145 } ,
146+ selection : {
147+ neighborDepth : 1 ,
148+ enableRefocus : true ,
149+ enableZoom : true ,
150+ }
134151} ;
135152
136153const graph = ForceGraph ( ) ;
137154const gui = initGUI ( ) ;
138155
156+ function getNeighbors ( nodeId , depth ) {
157+ let neighbors = new Set ( [ nodeId ] ) ;
158+ for ( let i = 0 ; i < depth ; i ++ ) {
159+ let newNeighbors = new Set ( ) ;
160+ for ( const neighborId of neighbors ) {
161+ if ( model . graph . nodeInfo [ neighborId ] ) {
162+ for ( const n of model . graph . nodeInfo [ neighborId ] . neighbors ) {
163+ newNeighbors . add ( n ) ;
164+ }
165+ } else {
166+ // Node is missing from nodeInfo (e.g., has been deleted). Skipping.
167+ // This may make debugging difficult if nodes are unexpectedly missing from highlights.
168+ console . debug ( `getNeighbors: node '${ neighborId } ' not found in nodeInfo, skipping.` ) ;
169+ }
170+ }
171+ for ( const newNeighbor of newNeighbors ) {
172+ neighbors . add ( newNeighbor ) ;
173+ }
174+ }
175+ return neighbors ;
176+ }
177+
139178function update ( patch ) {
140179 const startTime = performance . now ( ) ;
141180 // Apply the patch function to the model..
@@ -145,20 +184,20 @@ function update(patch) {
145184 // compute highlighted elements
146185 const focusNodes = new Set ( ) ;
147186 const focusLinks = new Set ( ) ;
148- if ( model . hoverNode ) {
149- focusNodes . add ( model . hoverNode ) ;
150- const info = model . graph . nodeInfo [ model . hoverNode ] ;
151- info . neighbors . forEach ( neighborId => focusNodes . add ( neighborId ) ) ;
152- info . links . forEach ( link => focusLinks . add ( link ) ) ;
153- }
154- if ( model . selectedNodes ) {
155- model . selectedNodes . forEach ( nodeId => {
156- focusNodes . add ( nodeId ) ;
157- const info = model . graph . nodeInfo [ nodeId ] ;
158- info . neighbors . forEach ( neighborId => focusNodes . add ( neighborId ) ) ;
159- info . links . forEach ( link => focusLinks . add ( link ) ) ;
160- } ) ;
161- }
187+
188+ const nodesToProcess = new Set ( [ ... model . selectedNodes , model . hoverNode ] . filter ( Boolean ) ) ;
189+
190+ nodesToProcess . forEach ( nodeId => {
191+ const neighbors = getNeighbors ( nodeId , model . selection . neighborDepth ) ;
192+ neighbors . forEach ( neighbor => focusNodes . add ( neighbor ) ) ;
193+ } ) ;
194+
195+ model . graph . links . forEach ( link => {
196+ if ( focusNodes . has ( getLinkNodeId ( link . source ) ) && focusNodes . has ( getLinkNodeId ( link . target ) ) ) {
197+ focusLinks . add ( link ) ;
198+ }
199+ } ) ;
200+
162201 model . focusNodes = focusNodes ;
163202 model . focusLinks = focusLinks ;
164203
@@ -616,7 +655,12 @@ try {
616655 const noteId = message . payload ;
617656 const node = graph . graphData ( ) . nodes . find ( node => node . id === noteId ) ;
618657 if ( node ) {
619- graph . centerAt ( node . x , node . y , 300 ) . zoom ( 3 , 300 ) ;
658+ if ( model . selection . enableRefocus ) {
659+ graph . centerAt ( node . x , node . y , 300 ) ;
660+ }
661+ if ( model . selection . enableZoom ) {
662+ graph . zoom ( 3 , 300 ) ;
663+ }
620664 Actions . selectNode ( noteId ) ;
621665 }
622666 break ;
0 commit comments