1- // VisualizationModal.jsx - 확대/축소 상태 유지 버전
1+ // VisualizationModal.jsx - AnimationFactory 감지 로직 활용 버전
22import React , { useState , useEffect , useCallback , useRef } from 'react' ;
33import ReactDOM from 'react-dom' ;
44import AnimationFactory from './AnimationFactory' ;
@@ -104,15 +104,14 @@ const ControlButton = ({ onClick, disabled, variant = 'default', children, title
104104 ) ;
105105} ;
106106
107- // 🎮 시각화 컨트롤 (확대/축소 제거)
107+ // 🎮 시각화 컨트롤
108108const VisualizationControls = ( {
109109 isPlaying, currentStep, totalSteps, speed,
110110 onPlay, onPause, onStepBack, onStepForward, onReset, onSpeedChange, onStepChange,
111111 theme
112112 } ) => {
113113 return (
114114 < div style = { { display : 'flex' , alignItems : 'center' , gap : '12px' , flexWrap : 'wrap' } } >
115- { /* 재생 컨트롤 */ }
116115 < ControlButton
117116 onClick = { isPlaying ? onPause : onPlay }
118117 disabled = { totalSteps === 0 }
@@ -135,7 +134,6 @@ const VisualizationControls = ({
135134 ⏮ 처음
136135 </ ControlButton >
137136
138- { /* 단계 표시 */ }
139137 < div style = { {
140138 display : 'flex' ,
141139 alignItems : 'center' ,
@@ -173,7 +171,6 @@ const VisualizationControls = ({
173171 < span style = { { fontSize : '12px' , color : theme . colors . textLight } } > / { totalSteps } </ span >
174172 </ div >
175173
176- { /* 속도 컨트롤 */ }
177174 < div style = { {
178175 display : 'flex' ,
179176 alignItems : 'center' ,
@@ -212,7 +209,7 @@ const VisualizationControls = ({
212209} ;
213210
214211// 📊 정보 패널
215- const InfoPanel = ( { data, currentStep, totalSteps, theme } ) => {
212+ const InfoPanel = ( { data, currentStep, totalSteps, animationType , theme } ) => {
216213 const InfoCard = ( { title, icon, children } ) => (
217214 < div style = { {
218215 background : theme . colors . card ,
@@ -244,6 +241,24 @@ const InfoPanel = ({ data, currentStep, totalSteps, theme }) => {
244241 ] ;
245242 const hasComplexityData = complexityItems . some ( item => item . value && item . value !== '-' ) ;
246243
244+ // 🎯 감지된 알고리즘 타입 표시
245+ const getAlgorithmLabel = ( type ) => {
246+ const labels = {
247+ 'bubble-sort' : '버블 정렬' ,
248+ 'selection-sort' : '선택 정렬' ,
249+ 'insertion-sort' : '삽입 정렬' ,
250+ 'merge-sort' : '병합 정렬' ,
251+ 'quick-sort' : '퀵 정렬' ,
252+ 'binary-tree' : '이진 트리' ,
253+ 'heap' : '힙' ,
254+ 'graph' : '그래프' ,
255+ 'linked-list' : '연결 리스트' ,
256+ 'recursion' : '재귀' ,
257+ 'variables' : '변수'
258+ } ;
259+ return labels [ type ] || type ;
260+ } ;
261+
247262 return (
248263 < div style = { {
249264 display : 'flex' ,
@@ -280,6 +295,7 @@ const InfoPanel = ({ data, currentStep, totalSteps, theme }) => {
280295 < InfoCard title = "시각화 정보" icon = "📊" >
281296 < div style = { { display : 'flex' , flexDirection : 'column' , gap : '6px' } } >
282297 { [
298+ { label : '알고리즘' , value : getAlgorithmLabel ( animationType ) } ,
283299 { label : '이벤트 수' , value : `${ data ?. events ?. length || 0 } 개` } ,
284300 { label : '현재 이벤트' , value : currentEvent ?. kind || '-' }
285301 ] . map ( ( item , index ) => (
@@ -400,43 +416,6 @@ const AnimationDisplay = ({ data, currentStep, totalSteps, animationType, isPlay
400416 ) ;
401417} ;
402418
403- // 알고리즘 감지 (기존 로직 유지)
404- const detectAlgorithmFromEvents = ( events ) => {
405- if ( ! events || events . length === 0 ) return 'variables' ;
406-
407- for ( let i = 0 ; i < events . length ; i ++ ) {
408- const event = events [ i ] ;
409- if ( event . viz ?. type ) {
410- const vizType = event . viz . type . toLowerCase ( ) ;
411- if ( vizType === 'heap' ) return 'heap' ;
412- if ( vizType === 'bst' || vizType === 'tree' ) return 'binary-tree' ;
413- if ( vizType === 'graph' ) return 'graph' ;
414- if ( vizType === 'list' || vizType === 'linkedlist' ) return 'linked-list' ;
415- }
416- }
417-
418- const heapEvent = events . find ( e => e . kind === 'ds_op' && e . target ?. toLowerCase ( ) . includes ( 'heap' ) ) ;
419- if ( heapEvent ) return 'heap' ;
420-
421- const listEvent = events . find ( e => e . kind === 'ds_op' && e . target && ( e . target . toLowerCase ( ) . includes ( 'list' ) || e . target . toLowerCase ( ) . includes ( 'linkedlist' ) || e . target . toLowerCase ( ) . includes ( 'node' ) ) ) ;
422- if ( listEvent ) return 'linked-list' ;
423-
424- const graphEvent = events . find ( e => e . kind === 'ds_op' && e . target && ( e . target . toLowerCase ( ) . includes ( 'graph' ) || e . target . toLowerCase ( ) . includes ( 'adj' ) ) ) ;
425- if ( graphEvent ) return 'graph' ;
426-
427- const treeEvent = events . find ( e => e . kind === 'ds_op' && e . target && ( e . target . toLowerCase ( ) . includes ( 'tree' ) || e . target . toLowerCase ( ) . includes ( 'bst' ) ) ) ;
428- if ( treeEvent ) return 'binary-tree' ;
429-
430- const recursionEvents = events . filter ( e => e . kind === 'call' && e . viz ?. recursionDepth !== undefined ) ;
431- if ( recursionEvents . length > 0 ) return 'recursion' ;
432-
433- const hasCompare = events . some ( e => e . kind === 'compare' ) ;
434- const hasSwap = events . some ( e => e . kind === 'swap' ) ;
435- if ( hasCompare && hasSwap ) return 'bubble-sort' ;
436-
437- return 'variables' ;
438- } ;
439-
440419// 📦 메인 모달
441420const VisualizationModal = ( {
442421 isOpen,
@@ -457,6 +436,24 @@ const VisualizationModal = ({
457436 const theme = getTheme ( isDark ) ;
458437 const animationControls = useAnimationControls ( totalSteps ) ;
459438
439+ // ✅ AnimationFactory의 감지 로직 활용 (한 번만 실행)
440+ const detectAndSetAnimationType = useCallback ( ( events ) => {
441+ if ( ! events || events . length === 0 ) {
442+ console . log ( '⚠️ 이벤트가 없어 기본값 사용' ) ;
443+ return 'variables' ;
444+ }
445+
446+ try {
447+ // 🎯 AnimationFactory의 고급 감지 로직 사용
448+ const detectedType = AnimationFactory . detectAnimationType ( events ) ;
449+ console . log ( '✅ AnimationFactory 감지 결과:' , detectedType ) ;
450+ return detectedType ;
451+ } catch ( error ) {
452+ console . error ( '❌ 알고리즘 감지 실패:' , error ) ;
453+ return 'variables' ;
454+ }
455+ } , [ ] ) ;
456+
460457 // 데이터 가져오기
461458 const fetchVisualizationData = async ( ) => {
462459 if ( ! code ?. trim ( ) && ! preloadedJsonData ) {
@@ -474,7 +471,7 @@ const VisualizationModal = ({
474471 const steps = preloadedJsonData . events ?. length || 0 ;
475472 setTotalSteps ( steps ) ;
476473 animationControls . reset ( ) ;
477- const detectedType = detectAlgorithmFromEvents ( preloadedJsonData . events ) ;
474+ const detectedType = detectAndSetAnimationType ( preloadedJsonData . events ) ;
478475 setAnimationType ( detectedType ) ;
479476 } catch ( err ) {
480477 setError ( err . message ) ;
@@ -495,7 +492,7 @@ const VisualizationModal = ({
495492 const steps = parsedJson . events ?. length || 0 ;
496493 setTotalSteps ( steps ) ;
497494 animationControls . reset ( ) ;
498- const detectedType = detectAlgorithmFromEvents ( parsedJson . events ) ;
495+ const detectedType = detectAndSetAnimationType ( parsedJson . events ) ;
499496 setAnimationType ( detectedType ) ;
500497 } catch ( err ) {
501498 setError ( `JSON 파싱 오류: ${ err . message } ` ) ;
@@ -514,7 +511,7 @@ const VisualizationModal = ({
514511 const steps = visualizationData . events ?. length || 0 ;
515512 setTotalSteps ( steps ) ;
516513 animationControls . reset ( ) ;
517- const detectedType = detectAlgorithmFromEvents ( visualizationData . events ) ;
514+ const detectedType = detectAndSetAnimationType ( visualizationData . events ) ;
518515 setAnimationType ( detectedType ) ;
519516 } catch ( err ) {
520517 setError ( err . message ) ;
@@ -529,7 +526,6 @@ const VisualizationModal = ({
529526 }
530527 } , [ isOpen , preloadedJsonData ] ) ;
531528
532- // 모달이 닫힐 때만 초기화
533529 useEffect ( ( ) => {
534530 if ( ! isOpen ) {
535531 setData ( null ) ;
@@ -687,10 +683,18 @@ const VisualizationModal = ({
687683 minHeight : 0
688684 } }
689685 className = "visualization-scrollbar" >
690- { data && < InfoPanel data = { data } currentStep = { animationControls . currentStep } totalSteps = { totalSteps } theme = { theme } /> }
686+ { data && (
687+ < InfoPanel
688+ data = { data }
689+ currentStep = { animationControls . currentStep }
690+ totalSteps = { totalSteps }
691+ animationType = { animationType }
692+ theme = { theme }
693+ />
694+ ) }
691695 </ div >
692696
693- { /* 오른쪽: 애니메이션만 */ }
697+ { /* 오른쪽: 애니메이션 */ }
694698 < div style = { {
695699 background : theme . colors . card ,
696700 overflowY : 'auto' ,
0 commit comments