Skip to content

Commit

Permalink
added enumeration/numerical to git tracked
Browse files Browse the repository at this point in the history
  • Loading branch information
myung03 committed Nov 23, 2024
1 parent 1dde808 commit e3ae7e0
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React, { useState, useEffect, useRef } from "react";

interface EnumerationGraphProps {
signalName: string;
currentState: string;
currentTime: number;
enumStates: string[];
}

interface StateHistoryItem {
state: string;
startTime: number;
}

interface StateBar {
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; // seconds

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, currentTime]);

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]);

// Calculate pixels per second
const containerWidth = containerRef.current?.offsetWidth || window.innerWidth;
const pixelsPerSecond = containerWidth / timeWindow;

// Calculate positions and widths for each state
const stateBars: StateBar[] = stateHistory.map((state, index) => {
const nextState = stateHistory[index + 1];

// Adjust start and end times to the bounds of the time window
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)) * pixelsPerSecond;
const duration = barEndTime - barStartTime;
const width = duration * pixelsPerSecond;

return {
...state,
left: startOffset,
width,
};
});

// Colors for the states, mapping to indices
const stateColors: string[] = [
"#FF3B2F",
"#FFCC02",
"#FF9500",
"#35C759",
"#007AFF",
];

// Helper function to get color based on state
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 * 1000
).toLocaleTimeString()})`}
></div>
)
)}
</div>
</div>
);
};

export default EnumerationGraph;
115 changes: 115 additions & 0 deletions software/tracksight/frontend/src/app/testing/components/Numerical.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useState, useEffect } from "react";
import {
AreaChart,
Area,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
} from "recharts";

interface DataPoint {
time: number;
[signalName: string]: number; // Dynamic keys for signal values
}

interface NumericalGraphProps {
currentTime: number;
numericalSignals: string[];
}

const NumericalGraph: React.FC<NumericalGraphProps> = ({
currentTime,
numericalSignals,
}) => {
const [data, setData] = useState<DataPoint[]>([]);
const updateInterval = 200; // Update every 200 milliseconds

useEffect(() => {
const newDataPoint: DataPoint = { time: currentTime };

// Generate random values for each numerical signal
numericalSignals.forEach((signalName) => {
newDataPoint[signalName] = Math.floor(Math.random() * 100);
});

setData((prevData) => {
const timeWindow = 30000; // 30 seconds in milliseconds
const cutoffTime = currentTime - timeWindow;
const filteredData = prevData.filter((d) => d.time >= cutoffTime);
return [...filteredData, newDataPoint];
});
}, [currentTime, numericalSignals]);

const colors = ["#ff4d4f", "#ffa940", "#36cfc9", "#597ef7", "#73d13d"];

return (
<div className="w-full h-64">
<div className="ml-24 mt-4 text-xs flex gap-4">
{numericalSignals.map((signalName) => (
<div key={signalName} className="flex items-center mb-1">
<div
className="w-3 h-3 inline-block mr-2"
style={{
backgroundColor: colors[numericalSignals.indexOf(signalName)],
}}
></div>
<span className="text-gray-500">{signalName}</span>
</div>
))}
</div>
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={data}>
<defs>
{numericalSignals.map((signalName, index) => (
<linearGradient
key={signalName}
id={`color${signalName}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor={colors[index % colors.length]}
stopOpacity={0.8}
/>
<stop
offset="95%"
stopColor={colors[index % colors.length]}
stopOpacity={0}
/>
</linearGradient>
))}
</defs>
<XAxis
dataKey="time"
type="number"
domain={["dataMin", "dataMax"]}
hide
/>
<YAxis />
<Tooltip
labelFormatter={(value) => new Date(value).toLocaleTimeString()}
formatter={(value, name) => [`${value}`, `${name}`]}
/>
{numericalSignals.map((signalName, index) => (
<Area
key={signalName}
type="monotone"
dataKey={signalName}
stroke={colors[index % colors.length]}
fillOpacity={1}
fill={`url(#color${signalName})`}
isAnimationActive={true}
animationDuration={updateInterval}
/>
))}
</AreaChart>
</ResponsiveContainer>
</div>
);
};

export default NumericalGraph;

0 comments on commit e3ae7e0

Please sign in to comment.