Skip to content

Commit

Permalink
Fixed css around enumerations.tsx. Working on Fixing overflow and ref…
Browse files Browse the repository at this point in the history
…actoring for itegration with backend
  • Loading branch information
matthlh committed Jan 31, 2025
1 parent 5247561 commit a25cca6
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 160 deletions.
6 changes: 3 additions & 3 deletions software/tracksight/frontend/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "tailwindcss";
@import 'tailwindcss';
@custom-variant dark (&:where(.dark, .dark *));

@layer base {
Expand Down Expand Up @@ -71,11 +71,11 @@
/* Dark background */
}

* {
/* * {
box-sizing: border-box;
padding: 0;
margin: 0;
}
} */

html,
body {
Expand Down
288 changes: 145 additions & 143 deletions software/tracksight/frontend/src/app/testing/components/Enumeration.tsx
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>
)
}
4 changes: 2 additions & 2 deletions software/tracksight/frontend/src/app/testing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ const TestingPage = () => {
currentTime={currentTime}
enumStates={enumStates}
/>
<NumericalGraph
{/* <NumericalGraph
numericalSignals={numericalSignals}
currentTime={currentTime}
/>
/> */}
</div>
)
}
Expand Down
31 changes: 19 additions & 12 deletions software/tracksight/frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit a25cca6

Please sign in to comment.