@@ -33,6 +33,7 @@ import { setNoteCountsVisible, refreshPositions as refreshOverlayPositions } fro
3333import { printDebug , printError , printWarn } from "../utils/debug.js" ;
3434import { TEST_ICON_SVG } from "../constants/testAssets.js" ;
3535import { GRAYSCALE_IMAGES } from "../config/features.js" ;
36+ import { ensureBgNode , removeBgNode } from "../graph/bgNodeAdapter.js" ;
3637
3738function CytoscapeGraph ( {
3839 nodes = [ ] ,
@@ -65,7 +66,8 @@ function CytoscapeGraph({
6566 showNoteCountOverlay = false ,
6667 notes = { } ,
6768 visited = { nodes : new Set ( ) , edges : new Set ( ) } ,
68- onCytoscapeInstanceReady
69+ onCytoscapeInstanceReady,
70+ bgNodeProps = { imageUrl : '' , visible : false , opacity : 100 , calibration : { tx : 0 , ty : 0 , s : 1 } }
6971} ) {
7072
7173 const containerRef = useRef ( null ) ;
@@ -212,6 +214,7 @@ function CytoscapeGraph({
212214 if ( cy . _eventCleanup ) cy . _eventCleanup ( ) ;
213215 if ( cy . _edgeCountCleanup ) cy . _edgeCountCleanup ( ) ;
214216 if ( cy . _viewportCleanup ) cy . _viewportCleanup ( ) ;
217+ try { removeBgNode ( cy ) ; } catch { /* noop */ }
215218
216219 cy . destroy ( ) ;
217220 } catch {
@@ -222,6 +225,34 @@ function CytoscapeGraph({
222225 // eslint-disable-next-line react-hooks/exhaustive-deps
223226 } , [ ] ) ; // mount once
224227
228+ // ------------------- Background image node sync -------------------
229+ useEffect ( ( ) => {
230+ const cy = cyRef . current ;
231+ if ( ! cy ) return ;
232+ const { imageUrl, visible, opacity, calibration } = bgNodeProps || { } ;
233+
234+ // Create/update or remove the background node
235+ ensureBgNode ( cy , {
236+ imageUrl,
237+ visible,
238+ opacity,
239+ calibration
240+ } ) ;
241+
242+ // Nothing special required on cleanup; node is removed when invisible.
243+ // Still, if component unmounts while visible, clean it up.
244+ return ( ) => {
245+ // Only remove on unmount (don’t fight with other effects)
246+ if ( cy ?. destroyed && ! cy . destroyed ( ) ) {
247+ // noop (we remove on visibility false in ensureBgNode)
248+ }
249+ } ;
250+ // Include a stable calibration dep (stringify small object is fine here)
251+ } , [
252+ cyRef ,
253+ bgNodeProps
254+ ] ) ;
255+
225256 // ------------------- Re-wire events when handlers/mode change -------------------
226257 useEffect ( ( ) => {
227258 printDebug ( `🔌 [CytoscapeGraph] Event handlers changed, re-wiring events` ) ;
@@ -373,6 +404,7 @@ function CytoscapeGraph({
373404
374405 // Optional: refresh layout on large changes
375406 if ( updatedCount > 0 && majorChange ) {
407+
376408 syncElements ( cy , { nodes, edges, mapName, cdnBaseUrl } , { mode } ) ;
377409 try { updateOverlays ( cy , notesRef . current , showNoteCountOverlay , visitedRef . current , mode ) ; } catch {
378410 printWarn ( 'Failed to update edge count node positions after major position-only update' ) ;
0 commit comments