@@ -5,20 +5,20 @@ import { CHART_RADIUS, CHART_SIZE } from './constants';
55import { generateArrayOfUniqColors } from './colorsGenerator' ;
66import './UserProjectPieChart.css' ;
77
8- export const PieChart = ( {
8+ export function PieChart ( {
99 tasksData = [ ] , // New array format: [{ projectId: "123", projectName: "Project A", totalTime: 10.5 }, ...]
1010 pieChartId,
1111 darkMode,
12- projectsData = [ ]
13- } ) => {
14-
15- if ( ! tasksData || tasksData . length === 0 ) return < div > Loading</ div > ;
12+ projectsData = [ ] ,
13+ } ) {
1614 const [ totalHours , setTotalHours ] = useState ( 0 ) ;
1715 const colors = useMemo ( ( ) => generateArrayOfUniqColors ( tasksData ?. length ) , [ tasksData ] ) ;
1816 const color = useMemo ( ( ) => d3 . scaleOrdinal ( ) . range ( colors ) , [ colors ] ) ;
1917
2018 const [ togglePercentage , setTogglePercentage ] = useState ( false ) ;
21- const [ selectedProjects , setSelectedProjects ] = useState ( tasksData ?. map ( project => project . projectId ) ) ;
19+ const [ selectedProjects , setSelectedProjects ] = useState (
20+ tasksData ?. map ( project => project . projectId ) ,
21+ ) ;
2222
2323 const handleTogglePercentage = ( ) => {
2424 setTogglePercentage ( prev => {
@@ -27,13 +27,14 @@ export const PieChart = ({
2727 if ( ! newToggleState ) {
2828 setSelectedProjects ( tasksData ?. map ( project => project . projectId ) ) ;
2929 }
30+ return newToggleState ;
3031 } ) ;
3132 } ;
32- const calculateTotalHours = ( projectsData , tasksData ) => {
33- const totalTaskTime = tasksData ?. reduce ( ( sum , project ) => sum + project . totalTime , 0 ) ;
34- const projectsDataTime = projectsData . reduce ( ( sum , project ) => sum + project . totalTime , 0 ) ;
35- return totalTaskTime + projectsDataTime ;
36- }
33+ const calculateTotalHours = ( projectsdata , tasksdata ) => {
34+ const totalTaskTime = tasksdata ?. reduce ( ( sum , project ) => sum + project . totalTime , 0 ) ;
35+ const projectsDataTime = projectsdata . reduce ( ( sum , project ) => sum + project . totalTime , 0 ) ;
36+ return totalTaskTime + projectsDataTime ;
37+ } ;
3738
3839 const handleProjectClick = projectId => {
3940 if ( togglePercentage ) {
@@ -46,7 +47,7 @@ export const PieChart = ({
4647 } ;
4748
4849 const getCreateSvgPie = totalValue => {
49- if ( totalValue === 0 ) return ;
50+ if ( totalValue === 0 ) return ;
5051 // Clear existing SVG before creating new one
5152 d3 . select ( `#pie-chart-${ pieChartId } ` ) . remove ( ) ;
5253 const svg = d3
@@ -57,55 +58,67 @@ export const PieChart = ({
5758 . attr ( 'height' , CHART_SIZE )
5859 . append ( 'g' )
5960 . attr ( 'transform' , `translate(${ CHART_SIZE / 2 } , ${ CHART_SIZE / 2 } )` ) ;
60-
61+
6162 const displayValue = togglePercentage
62- // ? (selectedProjects.reduce((sum, projectId) => {
63- // const project = tasksData.find(p => p.projectId === projectId);
64- // return sum + (project ? project.totalTime : 0);
65- // }, 0) / totalValue) * 100
66- // : totalValue;
67- ? ( totalValue / calculateTotalHours ( projectsData , tasksData ) ) * 100
68- : totalValue ;
69-
63+ ? // ? (selectedProjects.reduce((sum, projectId) => {
64+ // const project = tasksData.find(p => p.projectId === projectId);
65+ // return sum + (project ? project.totalTime : 0);
66+ // }, 0) / totalValue) * 100
67+ // : totalValue;
68+ ( totalValue / calculateTotalHours ( projectsData , tasksData ) ) * 100
69+ : totalValue ;
70+
7071 svg
7172 . append ( 'text' )
7273 . attr ( 'text-anchor' , 'middle' )
7374 . style ( 'fill' , darkMode ? 'white' : 'black' )
7475 . text (
7576 togglePercentage
76- ? `${ displayValue . toFixed ( 2 ) } % of ${ calculateTotalHours ( projectsData , tasksData ) . toFixed ( 2 ) } `
77+ ? `${ displayValue . toFixed ( 2 ) } % of ${ calculateTotalHours ( projectsData , tasksData ) . toFixed (
78+ 2 ,
79+ ) } `
7780 : totalValue . toFixed ( 2 ) ,
7881 ) ;
79-
82+
8083 svg
8184 . append ( 'foreignObject' )
8285 . attr ( 'x' , - 40 )
8386 . attr ( 'y' , 10 )
8487 . attr ( 'width' , 80 )
8588 . attr ( 'height' , 40 )
8689 . append ( 'xhtml:div' )
87- . html ( `
90+ . html (
91+ `
8892 <label class="switch">
8993 <input type="checkbox" ${ togglePercentage ? 'checked' : '' } />
9094 <span class="slider"></span>
9195 </label>
92- ` )
96+ ` ,
97+ )
9398 . select ( 'input' )
9499 . on ( 'change' , handleTogglePercentage ) ; // Use the existing React handler
95100
96- return svg ;
101+ // return svg;
97102 } ;
98-
103+
99104 const pie = d3 . pie ( ) . value ( d => d . totalTime ) ;
100105
101106 useEffect ( ( ) => {
102107 if ( ! tasksData || tasksData . length === 0 ) {
103- return ;
104- }
108+ return undefined ;
109+ }
105110 const totalValue = tasksData ?. reduce ( ( sum , project ) => sum + project . totalTime , 0 ) ;
106- if ( totalValue === 0 ) return ;
111+
107112 setTotalHours ( totalValue ) ;
108113
114+ if ( totalValue === 0 ) {
115+ return undefined ;
116+ }
117+
118+ if ( ! tasksData || tasksData . length === 0 ) {
119+ return < div > Loading</ div > ;
120+ }
121+
109122 const dataReady = pie ( tasksData ) ;
110123
111124 let div = d3 . select ( '.tooltip-donut' ) ;
@@ -119,10 +132,11 @@ export const PieChart = ({
119132 . style ( 'pointer-events' , 'none' ) ;
120133 }
121134
122- const svg = getCreateSvgPie ( totalValue )
123- if ( ! svg ) return ; // Early return if no svg created
135+ const svg = getCreateSvgPie ( totalValue ) ;
136+ if ( ! svg ) return undefined ; // Early return if no svg created
124137 // Create the pie chart
125- svg . selectAll ( 'path' )
138+ svg
139+ . selectAll ( 'path' )
126140 . data ( dataReady )
127141 . join ( 'path' )
128142 . attr (
@@ -132,65 +146,19 @@ export const PieChart = ({
132146 . innerRadius ( 70 )
133147 . outerRadius ( CHART_RADIUS ) ,
134148 )
135- //.attr('fill', d => color(d.data[0]))
136- //.style('opacity', d => (selectedTasks.includes(d.data[0]) ? 1 : 0.1))
137- //.on('click', (event, d) => handleTaskClick(d.data[0]))
138- //.on('mouseover', function handleMouseOver(d, i) {
139- // d3.select(this)
140- // .transition()
141- // .duration('50')
142- // .attr('opacity', '.5');
143- // div
144- // .transition()
145- // .duration(50)
146- // .style('opacity', 1)
147- // .style('visibility', 'visible');
148- // const taskName = Object.keys(chartLegend).map(key => {
149- // return chartLegend[key][0];
150- // });
151- // const index = Object.keys(chartLegend)
152- // .map(function(e) {
153- // return e;
154- // })
155- // .indexOf(i.data[0]);
156- // const legendInfo = taskName[index].toString();
157- // const taskName = chartLegend[i.data[0]][0];
158- // const taskValue = i.value;
159- // const percentage = ((taskValue / totalValue) * 100).toFixed(2);
160-
161-
162149 . attr ( 'fill' , d => color ( d . data . projectId ) )
163150 . style ( 'opacity' , d => ( selectedProjects . includes ( d . data . projectId ) ? 1 : 0.1 ) )
164151 . on ( 'click' , ( event , d ) => handleProjectClick ( d . data . projectId ) )
165152 . on ( 'mouseover' , ( event , d ) => {
166- d3 . select ( event . currentTarget ) . transition ( ) . duration ( 50 ) . attr ( 'opacity' , 0.5 ) ;
153+ d3 . select ( event . currentTarget )
154+ . transition ( )
155+ . duration ( 50 )
156+ . attr ( 'opacity' , 0.5 ) ;
167157 const percentage = ( ( d . data . totalTime / totalValue ) * 100 ) . toFixed ( 2 ) ;
168158 const legendInfo = togglePercentage
169159 ? `${ d . data . projectName } : ${ percentage } % of ${ totalValue . toFixed ( 2 ) } `
170160 : `${ d . data . projectName } : ${ d . data . totalTime . toFixed ( 2 ) } Hours` ;
171161
172- //const containerWidth = document.getElementById(`pie-chart-container-${pieChartId}`)
173- // .offsetWidth;
174- //const tooltipWidth = div.node().offsetWidth;
175- //const mouseX = d.pageX;
176-
177- //const tooltipX =
178- //mouseX + 10 + tooltipWidth > containerWidth ? mouseX - tooltipWidth - 10 : mouseX + 10;
179-
180- //div.style('left', `${tooltipX}px`).style('top', `${d.pageY - 15}px`);
181- //})
182- //.on('mouseout', function handleMouseOut() {
183- // d3.select(this)
184- // .transition()
185- // .duration('50')
186- // .attr('opacity', '.85');
187- // div
188- // .transition()
189- // .duration('50')
190- // .style('opacity', 0)
191- // .on('end', function hideTooltip() {
192- // d3.select(this).style('visibility', 'hidden'); // Hide after transition
193- // });
194162 div
195163 . html ( legendInfo )
196164 . style ( 'max-width' , '150px' )
@@ -200,73 +168,63 @@ export const PieChart = ({
200168 . style ( 'left' , `${ event . pageX + 10 } px` )
201169 . style ( 'top' , `${ event . pageY - 15 } px` ) ;
202170 } )
203- . on ( 'mouseout' , function ( ) {
204- d3 . select ( this ) . transition ( ) . duration ( 50 ) . attr ( 'opacity' , 1 ) ;
205- div . transition ( ) . duration ( 50 ) . style ( 'opacity' , 0 ) . on ( 'end' , function ( ) {
206- d3 . select ( this ) . style ( 'visibility' , 'hidden' ) ;
207- } ) ;
171+ . on ( 'mouseout' , function handleMouseOut ( ) {
172+ d3 . select ( this )
173+ . transition ( )
174+ . duration ( 50 )
175+ . attr ( 'opacity' , 1 ) ;
176+ div
177+ . transition ( )
178+ . duration ( 50 )
179+ . style ( 'opacity' , 0 )
180+ . on ( 'end' , function hideToolTip ( ) {
181+ d3 . select ( this ) . style ( 'visibility' , 'hidden' ) ;
182+ } ) ;
208183 } ) ;
209184
210185 return ( ) => {
211186 d3 . select ( `#pie-chart-${ pieChartId } ` ) . remove ( ) ;
212187 } ;
213188 } , [ tasksData , togglePercentage , selectedProjects ] ) ;
214189
215-
216-
217- return (
218- ! tasksData || tasksData ?. length === 0 ? < div > Loading </ div > : < div className = { `pie-chart-wrapper ${ darkMode ? 'text-light' : '' } ` } >
190+ return ! tasksData || tasksData ?. length === 0 ? (
191+ < div > Loading </ div >
192+ ) : (
193+ < div className = { `pie-chart-wrapper ${ darkMode ? 'text-light' : '' } ` } >
219194 < div id = { `pie-chart-container-${ pieChartId } ` } className = "pie-chart" />
220- //< div className = "pie-chart-legend-container" >
221- // < div className = "pie-chart-legend-header" >
222- // < div > Name</ div >
223- // < div > { dataLegendHeader } </ div >
224- // </ div >
225- // { Object . keys ( dataLegend ) . map ( key => (
226- // <div key={key} className="pie-chart-legend-item">
227- // <div className="data-legend-color" style={{ backgroundColor: color(key) }} />
228- // <div className="data-legend-info">
229- // {dataLegend[key].map((legendPart, index) => (
230- // <div
231- // className={`data-legend-info-part ${darkMode ? 'text-light' : ''}`}
232- // eslint-disable-next-line react/no-array-index-key
233- // key={index}
234- // >
235- // {legendPart}
236- // </div>
237- // ))}
238- // </div>
239- // </div>
240- // ))}
241- // <div className="data-total-value">Total Hours : {totalHours.toFixed(2)}</div>
242- < div className = "pie-chart-legend-container" >
243- < div className = "pie-chart-legend-table-wrapper" >
244- < table className = { darkMode ?"pie-chart-legend-table-dark" :"pie-chart-legend-table" } >
245- < thead >
246- < tr >
247- < th > Color</ th >
248- < th > Project Name</ th >
249- < th > Hours</ th >
250- </ tr >
251- </ thead >
252- < tbody >
253- { tasksData ?. map ( project => (
254- < tr key = { project . projectId } >
255- < td >
256- < div id = "project-chart-legend" style = { { backgroundColor : `${ color ( project . projectId ) } ` } } > </ div >
257- </ td >
258- < td > { project . projectName } </ td >
259- < td > { project . totalTime . toFixed ( 2 ) } </ td >
195+ < div className = "pie-chart-legend-container" >
196+ < div className = "pie-chart-legend-table-wrapper" >
197+ < table className = { darkMode ? 'pie-chart-legend-table-dark' : 'pie-chart-legend-table' } >
198+ < thead >
199+ < tr >
200+ < th > Color</ th >
201+ < th > Project Name</ th >
202+ < th > Hours</ th >
260203 </ tr >
261- ) ) }
262- </ tbody >
263- </ table >
264- </ div >
265-
266- < div className = "data-total-value" >
267- < strong > Total Hours:</ strong > { totalHours . toFixed ( 2 ) }
204+ </ thead >
205+ < tbody >
206+ { tasksData ?. map ( project => (
207+ < tr key = { project . projectId } >
208+ < td >
209+ < div
210+ id = "project-chart-legend"
211+ style = { { backgroundColor : `${ color ( project . projectId ) } ` } }
212+ />
213+ </ td >
214+ < td > { project . projectName } </ td >
215+ < td > { project . totalTime . toFixed ( 2 ) } </ td >
216+ </ tr >
217+ ) ) }
218+ </ tbody >
219+ </ table >
220+ </ div >
221+
222+ < div className = "data-total-value" >
223+ < strong > Total Hours:</ strong > { totalHours . toFixed ( 2 ) }
224+ </ div >
268225 </ div >
269226 </ div >
270- < / d i v >
271227 ) ;
272- } ;
228+ }
229+
230+ export default PieChart ;
0 commit comments