Skip to content

Commit eb537ec

Browse files
committed
save - VERY WIP
1 parent 4d1a489 commit eb537ec

File tree

9 files changed

+808
-345
lines changed

9 files changed

+808
-345
lines changed

frontend/app/components/FlexLayoutComponent.tsx

Lines changed: 112 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { useEffect, useState } from "react";
33
import SuspensionGauge from "./visualizations/SuspensionGauge";
44
import CarWireframe from "./visualizations/CarWireframe";
55
import GForceGauge from "./visualizations/GForceGauge";
6-
import DemoChart from "./visualizations/DemoChart";
76
import LineChartLightning from "./visualizations/lightning-charts/LineChartLightning";
7+
import TextBox from "./visualizations/TextBox";
88

99
const model = Model.fromJson({
1010
global: {},
@@ -19,7 +19,7 @@ const model = Model.fromJson({
1919
children: [
2020
{
2121
type: "tabset",
22-
weight: 50,
22+
weight: 30,
2323
children: [
2424
{
2525
type: "tab",
@@ -30,7 +30,7 @@ const model = Model.fromJson({
3030
},
3131
{
3232
type: "tabset",
33-
weight: 50,
33+
weight: 30,
3434
children: [
3535
{
3636
type: "tab",
@@ -40,6 +40,11 @@ const model = Model.fromJson({
4040
{ type: "tab", name: "G-Force Gauge", component: "g-force-gauge" },
4141
],
4242
},
43+
{
44+
type: "tabset",
45+
weight: 40,
46+
children: [{ type: "tab", name: "Timings", component: "timings-box" }],
47+
},
4348
],
4449
},
4550
{
@@ -53,46 +58,124 @@ const model = Model.fromJson({
5358
{
5459
type: "tab",
5560
name: "Chart 1",
56-
component: "demo-chart",
61+
component: "acc-seg-0-voltage-linegraph",
62+
},
63+
],
64+
},
65+
{
66+
type: "tabset",
67+
weight: 33,
68+
children: [
69+
{
70+
type: "tab",
71+
name: "Brake Presssure (psi)",
72+
component: "brake-pressure-linegraph",
73+
},
74+
],
75+
},
76+
{
77+
type: "tabset",
78+
weight: 33,
79+
children: [
80+
{
81+
type: "tab",
82+
name: "Longitudinal Acceleration",
83+
component: "long-accel-linegraph",
5784
},
5885
],
5986
},
60-
// {
61-
// type: "tabset",
62-
// weight: 33,
63-
// children: [
64-
// {
65-
// type: "tab",
66-
// name: "Chart 2",
67-
// component: "demo-chart",
68-
// },
69-
// ],
70-
// },
71-
// {
72-
// type: "tabset",
73-
// weight: 33,
74-
// children: [
75-
// {
76-
// type: "tab",
77-
// name: "Chart 3",
78-
// component: "demo-chart",
79-
// },
80-
// ],
81-
// },
8287
],
8388
},
8489
],
8590
},
8691
});
8792

93+
// const model = Model.fromJson({
94+
// global: {},
95+
// borders: [],
96+
// layout: {
97+
// type: "row",
98+
// children: [
99+
// {
100+
// type: "row",
101+
// children: [
102+
// {
103+
// type: "tabset",
104+
// children: [
105+
// {
106+
// type: "tab",
107+
// name: "Brake Presssure (psi)",
108+
// component: "brake-pressure-linegraph",
109+
// },
110+
// ],
111+
// },
112+
// {
113+
// type: "tabset",
114+
// children: [
115+
// {
116+
// type: "tab",
117+
// name: "Longitudinal Acceleration",
118+
// component: "long-accel-linegraph",
119+
// },
120+
// ],
121+
// },
122+
// ],
123+
// },
124+
// ],
125+
// },
126+
// });
127+
88128
export default function FlexLayoutComponent() {
89129
function factory(node: TabNode) {
90130
const components = {
91131
// prettier-ignore
92-
"suspension-gauge": <SuspensionGauge s1={1} s2={1 ** 2} s3={1 ** 3} s4={1 ** 4} />,
93-
"car-wireframe": <CarWireframe/>,
132+
"suspension-gauge": <SuspensionGauge />,
133+
"car-wireframe": <CarWireframe />,
94134
"g-force-gauge": <GForceGauge x={1} y={1} z={1} />,
95-
"demo-chart": <LineChartLightning keyName="Seg0_VOLT_0"/>,
135+
"acc-seg-0-voltage-linegraph": (
136+
<LineChartLightning
137+
title={"Acc Seg 0 Voltage"}
138+
yAxisTitle="Voltage"
139+
yAxisColumns={[
140+
"Seg0_VOLT_0",
141+
"Seg0_VOLT_1",
142+
"Seg0_VOLT_2",
143+
"Seg0_VOLT_3",
144+
"Seg0_VOLT_4",
145+
"Seg0_VOLT_5",
146+
]}
147+
/>
148+
),
149+
"timings-box": (
150+
<div className="p-0">
151+
<TextBox
152+
title="Lap Time"
153+
keyName=":LapTime"
154+
/>
155+
<TextBox
156+
title="Lap Number"
157+
keyName=":Lap"
158+
/>
159+
</div>
160+
),
161+
"brake-pressure-linegraph": (
162+
<LineChartLightning
163+
// title={""}
164+
yAxisTitle="Brake Pressure (psi)"
165+
yAxisColumns={["TELEM_STEERBRAKE_BRAKEF", "TELEM_STEERBRAKE_BRAKER"]}
166+
/>
167+
),
168+
"long-accel-linegraph": (
169+
<LineChartLightning
170+
// title={""}
171+
yAxisTitle="Longitudinal Acceleration"
172+
yAxisColumns={[
173+
"VDM_X_AXIS_ACCELERATION",
174+
"VDM_Y_AXIS_ACCELERATION",
175+
"VDM_Z_AXIS_ACCELERATION",
176+
]}
177+
/>
178+
),
96179
skeleton: <div className="w-full h-full bg-neutral-500"></div>,
97180
};
98181

frontend/app/components/TimelineBar.tsx

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { Box, RangeSlider, RangeSliderValue } from "@mantine/core";
2-
import { ArrowFatLinesRight, Pause, Play } from "@phosphor-icons/react";
1+
import { Box, Button, RangeSlider, RangeSliderValue } from "@mantine/core";
2+
import { ArrowFatLinesRight, CaretDoubleRight, Pause, Play } from "@phosphor-icons/react";
33
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
44
import { useDataMethods } from "../data-processing/DataMethodsProvider";
55
import DataSourceType from "@/models/DataSourceType";
66
import useDebounceCallbackGreedy from "../utils/useGreedyDebounce";
7+
import { timeColumnName } from "../data-processing/datatypes";
78

89
export default function TimelineBar() {
910
const [paused, setPaused] = useState(true);
11+
const { switchToRecording } = useDataMethods();
1012

1113
return (
1214
<>
@@ -23,61 +25,73 @@ export default function TimelineBar() {
2325
<MainSlider />
2426
</div>
2527
<SyncButton />
28+
<Button
29+
onClick={() =>
30+
switchToRecording("fs-data/FS-2/2025-03-06-BrakingTests1.parquet")
31+
}
32+
/>
2633
</div>
2734
</>
2835
);
2936
}
3037

3138
function SyncButton() {
32-
const [isTimelineSynced, setIsTimelineSynced] = useState(false);
33-
const { subscribeIsTimelineSynced } = useDataMethods();
39+
const [enabled, setEnabled] = useState(false);
40+
const [visible, setVisible] = useState(false);
41+
const { subscribeIsTimelineSynced, setIsTimelineSynced, subscribeDataSource } =
42+
useDataMethods();
3443
useEffect(() => {
35-
return subscribeIsTimelineSynced((isTimelineSynced: boolean) => {
36-
setIsTimelineSynced(isTimelineSynced);
44+
const unsub1 = subscribeIsTimelineSynced((isTimelineSynced: boolean) => {
45+
setEnabled(isTimelineSynced);
3746
});
47+
const unsub2 = subscribeDataSource((dataSourceType) => {
48+
setVisible(dataSourceType == DataSourceType.LIVE);
49+
});
50+
return () => {
51+
unsub1();
52+
unsub2();
53+
}
54+
}, []);
55+
const setTimelineSynced = useCallback(() => {
56+
setEnabled(true);
57+
setIsTimelineSynced(true, "timelineBar");
3858
}, []);
39-
const toggleIsTimelineSynced = useCallback(() => setIsTimelineSynced(!isTimelineSynced), []);
4059

41-
return (
42-
<Box c={isTimelineSynced ? "neutral.8" : "neutral.5"}>
43-
<ArrowFatLinesRight color="currentColor" weight="fill" onClick={toggleIsTimelineSynced} />
60+
return visible ? (
61+
<Box c={enabled ? "neutral.9" : "neutral.4"}>
62+
<CaretDoubleRight
63+
color="currentColor"
64+
weight="fill"
65+
size={24}
66+
onClick={enabled ? undefined : setTimelineSynced}
67+
/>
4468
</Box>
45-
);
69+
) : null;
4670
}
4771

4872
function MainSlider() {
4973
const [disabled, setDisabled] = useState<boolean>(false);
50-
const [minMax, setMinMax] = useState<RangeSliderValue>([0, 10]); // timestamp (seconds)
74+
const [minMax, setMinMax] = useState<RangeSliderValue>([0, 10]);
5175
const [value, setValue] = useState<RangeSliderValue>([0, 10]);
5276
const debouncedSetValue = useDebounceCallbackGreedy((value) => setValue(value), 10);
5377
const ref = useRef<HTMLDivElement>(null);
54-
// id is only used to differentiate between who set viewEdges (avoid infinite recursion)
78+
// id is only used to differentiate between who set viewInterval (avoid infinite recursion)
5579
const id = "timelineBar";
5680

81+
useEffect(() => console.log("value:", value), [value]);
82+
5783
const {
5884
setViewInterval,
5985
subscribeDataSource,
6086
subscribeNumRows,
6187
subscribeViewInterval,
6288
subscribeDataInterval,
6389
viewIntervalRef,
90+
dataArraysRef,
6491
// setCursorPosition, // eventually?
6592
} = useDataMethods();
6693

67-
// useEffect(() => {
68-
// console.log("Updated minMax:", minMax);
69-
// }, [minMax]); // Runs whenever minMax updates
70-
7194
useEffect(() => {
72-
// const unsub1 = subscribeFullArrays((fullArrays) => {
73-
// const timeCol = fullArrays[timeColumnName];
74-
// // Need at least one point to set min/max!
75-
// if (timeCol && timeCol.length > 0) {
76-
// // Give 0.5s padding on either side
77-
// setMinMax([timeCol[0] - 0.5, timeCol[timeCol.length - 1] + 0.5]);
78-
// // console.log([timeCol[0] - 0.5, timeCol[timeCol.length - 1] + 0.5]);
79-
// }
80-
// });
8195
const unsub1 = subscribeDataInterval(([left, right]) => {
8296
setMinMax([left, right]);
8397
});
@@ -105,12 +119,22 @@ function MainSlider() {
105119

106120
const onChange = useCallback((range: RangeSliderValue) => {
107121
if (range[1] == viewIntervalRef.current[1]) {
108-
console.log("range[1] ==", range[1], "== value[1] ==", viewIntervalRef.current[1]);
122+
// console.log("range[1] ==", range[1], "== value[1] ==", viewIntervalRef.current[1]);
109123
} else {
110-
console.log("range[1] ==", range[1], "=/= value[1] ==", viewIntervalRef.current[1]);
124+
// console.log(
125+
// "range[1] ==",
126+
// range[1],
127+
// "=/= value[1] ==",
128+
// viewIntervalRef.current[1],
129+
// );
111130
}
112131
setValue(range);
113-
setViewInterval(range, id);
132+
// setViewInterval(range, id);
133+
134+
const val = dataArraysRef.current[timeColumnName]![range[0]];
135+
console.log("idx:", range[0], val, dataArraysRef.current[":Time"]);
136+
console.log("timeline setting range:", range);
137+
114138
}, []);
115139

116140
const sliderStyles = useMemo(
@@ -122,20 +146,29 @@ function MainSlider() {
122146
[],
123147
);
124148

149+
const formatLabel = (idx: number) => {
150+
const val = dataArraysRef.current[timeColumnName]![idx];
151+
152+
// console.log("idx:", idx, val, dataArraysRef.current[":Time"]);
153+
return val !== undefined ? val.toFixed(2) : "???";
154+
155+
};
156+
125157
return (
126158
<>
127159
<RangeSlider
128160
ref={ref}
129-
step={0.01} // 100Hz == 0.01s per point
161+
step={1} // timeline _only_ refers to indexes into data arrays, so must be integers only
130162
disabled={disabled}
131163
onChange={onChange}
132164
// it's right around the corner I can feel it...
133-
min={55000} // min={minMax[0]}
134-
max={58000} // max={minMax[1]}
135-
minRange={10}
136-
// maxRange ??
165+
min={minMax[0]}
166+
max={minMax[1]}
167+
minRange={1}
168+
maxRange={minMax[1] - minMax[0]}
137169
value={value}
138170
styles={sliderStyles}
171+
label={formatLabel}
139172
/>
140173
{/* <DraggableRangeSlider */}
141174
{/* value={sliderRange} */}

frontend/app/components/visualizations/DemoChart.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)