@@ -1692,7 +1692,9 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
16921692 } ) ;
16931693 for ( let i = 0 ; i < numYears ; i ++ ) {
16941694 const yearLabelY = yearYOffset [ i ] + yearBandHeights [ i ] / 2 ;
1695- const label = g . append ( 'text' )
1695+ // Active-year highlighting (font-weight) is applied by the focusYear
1696+ // post-render effect, so toggling focus does not require a full redraw.
1697+ g . append ( 'text' )
16961698 . attr ( 'x' , - margin . left + 12 )
16971699 . attr ( 'y' , yearLabelY )
16981700 . text ( `${ tr [ language ] . year } ${ i + 1 } ` )
@@ -1707,11 +1709,6 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
17071709 event . stopPropagation ( ) ;
17081710 setFocusYear ( ( prev ) => ( prev === i + 1 ? null : i + 1 ) ) ;
17091711 } ) ;
1710-
1711- // Visually indicate active year label
1712- if ( focusYear === i + 1 ) {
1713- label . attr ( 'font-weight' , 600 ) ;
1714- }
17151712 }
17161713
17171714 // Draw arrows for prerequisites using stored positions
@@ -2368,17 +2365,9 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
23682365 if ( arrow . style . dash ) path . attr ( 'stroke-dasharray' , arrow . style . dash ) ;
23692366 } ) ;
23702367
2371- // style initial visibility based on layers state
2372- // note: this will run on each redraw so it's safe to set here
2373- container . selectAll ( '.study-period' ) . style ( 'display' , layers . studyPeriods ? '' : 'none' ) ;
2374- container . selectAll ( '.exam-period-rect' ) . style ( 'display' , layers . examPeriods ? '' : 'none' ) ;
2375- container . selectAll ( '.reexam-period-rect' ) . style ( 'display' , layers . reexamPeriods ? '' : 'none' ) ;
2376- // course blocks and labels
2377- container . selectAll ( '.course-block' ) . style ( 'display' , layers . courseBars ? '' : 'none' ) ;
2378- container . selectAll ( '.course-label' ) . style ( 'display' , layers . courseBars ? '' : 'none' ) ;
2379- // exam/reexam markers
2380- container . selectAll ( '.exam-dot' ) . style ( 'display' , layers . exams ? '' : 'none' ) ;
2381- container . selectAll ( '.reexam-dot' ) . style ( 'display' , layers . reexams ? '' : 'none' ) ;
2368+ // Initial layer visibility is applied by the dedicated `layers` post-render
2369+ // effect below; that effect runs after this one on every render and covers
2370+ // every selector. No need to duplicate the work here.
23822371
23832372 // create a dedicated top layer group so markers always render above chart elements
23842373 const topLayer = svg . append ( 'g' )
@@ -2439,7 +2428,11 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
24392428 . on ( 'mouseout' , ( ) => tooltip . style ( 'display' , 'none' ) ) ;
24402429 } ) ;
24412430
2442- } , [ courses , layers , language , selectedOptionPerGroup , focusYear , cosmetics , programCode , programName , studyplanUrl , getCourseColors ] ) ;
2431+ // `layers` and `focusYear` are intentionally NOT in this dep list. Their
2432+ // visual effects (visibility toggles, year-label highlight) are applied by
2433+ // the dedicated post-render effects below, which keeps a layer toggle or
2434+ // year-focus click from triggering a full ~3 000-call SVG rebuild.
2435+ } , [ courses , language , selectedOptionPerGroup , cosmetics , programCode , programName , studyplanUrl , getCourseColors ] ) ;
24432436
24442437 // Removed popup; outside clicks handled by svg.on('click') above
24452438
@@ -2659,7 +2652,9 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
26592652 container . selectAll ( '.exam-dot' ) . style ( 'opacity' , null ) ;
26602653 container . selectAll ( '.reexam-dot' ) . style ( 'opacity' , null ) ;
26612654 container . selectAll ( '.prereq-path' ) . style ( 'opacity' , null ) ;
2662- container . selectAll < SVGTextElement , unknown > ( '.year-label' ) . style ( 'opacity' , null ) ;
2655+ container . selectAll < SVGTextElement , unknown > ( '.year-label' )
2656+ . style ( 'opacity' , null )
2657+ . attr ( 'font-weight' , 400 ) ;
26632658 return ;
26642659 }
26652660
@@ -2710,11 +2705,15 @@ const TimelineVisualization = forwardRef(function TimelineVisualization({ course
27102705 container . selectAll < SVGPathElement , unknown > ( '.prereq-path' )
27112706 . style ( 'opacity' , '0.1' ) ;
27122707
2713- // Fade year labels not in focus
2708+ // Fade year labels not in focus and bold the active one.
27142709 container . selectAll < SVGTextElement , unknown > ( '.year-label' )
27152710 . style ( 'opacity' , function ( ) {
27162711 const year = parseInt ( ( this as Element ) . getAttribute ( 'data-year' ) || '0' ) ;
27172712 return year === focusYear ? '1' : '0.3' ;
2713+ } )
2714+ . attr ( 'font-weight' , function ( ) {
2715+ const year = parseInt ( ( this as Element ) . getAttribute ( 'data-year' ) || '0' ) ;
2716+ return year === focusYear ? 600 : 400 ;
27182717 } ) ;
27192718 } , [ focusYear , focusCourse , courses ] ) ;
27202719
0 commit comments