1+ "use client" ;
12import React , {
23 useEffect ,
34 useRef ,
@@ -122,7 +123,7 @@ const Graph: React.FC<GraphProps> = ({
122123
123124 // Responsive canvas sizing
124125 const containerWidth = container . clientWidth ;
125- const containerHeight = Math . min ( containerWidth * 0.5 , 400 ) ; // Limit max height
126+ const containerHeight = Math . min ( containerWidth * 0.5 , 400 ) ;
126127 canvas . width = containerWidth ;
127128 canvas . height = containerHeight ;
128129
@@ -131,89 +132,89 @@ const Graph: React.FC<GraphProps> = ({
131132
132133 ctx . clearRect ( 0 , 0 , width , height ) ;
133134
134- // Responsive bar sizing and margins
135- const leftMargin = width < 500 ? 50 : 70 ;
135+ // Unified padding and offset to prevent collisions
136+ const padding = Math . min ( width , height ) * 0.1 ;
137+ const yAxisLabelOffset = 30 ;
138+ const topMargin = padding ;
139+ const leftMargin = padding + yAxisLabelOffset + 20 ; // more room for Y-axis label
140+ const bottomMargin = padding + 40 ; // title + x-axis
141+ const rightMargin = padding ;
142+
143+ // Draw axes
144+ const axisColor = theme === "dark" ? "white" : "black" ;
145+ ctx . beginPath ( ) ;
146+ ctx . moveTo ( leftMargin , topMargin ) ;
147+ ctx . lineTo ( leftMargin , height - bottomMargin ) ;
148+ ctx . lineTo ( width - rightMargin , height - bottomMargin ) ;
149+ ctx . strokeStyle = axisColor ;
150+ ctx . stroke ( ) ;
136151
137- const rightMargin = 20 ;
138- const bottomMargin = width < 640 ? 40 : 50 ; // Smaller margin on mobile
139152 const barWidth = ( width - leftMargin - rightMargin ) / bandNames . length ;
140- const barSpacing = barWidth * 0.2 ; // Space between bars
153+ const barSpacing = barWidth * 0.3 ;
141154
142155 let minPower = 0 ;
143156 let maxPower = 100 ;
144-
145157 if ( maxPower - minPower < 1 ) {
146158 maxPower = minPower + 1 ;
147159 }
148160
149- const axisColor = theme === "dark" ? "white" : "black" ;
150-
151- // Draw axes
152- ctx . beginPath ( ) ;
153- ctx . moveTo ( leftMargin , 10 ) ;
154- ctx . lineTo ( leftMargin , height - bottomMargin ) ;
155- ctx . lineTo ( width - rightMargin , height - bottomMargin ) ;
156- ctx . strokeStyle = axisColor ;
157- ctx . stroke ( ) ;
158-
159161 // Draw bars
160- // Draw bars and beta percentage
161162 currentBandPowerData . forEach ( ( power , index ) => {
162163 const x = leftMargin + index * barWidth ;
163164 const normalizedHeight = Math . max ( 0 , ( power - minPower ) / ( maxPower - minPower ) ) ;
164- const barHeight = Math . max ( 0 , normalizedHeight * ( height - bottomMargin - 10 ) ) ;
165-
165+ const barHeight = Math . max ( 0 , normalizedHeight * ( height - bottomMargin - topMargin ) ) ;
166166 const barX = x + barSpacing / 2 ;
167167 const barY = height - bottomMargin - barHeight ;
168- const actualBarWidth = barWidth - barSpacing * 1.5 ; // Make it thinner than before
168+ const actualBarWidth = barWidth - barSpacing * 1.5 ;
169169
170170 ctx . fillStyle = bandColors [ index ] ;
171171 ctx . fillRect ( barX , barY , actualBarWidth , barHeight ) ;
172-
173-
174172 } ) ;
175173
176-
177- // Draw labels
174+ // Font sizing responsive
175+ const fontSize = width < 640 ? 12 : width < 768 ? 14 : width < 1024 ? 16 : 18 ;
178176 ctx . fillStyle = axisColor ;
179- const fontSize = width < 640 ? 10 : 12 ; // Smaller text on mobile
180177 ctx . font = `${ fontSize } px Arial` ;
181-
182- // Y-axis labels (log scale)
183178 ctx . textAlign = "right" ;
184179 ctx . textBaseline = "middle" ;
185- const yLabelCount = Math . min ( 5 , Math . floor ( height / 50 ) ) ; // Fewer labels on small screens
180+
181+ const yLabelCount = Math . min ( 5 , Math . floor ( height / 50 ) ) ;
186182 for ( let i = 0 ; i <= yLabelCount ; i ++ ) {
187183 const value = minPower + ( maxPower - minPower ) * ( i / yLabelCount ) ;
188- const labelY = height - bottomMargin - ( i / yLabelCount ) * ( height - bottomMargin - 10 ) ;
189- ctx . fillText ( value . toFixed ( 1 ) , leftMargin - 5 , labelY ) ;
184+ const labelY = height - bottomMargin - ( i / yLabelCount ) * ( height - bottomMargin - topMargin ) ;
185+ ctx . fillText ( value . toFixed ( 1 ) , leftMargin - 10 , labelY ) ;
190186 }
191187
192188 // X-axis labels
193189 ctx . textAlign = "center" ;
194190 ctx . textBaseline = "top" ;
195191 bandNames . forEach ( ( band , index ) => {
196- const labelX = leftMargin + index * barWidth + barWidth * 0.5 ;
192+ const barX = leftMargin + index * barWidth + barSpacing / 2 ;
193+ const barW = barWidth - barSpacing * 1.5 ;
194+ const labelX = barX + barW / 2 ;
197195 ctx . fillText ( band , labelX , height - bottomMargin + 5 ) ;
198196 } ) ;
199197
200- // EEG Band Power – same as "Frequency (Hz)"
201- ctx . font = "16px Arial" ;
198+ // Title: EEG Band Power below graph area with consistent padding
199+ ctx . font = ` ${ fontSize + 2 } px Arial` ;
202200 ctx . textAlign = "center" ;
203- ctx . fillText ( "EEG Band Power" , ( width + leftMargin ) / 2 , height - 17 ) ;
201+ ctx . textBaseline = "top" ;
202+ ctx . fillText ( "EEG Band Power" , width / 2 , height - padding + 6 ) ;
204203
205- // Power – same as "Magnitude"
204+ // Y-axis label: Power, fully visible with outer padding
206205 ctx . save ( ) ;
207206 ctx . rotate ( - Math . PI / 2 ) ;
208- ctx . font = "20px Arial" ;
207+ ctx . font = ` ${ fontSize + 2 } px Arial` ;
209208 ctx . textAlign = "center" ;
210- ctx . fillText ( "Power" , - height / 2 , 15 ) ;
209+ ctx . textBaseline = "bottom" ;
210+ ctx . fillText ( "Power" , - height / 2 , padding ) ;
211211 ctx . restore ( ) ;
212-
213212 } ,
214213 [ theme , bandColors , bandNames ]
215214 ) ;
216215
216+
217+
217218 // Rest of the component remains the same (animateGraph, useEffect hooks)
218219 const animateGraph = useCallback ( ( ) => {
219220 const interpolationFactor = 0.1 ;
@@ -255,7 +256,7 @@ const Graph: React.FC<GraphProps> = ({
255256 return (
256257 < div
257258 ref = { containerRef }
258- className = { `w-full h-full min-h-0 min-w-0 px-4 ` }
259+ className = { `w-full h-full min-h-0 min-w-0 py-2 ` }
259260 >
260261 < canvas
261262 ref = { canvasRef }
0 commit comments