@@ -64,7 +64,6 @@ import { appStateReducer, initialAppState, ACTION_TYPES } from "./appStateReduce
6464import { ZOOM_TO_SELECTION , DEBUG_LOGGING , DEV_MODE , GRAYSCALE_IMAGES , CAMERA_INFO_HIDDEN } from "./config/features.js" ;
6565import { handleLoadFromCdn , setCdnBaseUrl , getCdnBaseUrl } from "./utils/cdnHelpers.js" ; // getMapUrlFromQuery, clearQueryParams
6666import BgImageModal from "./components/BgImageModal.jsx" ;
67- // import BgImageLayer from "./bg/BgImageLayer";
6867import { useBgImageState } from "./bg/useBgImageState" ;
6968// import { loadImageWithFallback } from "./utils/imageLoader.js";
7069// import { dataUrlOrBlobToWebpDataUrl } from "./utils/imageUtils.js"
@@ -76,7 +75,7 @@ import { saveToLocal, loadFromLocal, saveModeToLocal, loadModeFromLocal, saveUnd
7675// Add new persistence imports
7776import { loadOrientationFromLocal , saveOrientationToLocal , loadCompassVisibleFromLocal , saveCompassVisibleToLocal } from './persistence/index.js' ;
7877import { renameNode } from "./graph/ops.js" ; // edgeId
79- import { printDebug } from "./utils/debug.js" ;
78+ import { printDebug , printWarn } from "./utils/debug.js" ;
8079// import { rotateNodesAndCompass } from './utils/rotation.js'; // REFACTOR STEP 1: Removed rotateCompassOnly - now using graphOps.handleRotateRight
8180import { getCanEditFromQuery , hasAnyQueryParams } from "./utils/mapHelpers.js" ;
8281
@@ -418,12 +417,20 @@ function App() {
418417 setCdnBaseUrl ( cdnBaseUrl ) ;
419418 } , [ cdnBaseUrl ] ) ;
420419
421- // Save camera state to localStorage (kept as-is )
420+ // Save camera state to localStorage (debounced to prevent excessive writes )
422421 useEffect ( ( ) => {
423- localStorage . setItem ( "shipLogCamera" , JSON . stringify ( {
424- zoom : zoomLevel ,
425- position : cameraPosition
426- } ) ) ;
422+ const timeoutId = setTimeout ( ( ) => {
423+ try {
424+ localStorage . setItem ( "shipLogCamera" , JSON . stringify ( {
425+ zoom : zoomLevel ,
426+ position : cameraPosition
427+ } ) ) ;
428+ } catch ( e ) {
429+ printWarn ( 'Failed to save camera to localStorage:' , e ) ;
430+ }
431+ } , 200 ) ; // Save at most once every 200ms
432+
433+ return ( ) => clearTimeout ( timeoutId ) ;
427434 } , [ zoomLevel , cameraPosition ] ) ;
428435
429436 // Save mode to localStorage
@@ -1045,6 +1052,17 @@ function App() {
10451052 const memoSelectedEdgeIds = useMemo ( ( ) => selectedEdgeIds , [ selectedEdgeIds ] ) ;
10461053 const memoCameraPosition = useMemo ( ( ) => cameraPosition , [ cameraPosition ] ) ;
10471054 const memoNotes = useMemo ( ( ) => graphData . notes , [ graphData . notes ] ) ;
1055+
1056+ // Memoize background image object to prevent infinite re-renders
1057+ const memoBgImage = useMemo ( ( ) => {
1058+ if ( ! bgImage . imageUrl ) return null ;
1059+ return {
1060+ imageUrl : bgImage . imageUrl ,
1061+ visible : bgImage . visible ,
1062+ opacity : bgImage . opacity ,
1063+ calibration : bgCalibration
1064+ } ;
1065+ } , [ bgImage . imageUrl , bgImage . visible , bgImage . opacity , bgCalibration ] ) ;
10481066
10491067 const handleLoadFromCdnButton = useCallback ( ( cdnBaseUrlArg ) => {
10501068 handleLoadFromCdn ( {
@@ -1124,6 +1142,9 @@ useEffect(() => {
11241142 </ div >
11251143 </ div >
11261144
1145+ { /* Background image underlay - DISABLED: Now integrated into Cytoscape canvas */ }
1146+ { /* Background now renders as a Cytoscape node for perfect sync with pan/zoom */ }
1147+ { /* See CytoscapeGraph bgImage prop and bgNodeAdapter.js */ }
11271148
11281149 { canEdit && (
11291150 < GraphControls
@@ -1330,14 +1351,7 @@ useEffect(() => {
13301351 showNoteCountOverlay = { showNoteCountOverlay }
13311352 notes = { memoNotes }
13321353 visited = { visited } /* pass visited to drive unseen badges */
1333- // Background node integration
1334- bgNodeProps = { {
1335- imageUrl : bgImage ?. imageUrl || '' ,
1336- visible : ! ! bgImage ?. visible ,
1337- opacity : Number . isFinite ( bgImage ?. opacity ) ? bgImage . opacity : 100 ,
1338- calibration : bgCalibration || { tx : 0 , ty : 0 , s : 1 }
1339- } }
1340-
1354+ bgImage = { memoBgImage }
13411355 />
13421356
13431357 { compassVisible && (
0 commit comments