@@ -329,41 +329,93 @@ function GraphPanel(a_id, a_frame, a_parent) {
329
329
} ;
330
330
331
331
// Add UI buttons for saving and loading graph state
332
- this . addGraphControls = function ( container ) {
332
+ this . addGraphControls = function ( containerSelector ) {
333
+ const controlsId = "graph-controls" ;
334
+ const helpTipId = "graph-help-tooltip" ;
335
+ let controlsDiv = document . getElementById ( controlsId ) ;
336
+ let helpTip = document . getElementById ( helpTipId ) ;
337
+
333
338
// Create container for graph controls if it doesn't exist
334
- if ( ! document . getElementById ( "graph-controls" ) ) {
335
- const controlsDiv = document . createElement ( "div" ) ;
336
- controlsDiv . id = "graph-controls" ;
339
+ if ( ! controlsDiv ) {
340
+ controlsDiv = document . createElement ( "div" ) ;
341
+ controlsDiv . id = controlsId ;
337
342
controlsDiv . className = "graph-controls" ;
338
343
339
- // Help tooltip
340
- const helpTip = document . createElement ( "div" ) ;
344
+ // "Show Help" button
345
+ const showHelpButton = document . createElement ( "button" ) ;
346
+ showHelpButton . textContent = "Show Help" ;
347
+ showHelpButton . id = "show-graph-help-button" ;
348
+ showHelpButton . addEventListener ( "click" , function ( ) {
349
+ const tipElement = document . getElementById ( helpTipId ) ;
350
+ if ( tipElement ) {
351
+ tipElement . style . display = "block" ;
352
+ }
353
+ } ) ;
354
+ controlsDiv . appendChild ( showHelpButton ) ;
355
+ }
356
+
357
+ // Create help tooltip if it doesn't exist
358
+ if ( ! helpTip ) {
359
+ helpTip = document . createElement ( "div" ) ;
360
+ helpTip . id = helpTipId ;
341
361
helpTip . className = "graph-tooltip" ;
342
- helpTip . innerHTML =
362
+
363
+ const closeButton = document . createElement ( "span" ) ;
364
+ closeButton . innerHTML = "×" ; // X button
365
+ closeButton . className = "graph-tooltip-close" ;
366
+ closeButton . style . position = "absolute" ;
367
+ closeButton . style . top = "5px" ;
368
+ closeButton . style . right = "10px" ;
369
+ closeButton . style . cursor = "pointer" ;
370
+ closeButton . style . pointerEvents = "all" ;
371
+ closeButton . style . fontSize = "20px" ;
372
+ closeButton . addEventListener ( "click" , function ( ) {
373
+ const tipElement = document . getElementById ( helpTipId ) ;
374
+ if ( tipElement ) {
375
+ tipElement . style . display = "none" ;
376
+ }
377
+ } ) ;
378
+ helpTip . appendChild ( closeButton ) ;
379
+
380
+ const helpText = document . createElement ( "div" ) ;
381
+ helpText . innerHTML =
343
382
"<strong>Graph Controls:</strong><br>" +
344
383
"• Drag nodes to move them<br>" +
345
384
"• Shift+Drag to anchor nodes<br>" +
346
385
"• Alt+Drag to move label<br>" +
347
386
"• Right-click for customization options<br>" +
348
387
"• Double-click to toggle anchor" ;
388
+ helpTip . appendChild ( helpText ) ;
389
+ helpTip . style . display = "block" ; // Initially visible
390
+ }
349
391
350
- // Add container to the graph
351
- let graphContainer ;
352
- if ( container ) {
353
- graphContainer = document . querySelector ( container ) ;
354
- } else {
355
- // Make sure we don't double-prefix with #
356
- const selector = a_id . startsWith ( "#" ) ? a_id : "#" + a_id ;
357
- graphContainer = document . querySelector ( selector ) ;
392
+ // Add controls and tooltip to the graph container's parent
393
+ let graphContainerParent ;
394
+ if ( containerSelector ) {
395
+ graphContainerParent = document . querySelector ( containerSelector ) ;
396
+ } else {
397
+ const selector = a_id . startsWith ( "#" ) ? a_id : "#" + a_id ;
398
+ const svgElement = document . querySelector ( selector ) ;
399
+ if ( svgElement && svgElement . parentElement ) {
400
+ graphContainerParent = svgElement . parentElement ;
358
401
}
402
+ }
359
403
360
- if ( graphContainer ) {
361
- graphContainer . style . position = "relative" ;
362
- graphContainer . appendChild ( controlsDiv ) ;
363
- graphContainer . appendChild ( helpTip ) ;
364
- } else {
365
- console . error ( "Graph container not found:" , container || "#" + a_id ) ;
404
+ if ( graphContainerParent ) {
405
+ graphContainerParent . style . position = "relative" ; // Important for absolute positioning of tooltip
406
+ if ( ! document . getElementById ( controlsId ) && controlsDiv ) {
407
+ // Append only if not already there
408
+ graphContainerParent . appendChild ( controlsDiv ) ;
366
409
}
410
+ if ( ! document . getElementById ( helpTipId ) && helpTip ) {
411
+ // Append only if not already there
412
+ graphContainerParent . appendChild ( helpTip ) ;
413
+ }
414
+ } else {
415
+ console . error (
416
+ "Graph container parent not found for controls:" ,
417
+ containerSelector || a_id ,
418
+ ) ;
367
419
}
368
420
} ;
369
421
@@ -901,7 +953,6 @@ function GraphPanel(a_id, a_frame, a_parent) {
901
953
//console.log("PRUNE ALL");
902
954
graphPrune ( node_data , link_data , dest ) ;
903
955
} else if ( dest . row === undefined ) {
904
- //console.log("PRUNE LOCAL EDGE ONLY");
905
956
graphPruneReset ( link_data , node_data ) ;
906
957
loc_trim . push ( link ) ;
907
958
//link.prune = true;
@@ -918,9 +969,6 @@ function GraphPanel(a_id, a_frame, a_parent) {
918
969
}
919
970
graphPrune ( link_data , node_data ) ;
920
971
}
921
-
922
- //graphPruneReset();
923
-
924
972
renderGraph ( ) ;
925
973
}
926
974
} ;
@@ -956,8 +1004,6 @@ function GraphPanel(a_id, a_frame, a_parent) {
956
1004
957
1005
// Called automatically from API module when data records are impacted by edits or annotations
958
1006
this . updateData = function ( a_data ) {
959
- //console.log( "graph updating:", a_data );
960
-
961
1007
let j ,
962
1008
node ,
963
1009
item ,
@@ -967,9 +1013,6 @@ function GraphPanel(a_id, a_frame, a_parent) {
967
1013
dep_cnt ,
968
1014
render = false ;
969
1015
970
- //if ( focus_node_id )
971
- // inst.load( focus_node_id, sel_node_id );
972
-
973
1016
// Scan updates for dependency changes that impact current graph,
974
1017
// if found, reload entire graph from DB
975
1018
// If not reloading, scan for changes to title, annotations, status...
@@ -1124,19 +1167,6 @@ function GraphPanel(a_id, a_frame, a_parent) {
1124
1167
)
1125
1168
. append ( "g" ) ;
1126
1169
// TODO add deselect selected node highlight on double-click
1127
- // .on("dblclick", function () {
1128
- // // Clear selection when double-clicking on empty space
1129
- // if (sel_node) {
1130
- // d3.select(".highlight").attr("class", "select hidden");
1131
- // sel_node = null;
1132
- // sel_node_id = null;
1133
- // panel_info.showSelectedInfo(null);
1134
- // a_parent.updateBtnState();
1135
- // }
1136
- //
1137
- // // Stop event propagation
1138
- // d3.event.stopPropagation();
1139
- // });
1140
1170
1141
1171
defineArrowMarkerDeriv ( svg ) ;
1142
1172
defineArrowMarkerComp ( svg ) ;
0 commit comments