@@ -278,7 +278,26 @@ export default function GraphFunctionalPage() {
278278
279279
280280
281- // Touch: single-finger pan, two-finger pinch zoom (must be after view state is declared)
281+ // Dynamic root id (default ECON 201)
282+ const [ rootId , setRootId ] = useState < string > ( "ECON 201" ) ;
283+
284+ const [ nodes , setNodes ] = useState < SimNode [ ] > ( [ ] ) ;
285+ const [ links , setLinks ] = useState < SimLink [ ] > ( [ ] ) ;
286+ const nodesRef = useRef < SimNode [ ] > ( nodes ) ;
287+ const linksRef = useRef < SimLink [ ] > ( links ) ;
288+ const [ , forceRender ] = useState ( { } ) ;
289+
290+ // Remember which children were open when a coursecard was closed,
291+ // so we can reopen them if that course is reopened later
292+ const [ reopenMemory , setReopenMemory ] = useState < Map < string , Set < string > > > ( new Map ( ) ) ;
293+ const reopenMemoryRef = useRef ( reopenMemory ) ;
294+ useEffect ( ( ) => void ( reopenMemoryRef . current = reopenMemory ) , [ reopenMemory ] ) ;
295+
296+ // View transform (pan/zoom)
297+ const [ view , setView ] = useState ( { x : 0 , y : 0 , k : 1 } ) ;
298+ const viewRef = useRef ( view ) ;
299+ useEffect ( ( ) => void ( viewRef . current = view ) , [ view ] ) ;
300+ // Touch: single-finger pan, two-finger pinch zoom
282301 useEffect ( ( ) => {
283302 const container = containerRef . current ;
284303 if ( ! container ) return ;
@@ -309,7 +328,7 @@ export default function GraphFunctionalPage() {
309328 panActive = false ;
310329 lastDist = getTouchDist ( e . touches [ 0 ] , e . touches [ 1 ] ) ;
311330 lastMid = getTouchMid ( e . touches [ 0 ] , e . touches [ 1 ] ) ;
312- startView = { ...view } ;
331+ startView = { ...viewRef . current } ;
313332 }
314333 } ;
315334 const onTouchMove = ( e : TouchEvent ) => {
@@ -354,27 +373,7 @@ export default function GraphFunctionalPage() {
354373 container . removeEventListener ( "touchmove" , onTouchMove ) ;
355374 container . removeEventListener ( "touchend" , onTouchEnd ) ;
356375 } ;
357- } , [ view ] ) ;
358-
359- // Dynamic root id (default ECON 201)
360- const [ rootId , setRootId ] = useState < string > ( "ECON 201" ) ;
361-
362- const [ nodes , setNodes ] = useState < SimNode [ ] > ( [ ] ) ;
363- const [ links , setLinks ] = useState < SimLink [ ] > ( [ ] ) ;
364- const nodesRef = useRef < SimNode [ ] > ( nodes ) ;
365- const linksRef = useRef < SimLink [ ] > ( links ) ;
366- const [ , forceRender ] = useState ( { } ) ;
367-
368- // Remember which children were open when a coursecard was closed,
369- // so we can reopen them if that course is reopened later
370- const [ reopenMemory , setReopenMemory ] = useState < Map < string , Set < string > > > ( new Map ( ) ) ;
371- const reopenMemoryRef = useRef ( reopenMemory ) ;
372- useEffect ( ( ) => void ( reopenMemoryRef . current = reopenMemory ) , [ reopenMemory ] ) ;
373-
374- // View transform (pan/zoom)
375- const [ view , setView ] = useState ( { x : 0 , y : 0 , k : 1 } ) ;
376- const viewRef = useRef ( view ) ;
377- useEffect ( ( ) => void ( viewRef . current = view ) , [ view ] ) ;
376+ } , [ ] ) ;
378377 const [ isPanning , setIsPanning ] = useState ( false ) ;
379378 // Stable drag state (avoid effect rebinds mid-drag)
380379 const draggingRef = useRef ( false ) ;
0 commit comments