1+ import CloudIcon from "@mui/icons-material/Cloud" ;
12import SaveAltIcon from "@mui/icons-material/SaveAlt" ;
23import {
34 Box ,
45 Checkbox ,
5- Divider ,
66 FormControl ,
77 FormControlLabel ,
88 IconButton ,
99 MenuItem ,
1010 Select ,
11- Toolbar ,
1211 Tooltip ,
1312 Typography ,
1413} from "@mui/material" ;
1514import { scaleLog } from "@visx/scale" ;
1615import { Text } from "@visx/text" ;
1716import { Wordcloud } from "@visx/wordcloud" ;
1817import { toPng } from "html-to-image" ;
19- import { useRef , useState } from "react" ;
18+ import { useCallback , useRef , useState } from "react" ;
2019import { WordFrequencyStat } from "../../../api/openapi/models/WordFrequencyStat.ts" ;
20+ import DATSToolbar from "../../../components/MUI/DATSToolbar.tsx" ;
2121
2222interface WordCloudProps {
2323 width : number ;
2424 height : number ;
2525 words : WordFrequencyStat [ ] ;
26- showControls ?: boolean ;
2726}
2827
2928const colors = [ "#143059" , "#2F6B9A" , "#82a6c2" ] ;
@@ -38,27 +37,29 @@ const fixedValueGenerator = () => 0.5;
3837
3938type SpiralType = "archimedean" | "rectangular" ;
4039
41- export default function WordCloud ( { width, height, words, showControls = true } : WordCloudProps ) {
40+ export default function WordCloud ( { width, height, words } : WordCloudProps ) {
4241 const [ spiralType , setSpiralType ] = useState < SpiralType > ( "archimedean" ) ;
4342 const [ withRotation , setWithRotation ] = useState < boolean > ( false ) ;
4443 const wordCloudRef = useRef < HTMLDivElement > ( null ) ;
4544
46- const fontScale = scaleLog ( {
47- domain : [ Math . min ( ...words . map ( ( w ) => w . count ) ) , Math . max ( ...words . map ( ( w ) => w . count ) ) ] ,
48- range : [ 10 , 100 ] ,
49- } ) ;
45+ const fontSizeSetter = useCallback (
46+ ( datum : { text : string ; value : number } ) => {
47+ const fontScale = scaleLog ( {
48+ domain : [ Math . min ( ...words . map ( ( w ) => w . count ) ) , Math . max ( ...words . map ( ( w ) => w . count ) ) ] ,
49+ range : [ 10 , 100 ] ,
50+ } ) ;
5051
51- const fontSizeSetter = ( datum : { text : string ; value : number } ) => {
52- return fontScale ( datum . value ) ;
53- } ;
52+ return fontScale ( datum . value ) ;
53+ } ,
54+ [ words ] ,
55+ ) ;
5456
5557 const hasWords = words . length > 0 ;
5658
5759 const handleExport = ( ) => {
5860 if ( wordCloudRef . current === null ) return ;
5961
6062 toPng ( wordCloudRef . current , {
61- filter : ( node ) => ! node ?. classList ?. contains ( "word-cloud-controls" ) ,
6263 backgroundColor : "white" ,
6364 } ) . then ( ( dataUrl ) => {
6465 const link = document . createElement ( "a" ) ;
@@ -69,43 +70,25 @@ export default function WordCloud({ width, height, words, showControls = true }:
6970 } ;
7071
7172 return (
72- < Box
73- component = { "div" }
74- sx = { {
75- display : "flex" ,
76- flexDirection : "column" ,
77- alignItems : "center" ,
78- userSelect : "none" ,
79- backgroundColor : "white" ,
80- height : "100%" ,
81- } }
82- >
83- { showControls && (
84- < Toolbar
85- variant = "dense"
86- sx = { { width : "100%" , justifyContent : "flex-end" , gap : 2 , mt : 1 } }
87- className = "word-cloud-controls"
88- >
89- < FormControl size = "small" sx = { { minWidth : 200 } } >
90- < Select value = { spiralType } onChange = { ( e ) => setSpiralType ( e . target . value as SpiralType ) } displayEmpty >
91- < MenuItem value = "archimedean" > Archimedean Spiral</ MenuItem >
92- < MenuItem value = "rectangular" > Rectangular Spiral</ MenuItem >
93- </ Select >
94- </ FormControl >
95- < FormControlLabel
96- control = {
97- < Checkbox checked = { withRotation } onChange = { ( e ) => setWithRotation ( e . target . checked ) } size = "small" />
98- }
99- label = "Enable Rotation"
100- />
101- < Tooltip title = "Export Word Cloud" >
102- < IconButton onClick = { handleExport } size = "small" >
103- < SaveAltIcon />
104- </ IconButton >
105- </ Tooltip >
106- </ Toolbar >
107- ) }
108- < Divider sx = { { width : "100%" , mt : 1 , mb : 1 , boxShadow : 1 } } />
73+ < Box sx = { { display : "flex" , flexDirection : "column" , height : "100%" } } >
74+ < DATSToolbar variant = "dense" >
75+ < FormControl size = "small" sx = { { minWidth : 200 } } >
76+ < Select value = { spiralType } onChange = { ( e ) => setSpiralType ( e . target . value as SpiralType ) } displayEmpty >
77+ < MenuItem value = "archimedean" > Archimedean Spiral</ MenuItem >
78+ < MenuItem value = "rectangular" > Rectangular Spiral</ MenuItem >
79+ </ Select >
80+ </ FormControl >
81+ < FormControlLabel
82+ control = { < Checkbox checked = { withRotation } onChange = { ( e ) => setWithRotation ( e . target . checked ) } size = "small" /> }
83+ label = "Enable Rotation"
84+ />
85+ < Box sx = { { flexGrow : 1 } } />
86+ < Tooltip title = "Export Word Cloud" >
87+ < IconButton onClick = { handleExport } size = "small" >
88+ < SaveAltIcon />
89+ </ IconButton >
90+ </ Tooltip >
91+ </ DATSToolbar >
10992 < Box
11093 ref = { wordCloudRef }
11194 sx = { {
@@ -156,11 +139,17 @@ export default function WordCloud({ width, height, words, showControls = true }:
156139 textAlign : "center" ,
157140 } }
158141 >
142+ < CloudIcon
143+ sx = { {
144+ fontSize : "64px" ,
145+ color : "text.secondary" ,
146+ } }
147+ />
159148 < Typography variant = "h6" color = "text.secondary" gutterBottom >
160149 No words selected
161150 </ Typography >
162151 < Typography variant = "body2" color = "text.secondary" >
163- Select words from the table to visualize them in the word cloud
152+ Select words from the table to visualize them as a word cloud
164153 </ Typography >
165154 </ Box >
166155 ) }
0 commit comments