11import React , { useEffect , useRef } from "react" ;
22import * as d3 from "d3" ;
33
4- const BubbleChart = ( { keywordCounts } ) => {
4+ const BubbleChart = ( { keywordCounts, onKeywordClick } ) => {
55 const svgRef = useRef ( ) ;
66
77 useEffect ( ( ) => {
88 if ( ! keywordCounts || Object . keys ( keywordCounts ) . length === 0 ) return ;
99
1010 d3 . select ( svgRef . current ) . selectAll ( "*" ) . remove ( ) ; // 기존 차트 제거
1111
12- const width = 600 ,
13- height = 500 ;
12+ const width = 800 ,
13+ height = 700 ;
1414
1515 // 🔹 데이터 유효성 검사 (NaN 제거)
1616 const validData = Object . entries ( keywordCounts )
@@ -48,12 +48,18 @@ const BubbleChart = ({ keywordCounts }) => {
4848 . enter ( )
4949 . append ( "g" )
5050 . attr ( "class" , "node" )
51- . attr ( "transform" , ( d ) => `translate(${ d . x || 0 } , ${ d . y || 0 } )` ) ; // 🔹 NaN 방지
51+ . attr ( "transform" , ( d ) => `translate(${ d . x || 0 } , ${ d . y || 0 } )` )
52+ . style ( "cursor" , "pointer" )
53+ . on ( "click" , ( event , d ) => {
54+ if ( onKeywordClick ) {
55+ onKeywordClick ( d . data . name ) ; // ✅ 클릭 시 검색 API 호출
56+ }
57+ } ) ;
5258
5359 nodes
5460 . append ( "circle" )
55- . attr ( "r" , ( d ) => d . r || 10 ) // 🔹 NaN 방지: 최소 크기 지정
56- . style ( "fill" , ( d ) => colorScale ( d . data . size ) ) // ✅ 값이 클수록 진한 파란색 적용
61+ . attr ( "r" , ( d ) => d . r || 10 )
62+ . style ( "fill" , ( d ) => colorScale ( d . data . size ) )
5763 . style ( "opacity" , 0.8 )
5864 . transition ( )
5965 . duration ( 1000 )
@@ -66,7 +72,7 @@ const BubbleChart = ({ keywordCounts }) => {
6672 . style ( "fill" , "#fff" )
6773 . style ( "font-size" , ( d ) => Math . max ( 10 , d . r / 4 ) + "px" )
6874 . text ( ( d ) => d . data . name ) ;
69- } , [ keywordCounts ] ) ;
75+ } , [ keywordCounts , onKeywordClick ] ) ;
7076
7177 return < svg ref = { svgRef } /> ;
7278} ;
0 commit comments