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