@@ -12,9 +12,10 @@ import { WebglPlot, ColorRGBA, WebglLine } from "webgl-plot";
1212
1313interface CanvasProps {
1414 pauseRef : React . RefObject < boolean > ;
15- selectedBits ?: BitSelection ; // Add `?` to make it optional
15+ selectedBits ?: BitSelection ;
1616 isDisplay : boolean ;
1717 canvasCount ?: number ;
18+ selectedChannels : number [ ] ;
1819 timeBase ?: number ;
1920 currentSamplingRate : number ;
2021 Zoom : number ;
@@ -27,11 +28,11 @@ const Canvas = forwardRef(
2728 {
2829 pauseRef,
2930 selectedBits,
30- isDisplay,
3131 canvasCount = 6 , // default value in case not provided
3232 timeBase = 4 ,
3333 currentSamplingRate,
3434 Zoom,
35+ selectedChannels,
3536 currentSnapshot,
3637 snapShotRef,
3738 } : CanvasProps ,
@@ -40,7 +41,7 @@ const Canvas = forwardRef(
4041 const { theme } = useTheme ( ) ;
4142 let previousCounter : number | null = null ; // Variable to store the previous counter value for loss detection
4243 const canvasContainerRef = useRef < HTMLDivElement > ( null ) ;
43- const [ numChannels , setNumChannels ] = useState < number > ( canvasCount ) ;
44+ const [ numChannels , setNumChannels ] = useState < number > ( selectedChannels . length ) ;
4445 const numXRef = useRef < number > ( 2000 ) ; // To track the calculated value
4546 const [ canvases , setCanvases ] = useState < HTMLCanvasElement [ ] > ( [ ] ) ;
4647 const [ wglPlots , setWglPlots ] = useState < WebglPlot [ ] > ( [ ] ) ;
@@ -54,6 +55,7 @@ const Canvas = forwardRef(
5455 Array . from ( { length : 6 } , ( ) => Array ( ) )
5556 )
5657 ) ;
58+ const selectedChannelsRef = useRef ( selectedChannels ) ;
5759 const activebuffer = useRef ( 0 ) ; // Initialize useRef with 0
5860 const indicesRef = useRef < number [ ] > ( [ ] ) ; // Use `useRef` for indices
5961
@@ -71,12 +73,15 @@ const Canvas = forwardRef(
7173 }
7274 } , [ ] ) ;
7375
74-
7576 useEffect ( ( ) => {
7677 numXRef . current = ( currentSamplingRate * timeBase ) ;
7778
7879 } , [ timeBase ] ) ;
7980
81+ useEffect ( ( ) => {
82+ selectedChannelsRef . current = selectedChannels ;
83+ } , [ selectedChannels ] ) ;
84+
8085 const prevCanvasCountRef = useRef < number > ( canvasCount ) ;
8186
8287 const processIncomingData = ( incomingData : number [ ] ) => {
@@ -113,16 +118,15 @@ const Canvas = forwardRef(
113118 } ;
114119
115120 useEffect ( ( ) => {
116- setNumChannels ( canvasCount ) ;
117- } , [ canvasCount ] ) ;
121+ setNumChannels ( selectedChannels . length ) ;
122+ } , [ selectedChannels ] ) ;
118123
119124
120125 useEffect ( ( ) => {
121126 // Reset when timeBase changes
122127 currentSweepPos . current = new Array ( numChannels ) . fill ( 0 ) ;
123128 sweepPositions . current = new Array ( numChannels ) . fill ( 0 ) ;
124- } , [ timeBase ] ) ;
125-
129+ } , [ timeBase , theme ] ) ;
126130
127131 useImperativeHandle (
128132 ref ,
@@ -155,11 +159,17 @@ const Canvas = forwardRef(
155159 ) ;
156160
157161 const createCanvases = ( ) => {
158- if ( ! canvasContainerRef . current ) return ;
162+ const container = canvasContainerRef . current ;
163+ if ( ! container ) {
164+ return ; // Exit if the ref is null
165+ }
159166
160- // Clean up all existing canvases and their WebGL contexts
161- while ( canvasContainerRef . current . firstChild ) {
162- const firstChild = canvasContainerRef . current . firstChild ;
167+ currentSweepPos . current = new Array ( numChannels ) . fill ( 0 ) ;
168+ sweepPositions . current = new Array ( numChannels ) . fill ( 0 ) ;
169+
170+ // Clear existing child elements
171+ while ( container . firstChild ) {
172+ const firstChild = container . firstChild ;
163173 if ( firstChild instanceof HTMLCanvasElement ) {
164174 const gl = firstChild . getContext ( "webgl" ) ;
165175 if ( gl ) {
@@ -169,130 +179,128 @@ const Canvas = forwardRef(
169179 }
170180 }
171181 }
172- canvasContainerRef . current . removeChild ( firstChild ) ;
182+ container . removeChild ( firstChild ) ;
173183 }
174184
175185 setCanvases ( [ ] ) ;
176186 setWglPlots ( [ ] ) ;
177187 linesRef . current = [ ] ;
178- const newCanvases = [ ] ;
179- const newWglPlots = [ ] ;
180- const newLines = [ ] ;
181-
188+ const newCanvases : HTMLCanvasElement [ ] = [ ] ;
189+ const newWglPlots : WebglPlot [ ] = [ ] ;
190+ const newLines : WebglLine [ ] = [ ] ;
182191
183- // // Create grid lines
192+ // Create grid lines
184193 const canvasWrapper = document . createElement ( "div" ) ;
185- canvasWrapper . className = "absolute inset-0" ; // Make the wrapper fill the parent container
186- const opacityDarkMajor = "0.2" ; // Opacity for every 5th line in dark theme
187- const opacityDarkMinor = "0.05" ; // Opacity for other lines in dark theme
188- const opacityLightMajor = "0.4" ; // Opacity for every 5th line in light theme
189- const opacityLightMinor = "0.1" ; // Opacity for other lines in light theme
194+ canvasWrapper . className = "absolute inset-0" ;
195+ const opacityDarkMajor = "0.2" ;
196+ const opacityDarkMinor = "0.05" ;
197+ const opacityLightMajor = "0.4" ;
198+ const opacityLightMinor = "0.1" ;
190199 const distanceminor = samplingRate * 0.04 ;
191- const numGridLines = getpoints ( selectedBits ?? 10 ) * 4 / distanceminor ;
200+ const numGridLines = ( getpoints ( selectedBits ?? 10 ) * 4 ) / distanceminor ;
201+
192202 for ( let j = 1 ; j < numGridLines ; j ++ ) {
193203 const gridLineX = document . createElement ( "div" ) ;
194204 gridLineX . className = "absolute bg-[rgb(128,128,128)]" ;
195205 gridLineX . style . width = "1px" ;
196206 gridLineX . style . height = "100%" ;
197- const divPoint = ( j / numGridLines ) * 100
198- const a = parseFloat ( divPoint . toFixed ( 3 ) ) ;
199- gridLineX . style . left = `${ a } %`
200- gridLineX . style . top = "0" ;
207+ gridLineX . style . left = `${ ( ( j / numGridLines ) * 100 ) . toFixed ( 3 ) } %` ;
201208 gridLineX . style . opacity = j % 5 === 0 ? ( theme === "dark" ? opacityDarkMajor : opacityLightMajor ) : ( theme === "dark" ? opacityDarkMinor : opacityLightMinor ) ;
202-
203- // Append grid lines to the wrapper
204209 canvasWrapper . appendChild ( gridLineX ) ;
205210 }
211+
206212 const horizontalline = 50 ;
207213 for ( let j = 1 ; j < horizontalline ; j ++ ) {
208214 const gridLineY = document . createElement ( "div" ) ;
209215 gridLineY . className = "absolute bg-[rgb(128,128,128)]" ;
210216 gridLineY . style . height = "1px" ;
211217 gridLineY . style . width = "100%" ;
212- const distance = ( j / horizontalline ) * 100
213- const distancetop = parseFloat ( distance . toFixed ( 3 ) ) ;
214- gridLineY . style . top = `${ distancetop } %` ;
215- gridLineY . style . left = "0" ;
218+ gridLineY . style . top = `${ ( ( j / horizontalline ) * 100 ) . toFixed ( 3 ) } %` ;
216219 gridLineY . style . opacity = j % 5 === 0 ? ( theme === "dark" ? opacityDarkMajor : opacityLightMajor ) : ( theme === "dark" ? opacityDarkMinor : opacityLightMinor ) ;
217-
218- // Append grid lines to the wrapper
219220 canvasWrapper . appendChild ( gridLineY ) ;
220221 }
221- canvasContainerRef . current . appendChild ( canvasWrapper ) ;
222- for ( let i = 0 ; i < numChannels ; i ++ ) {
222+ container . appendChild ( canvasWrapper ) ;
223+
224+ // Create canvases for each selected channel
225+ selectedChannels . forEach ( ( channelNumber ) => {
223226 const canvasWrapper = document . createElement ( "div" ) ;
224- canvasWrapper . className = "canvas-container relative flex-[1_1_0%]" ; // Add relative positioning for absolute grid positioning
227+ canvasWrapper . className = "canvas-container relative flex-[1_1_0%]" ;
225228
226229 const canvas = document . createElement ( "canvas" ) ;
227- canvas . id = `canvas${ i + 1 } ` ;
228- canvas . width = canvasContainerRef . current . clientWidth ;
229- const canvasHeight = ( canvasContainerRef . current . clientHeight / numChannels ) ;
230- canvas . height = canvasHeight ;
230+ canvas . id = `canvas${ channelNumber } ` ;
231+ canvas . width = container . clientWidth ;
232+ canvas . height = container . clientHeight / selectedChannels . length ;
231233 canvas . className = "w-full h-full block rounded-xl" ;
232234
233- // Create a badge for the channel number
234235 const badge = document . createElement ( "div" ) ;
235236 badge . className = "absolute text-gray-500 text-sm rounded-full p-2 m-2" ;
236- badge . innerText = `CH${ i + 1 } ` ;
237+ badge . innerText = `CH${ channelNumber } ` ;
237238
238- // Append the canvas and badge to the container
239239 canvasWrapper . appendChild ( badge ) ;
240240 canvasWrapper . appendChild ( canvas ) ;
241- canvasContainerRef . current . appendChild ( canvasWrapper ) ;
241+ container . appendChild ( canvasWrapper ) ;
242242
243243 newCanvases . push ( canvas ) ;
244244 const wglp = new WebglPlot ( canvas ) ;
245245 newWglPlots . push ( wglp ) ;
246246 wglp . gScaleY = Zoom ;
247- const line = new WebglLine ( getLineColor ( i , theme ) , numXRef . current ) ;
247+ const line = new WebglLine ( getLineColor ( channelNumber , theme ) , numXRef . current ) ;
248248 wglp . gOffsetY = 0 ;
249249 line . offsetY = 0 ;
250250 line . lineSpaceX ( - 1 , 2 / numXRef . current ) ;
251251
252252 wglp . addLine ( line ) ;
253253 newLines . push ( line ) ;
254- }
254+ } ) ;
255255
256256 linesRef . current = newLines ;
257257 setCanvases ( newCanvases ) ;
258258 setWglPlots ( newWglPlots ) ;
259259 setLines ( newLines ) ;
260260 } ;
261261
262-
263262 const getLineColor = ( i : number , theme : string | undefined ) : ColorRGBA => {
264- // Define bright colors
263+ // Define the updated dark colors
265264 const colorsDark : ColorRGBA [ ] = [
266- new ColorRGBA ( 1 , 0.286 , 0.529 , 1 ) , // Bright Pink
267- new ColorRGBA ( 0.475 , 0.894 , 0.952 , 1 ) , // Light Blue
268- new ColorRGBA ( 0 , 1 , 0.753 , 1 ) , // Bright Cyan
269- new ColorRGBA ( 0.431 , 0.761 , 0.031 , 1 ) , // Bright Green
270- new ColorRGBA ( 0.678 , 0.286 , 0.882 , 1 ) , // Bright Purple
271- new ColorRGBA ( 0.914 , 0.361 , 0.051 , 1 ) , // Bright Orange
265+ new ColorRGBA ( 180 / 255 , 70 / 255 , 120 / 255 , 1 ) , // Darkened #EC6FAA
266+ new ColorRGBA ( 150 / 255 , 70 / 255 , 125 / 255 , 1 ) , // Darkened #CE6FAC
267+ new ColorRGBA ( 130 / 255 , 90 / 255 , 140 / 255 , 1 ) , // Darkened #B47EB7
268+ new ColorRGBA ( 110 / 255 , 110 / 255 , 160 / 255 , 1 ) , // Darkened #9D8DC4
269+ new ColorRGBA ( 70 / 255 , 100 / 255 , 150 / 255 , 1 ) , // Darkened #689AD2
270+ new ColorRGBA ( 40 / 255 , 110 / 255 , 140 / 255 , 1 ) , // Darkened #35A5CC
271+ new ColorRGBA ( 35 / 255 , 120 / 255 , 130 / 255 , 1 ) , // Darkened #30A8B4
272+ new ColorRGBA ( 35 / 255 , 125 / 255 , 120 / 255 , 1 ) , // Darkened #32ABA2
273+
272274 ] ;
275+
273276 const colorsLight : ColorRGBA [ ] = [
274- new ColorRGBA ( 0.820 , 0.000 , 0.329 , 1 ) , // #D10054 - Bright Pink
275- new ColorRGBA ( 0.000 , 0.478 , 0.549 , 1 ) , // #007A8C - Light Blue
276- new ColorRGBA ( 0.039 , 0.408 , 0.278 , 1 ) , // #0A6847 - Dark Green
277- new ColorRGBA ( 0.404 , 0.255 , 0.533 , 1 ) , // #674188 - Bright Purple
278- new ColorRGBA ( 0.902 , 0.361 , 0.098 , 1 ) , // #E65C19 - Bright Orange
279- new ColorRGBA ( 0.180 , 0.027 , 0.247 , 1 ) , // #2E073F - Dark Purple
280- ] ;
277+ new ColorRGBA ( 236 / 255 , 111 / 255 , 170 / 255 , 0.8 ) , // Slightly transparent #EC6FAA
278+ new ColorRGBA ( 206 / 255 , 111 / 255 , 172 / 255 , 0.8 ) , // Slightly transparent #CE6FAC
279+ new ColorRGBA ( 180 / 255 , 126 / 255 , 183 / 255 , 0.8 ) , // Slightly transparent #B47EB7
280+ new ColorRGBA ( 157 / 255 , 141 / 255 , 196 / 255 , 0.8 ) , // Slightly transparent #9D8DC4
281+ new ColorRGBA ( 104 / 255 , 154 / 255 , 210 / 255 , 0.8 ) , // Slightly transparent #689AD2
282+ new ColorRGBA ( 53 / 255 , 165 / 255 , 204 / 255 , 0.8 ) , // Slightly transparent #35A5CC
283+ new ColorRGBA ( 48 / 255 , 168 / 255 , 180 / 255 , 0.8 ) , // Slightly transparent #30A8B4
284+ new ColorRGBA ( 50 / 255 , 171 / 255 , 162 / 255 , 0.8 ) , // Slightly transparent #32ABA2
281285
286+ ] ;
282287
283- // Return color based on the index, cycling through if necessary
288+ // Swap light and dark colors for themes
284289 return theme === "dark"
285- ? colorsDark [ i % colorsDark . length ]
286- : colorsLight [ i % colorsLight . length ] ;
290+ ? colorsLight [ i % colorsLight . length ] // Use lighter colors in dark theme
291+ : colorsDark [ i % colorsDark . length ] ; // Use darker colors in light theme
287292 } ;
288293
289294 const updatePlots = useCallback (
290295 ( data : number [ ] , Zoom : number ) => {
296+ // Access the latest selectedChannels via the ref
297+ const currentSelectedChannels = selectedChannelsRef . current ;
291298
299+ // Adjust zoom level for each WebglPlot
292300 wglPlots . forEach ( ( wglp , index ) => {
293301 if ( wglp ) {
294302 try {
295- wglp . gScaleY = Zoom ; // Adjust the zoom value
303+ wglp . gScaleY = Zoom ; // Adjust zoom value
296304 } catch ( error ) {
297305 console . error (
298306 `Error setting gScaleY for WebglPlot instance at index ${ index } :` ,
@@ -303,28 +311,59 @@ const Canvas = forwardRef(
303311 console . warn ( `WebglPlot instance at index ${ index } is undefined.` ) ;
304312 }
305313 } ) ;
306-
307314 linesRef . current . forEach ( ( line , i ) => {
315+ if ( ! line ) {
316+ console . warn ( `Line at index ${ i } is undefined.` ) ;
317+ return ;
318+ }
308319
309- // Use a separate sweep position for each line
310- currentSweepPos . current [ i ] = sweepPositions . current [ i ] ;
311- // Plot the new data at the current sweep position
312- line . setY ( currentSweepPos . current [ i ] % line . numPoints , data [ i + 1 ] ) ;
320+ // Map channel number from selectedChannels
321+ const channelNumber = currentSelectedChannels [ i ] ;
322+ if ( channelNumber == null || channelNumber < 0 || channelNumber >= data . length ) {
323+ console . warn ( `Invalid channel number: ${ channelNumber } . Skipping.` ) ;
324+ return ;
325+ }
326+
327+ const channelData = data [ channelNumber ] ;
313328
314- // Clear the next point to create a gap (optional, for visual effect)
315- const clearPosition = Math . ceil ( ( currentSweepPos . current [ i ] + ( numXRef . current / 100 ) ) % line . numPoints ) ;
316- line . setY ( clearPosition , NaN ) ;
329+ // Ensure sweepPositions.current[i] is initialized
330+ if ( sweepPositions . current [ i ] === undefined ) {
331+ sweepPositions . current [ i ] = 0 ;
332+ }
317333
318- // Increment the sweep position for the current line
319- sweepPositions . current [ i ] = ( currentSweepPos . current [ i ] + 1 ) % line . numPoints ;
334+ // Calculate the current position
335+ const currentPos = sweepPositions . current [ i ] % line . numPoints ;
336+
337+ if ( Number . isNaN ( currentPos ) ) {
338+ console . error ( `Invalid currentPos at index ${ i } . sweepPositions.current[i]:` , sweepPositions . current [ i ] ) ;
339+ return ;
340+ }
341+
342+ // Plot the data
343+ try {
344+ line . setY ( currentPos , channelData ) ;
345+ } catch ( error ) {
346+ console . error ( `Error plotting data for line ${ i } at position ${ currentPos } :` , error ) ;
347+ }
348+
349+ // Clear the next point for visual effect
350+ const clearPosition = Math . ceil ( ( currentPos + numXRef . current / 100 ) % line . numPoints ) ;
351+ try {
352+ line . setY ( clearPosition , NaN ) ;
353+ } catch ( error ) {
354+ console . error ( `Error clearing data at position ${ clearPosition } for line ${ i } :` , error ) ;
355+ }
356+
357+ // Increment the sweep position
358+ sweepPositions . current [ i ] = ( currentPos + 1 ) % line . numPoints ;
320359 } ) ;
321360 } ,
322- [ lines , wglPlots , numChannels , theme , timeBase ]
361+ [ linesRef , wglPlots , selectedChannelsRef , numXRef , sweepPositions ]
323362 ) ;
324363
325364 useEffect ( ( ) => {
326365 createCanvases ( ) ;
327- } , [ numChannels , theme , timeBase ] ) ;
366+ } , [ numChannels , theme , timeBase , selectedChannels ] ) ;
328367
329368
330369 const animate = useCallback ( ( ) => {
@@ -384,6 +423,18 @@ const Canvas = forwardRef(
384423
385424 } , [ animate ] ) ;
386425
426+ useEffect ( ( ) => {
427+ const handleResize = ( ) => {
428+ createCanvases ( ) ;
429+
430+ } ;
431+ window . addEventListener ( "resize" , handleResize ) ;
432+ return ( ) => {
433+ window . removeEventListener ( "resize" , handleResize ) ;
434+ } ;
435+ } , [ createCanvases ] ) ;
436+
437+
387438 return (
388439 < main className = " flex flex-col flex-[1_1_0%] min-h-80 bg-highlight rounded-2xl m-4 relative"
389440 ref = { canvasContainerRef }
@@ -393,4 +444,4 @@ const Canvas = forwardRef(
393444 }
394445) ;
395446Canvas . displayName = "Canvas" ;
396- export default Canvas ;
447+ export default Canvas ;
0 commit comments