-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed css around enumerations.tsx. Working on Fixing overflow and ref…
…actoring for itegration with backend
- Loading branch information
Showing
4 changed files
with
169 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
288 changes: 145 additions & 143 deletions
288
software/tracksight/frontend/src/app/testing/components/Enumeration.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,150 +1,152 @@ | ||
import React, { useState, useEffect, useRef } from "react"; | ||
|
||
interface EnumerationGraphProps { | ||
signalName: string; | ||
currentState: string; | ||
currentTime: number; | ||
enumStates: string[]; | ||
} | ||
import React, { useState, useEffect, useRef, useCallback } from 'react' | ||
|
||
interface StateHistoryItem { | ||
state: string; | ||
startTime: number; | ||
state: string | ||
startTime: number | ||
} | ||
|
||
interface StateBar { | ||
state: string; | ||
startTime: number; | ||
left: number; | ||
width: number; | ||
state: string | ||
startTime: number | ||
left: number | ||
width: number | ||
} | ||
|
||
const EnumerationGraph: React.FC<EnumerationGraphProps> = ({ | ||
signalName, | ||
currentState, | ||
currentTime, | ||
enumStates, | ||
}) => { | ||
const containerRef = useRef<HTMLDivElement>(null); | ||
const [stateHistory, setStateHistory] = useState<StateHistoryItem[]>([]); | ||
|
||
// Define the total time window displayed on the graph (e.g., last 60 seconds) | ||
const timeWindow = 11 * 1000; // milliseconds | ||
|
||
useEffect(() => { | ||
// Update state history when currentState changes | ||
setStateHistory((prevHistory) => { | ||
const lastState = prevHistory[prevHistory.length - 1]; | ||
if (!lastState || lastState.state !== currentState) { | ||
// If state changed, add new state with current time | ||
return [ | ||
...prevHistory, | ||
{ state: currentState, startTime: currentTime }, | ||
]; | ||
} else { | ||
// State didn't change, return previous history | ||
return prevHistory; | ||
} | ||
}); | ||
}, [currentState]); | ||
|
||
useEffect(() => { | ||
// Remove states that end before the current time window | ||
setStateHistory((prevHistory) => | ||
prevHistory.filter((state, index) => { | ||
const nextState = prevHistory[index + 1]; | ||
const endTime = nextState ? nextState.startTime : currentTime; | ||
return endTime > currentTime - timeWindow; | ||
}) | ||
); | ||
}, [currentTime]); | ||
|
||
// TODO: actual signals will have variable width based on time window, | ||
// will return data points at unspecified intervals and will need to be interpolated | ||
|
||
const containerWidth = containerRef.current?.offsetWidth || window.innerWidth; | ||
const pixelsPerMs = containerWidth / timeWindow; | ||
|
||
const stateBars: StateBar[] = stateHistory.map((state, index) => { | ||
const nextState = stateHistory[index + 1]; | ||
|
||
const stateStartTime = state.startTime; | ||
const stateEndTime = nextState ? nextState.startTime : currentTime; | ||
|
||
const barStartTime = Math.max(stateStartTime, currentTime - timeWindow); | ||
const barEndTime = Math.min(stateEndTime, currentTime); | ||
|
||
const startOffset = | ||
(barStartTime - (currentTime - timeWindow)) * pixelsPerMs; | ||
const duration = barEndTime - barStartTime; | ||
const width = duration * pixelsPerMs; | ||
|
||
return { | ||
...state, | ||
left: startOffset, | ||
width, | ||
}; | ||
}); | ||
|
||
// Colors for the states, mapping to indices | ||
const stateColors: string[] = [ | ||
"#FF3B2F", | ||
"#FFCC02", | ||
"#FF9500", | ||
"#35C759", | ||
"#007AFF", | ||
]; | ||
|
||
const getStateColor = (state: string): string => { | ||
const index = enumStates.indexOf(state); | ||
return stateColors[index % stateColors.length]; // Wrap around if more states | ||
}; | ||
|
||
return ( | ||
<div className="w-full relative"> | ||
{/* Signal Name and Legend */} | ||
<div className="mx-4 flex gap-5 items-center"> | ||
<div className="font-bold my-2 text-white bg-blue-500 rounded-full inline-block p-1 text-sm"> | ||
{signalName} | ||
</div> | ||
{/* Legend */} | ||
<div className="mt-2 text-xs flex gap-4"> | ||
{enumStates.map((state, index) => ( | ||
<div key={index} className="flex items-center mb-1"> | ||
<span | ||
className="w-3 h-3 inline-block mr-2" | ||
style={{ backgroundColor: getStateColor(state) }} | ||
></span> | ||
<span className="text-gray-500">{state}</span> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
{/* Graph */} | ||
<div | ||
className="relative w-full h-6 bg-gray-100 overflow-hidden" | ||
ref={containerRef} | ||
> | ||
{stateBars.map( | ||
(bar, index) => | ||
bar.width > 0 && ( | ||
<div | ||
key={index} | ||
className="absolute top-0 bottom-0" | ||
style={{ | ||
left: `${bar.left}px`, | ||
width: `${bar.width}px`, | ||
backgroundColor: getStateColor(bar.state), | ||
}} | ||
title={`${bar.state} (${new Date( | ||
bar.startTime | ||
).toLocaleTimeString()})`} | ||
></div> | ||
) | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default EnumerationGraph; | ||
// Colors for the states, mapping to indices | ||
const stateColors: string[] = [ | ||
'#FF3B2F', | ||
'#FFCC02', | ||
'#FF9500', | ||
'#35C759', | ||
'#007AFF', | ||
// TODO add a few more colours | ||
] | ||
|
||
export default function EnumerationGraph({ | ||
signalName, | ||
currentState, | ||
currentTime, | ||
enumStates, | ||
}: { | ||
signalName: string | ||
currentState: string | ||
currentTime: number | ||
enumStates: string[] | ||
}) { | ||
const containerRef = useRef<HTMLDivElement>(null) | ||
const [stateHistory, setStateHistory] = useState<StateHistoryItem[]>([]) | ||
|
||
// Define the total time window displayed on the graph (e.g., last 60 seconds) | ||
const timeWindow = 11 * 1000 // milliseconds | ||
|
||
useEffect(() => { | ||
// Update state history when currentState changes | ||
setStateHistory((prevHistory) => { | ||
const lastState = prevHistory[prevHistory.length - 1] | ||
if (!lastState || lastState.state !== currentState) { | ||
// If state changed, add new state with current time | ||
return [...prevHistory, { state: currentState, startTime: currentTime }] | ||
} else { | ||
// State didn't change, return previous history | ||
return prevHistory | ||
} | ||
}) | ||
}, [currentState]) | ||
|
||
useEffect(() => { | ||
// Remove states that end before the current time window | ||
setStateHistory((prevHistory) => | ||
prevHistory.filter((state, index) => { | ||
const nextState = prevHistory[index + 1] | ||
const endTime = nextState ? nextState.startTime : currentTime | ||
return endTime > currentTime - timeWindow | ||
}) | ||
) | ||
}, [currentTime]) | ||
|
||
// TODO: actual signals will have variable width based on time window, | ||
// will return data points at unspecified intervals and will need to be interpolated | ||
const containerWidth = containerRef.current?.offsetWidth || window.innerWidth | ||
const pixelsPerMs = containerWidth / timeWindow | ||
|
||
const stateBars: StateBar[] = stateHistory.map((state, index) => { | ||
const nextState = stateHistory[index + 1] | ||
|
||
const stateStartTime = state.startTime | ||
const stateEndTime = nextState ? nextState.startTime : currentTime | ||
|
||
const barStartTime = Math.max(stateStartTime, currentTime - timeWindow) | ||
const barEndTime = Math.min(stateEndTime, currentTime) | ||
|
||
const startOffset = | ||
(barStartTime - (currentTime - timeWindow)) * pixelsPerMs | ||
const duration = barEndTime - barStartTime | ||
const width = duration * pixelsPerMs | ||
|
||
return { | ||
...state, | ||
left: startOffset, | ||
width, | ||
} | ||
}) | ||
|
||
const getStateColor = useCallback((state: string): string => { | ||
const index = enumStates.indexOf(state) | ||
return stateColors[index % stateColors.length] // Wrap around if more states | ||
}, []) | ||
|
||
const isActive = useCallback( | ||
(state: string): Boolean => { | ||
return stateBars.length != 0 && stateBars.at(-1)!.state === state | ||
}, | ||
[stateBars] | ||
) | ||
|
||
return ( | ||
<div className='w-min-screen my-1'> | ||
{/* Signal Name and Legend */} | ||
<div className='mx-4 flex gap-5 items-center'> | ||
<div className='font-bold my-1 px-2 py-1 text-white bg-blue-500 rounded-full inline-block text-sm '> | ||
{signalName} | ||
</div> | ||
{/* Legend */} | ||
<div className='my-1 text-xs flex gap-4'> | ||
{enumStates.map((state, index) => ( | ||
<div key={index} className='flex items-center mb-1'> | ||
<span | ||
className='w-3 h-3 inline-block mr-2' | ||
style={{ backgroundColor: getStateColor(state) }} | ||
/> | ||
<span | ||
data-active={isActive(state)} | ||
className='text-gray-500 font-normal data-[active=true]:text-black data-[active=true]:font-bold transition-all duration-300'> | ||
{state} | ||
</span> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
{/* Graph */} | ||
<div className='h-6 bg-gray-100 flex flex-row' ref={containerRef}> | ||
{stateBars.map((bar, index) => { | ||
// console.log(bar.state) | ||
return ( | ||
bar.width > 0 && ( | ||
<div | ||
key={index} | ||
className='h-full' | ||
style={{ | ||
left: `${bar.left}px`, | ||
width: `${bar.width}px`, | ||
backgroundColor: getStateColor(bar.state), | ||
}} | ||
title={`${bar.state} (${new Date( | ||
bar.startTime | ||
).toLocaleTimeString()})`}></div> | ||
) | ||
) | ||
})} | ||
</div> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -693,10 +693,17 @@ | |
resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz" | ||
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== | ||
|
||
"@img/sharp-win32[email protected]": | ||
"@img/sharp-darwin[email protected]": | ||
version "0.33.5" | ||
resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz" | ||
integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== | ||
resolved "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz" | ||
integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q== | ||
optionalDependencies: | ||
"@img/sharp-libvips-darwin-x64" "1.0.4" | ||
|
||
"@img/[email protected]": | ||
version "1.0.4" | ||
resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz" | ||
integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== | ||
|
||
"@jridgewell/gen-mapping@^0.3.5": | ||
version "0.3.8" | ||
|
@@ -905,10 +912,10 @@ | |
dependencies: | ||
fast-glob "3.3.1" | ||
|
||
"@next/swc-win32-x64-msvc@15.1.6": | ||
"@next/swc-darwin[email protected]": | ||
version "15.1.6" | ||
resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.6.tgz" | ||
integrity sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ== | ||
resolved "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.6.tgz" | ||
integrity sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg== | ||
|
||
"@nodelib/[email protected]": | ||
version "2.1.5" | ||
|
@@ -1404,10 +1411,10 @@ | |
jiti "^2.4.2" | ||
tailwindcss "4.0.0" | ||
|
||
"@tailwindcss/oxide-win32-x64-msvc@4.0.0": | ||
"@tailwindcss/oxide-darwin[email protected]": | ||
version "4.0.0" | ||
resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0.tgz" | ||
integrity sha512-bqT0AY8RXb8GMDy28JtngvqaOSB2YixbLPLvUo6I6lkvvUwA6Eqh2Tj60e2Lh7O/k083f8tYiB0WEK4wmTI7Jg== | ||
resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0.tgz" | ||
integrity sha512-+dOUUaXTkPKKhtUI9QtVaYg+MpmLh2CN0dHohiYXaBirEyPMkjaT0zbRgzQlNnQWjCVVXPQluIEb0OMEjSTH+Q== | ||
|
||
"@tailwindcss/oxide@^4.0.0": | ||
version "4.0.0" | ||
|
@@ -4453,10 +4460,10 @@ levn@^0.4.1: | |
prelude-ls "^1.2.1" | ||
type-check "~0.4.0" | ||
|
||
lightningcss-win32-x64-msvc@1.29.1: | ||
lightningcss-darwin[email protected]: | ||
version "1.29.1" | ||
resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz" | ||
integrity sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q== | ||
resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz" | ||
integrity sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA== | ||
|
||
lightningcss@^1.29.1: | ||
version "1.29.1" | ||
|