round graph times correctly
This commit is contained in:
parent
9fa0fd1f22
commit
b7c443fc93
|
@ -1,23 +1,42 @@
|
||||||
import Plot from "react-plotly.js";
|
import Plot from "react-plotly.js";
|
||||||
import { RecordSeries } from "../../../dataCache/data";
|
import { RecordSeries } from "../../../dataCache/data";
|
||||||
import { parseCsv, transformToGraphData } from "../../../util/graph.util";
|
import { parseCsv, transformToGraphData } from "../../../util/graph.util";
|
||||||
import { TimeSpan, UnixTime } from "../../../dataCache/time";
|
import { TimeRange, TimeSpan, UnixTime } from "../../../dataCache/time";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { ReactNode, useEffect, useMemo, useState } from "react";
|
||||||
import { BehaviorSubject, startWith, throttleTime, withLatestFrom } from "rxjs";
|
import { BehaviorSubject, startWith, throttleTime, withLatestFrom } from "rxjs";
|
||||||
import { S3Access } from "../../../dataCache/S3/S3Access";
|
import { S3Access } from "../../../dataCache/S3/S3Access";
|
||||||
import DataCache, { FetchResult } from "../../../dataCache/dataCache";
|
import DataCache, { FetchResult } from "../../../dataCache/dataCache";
|
||||||
|
import { TreeItem, TreeView } from "@mui/lab";
|
||||||
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||||
|
import { Checkbox } from "@mui/material";
|
||||||
|
|
||||||
|
export const createTimes = (
|
||||||
|
range: TimeRange,
|
||||||
|
numberOfNodes: number
|
||||||
|
): UnixTime[] => {
|
||||||
|
const oneSpan = range.duration.divide(numberOfNodes);
|
||||||
|
const roundedRange = TimeRange.fromTimes(
|
||||||
|
range.start.round(oneSpan),
|
||||||
|
range.end.round(oneSpan)
|
||||||
|
);
|
||||||
|
return roundedRange.sample(oneSpan);
|
||||||
|
};
|
||||||
|
|
||||||
|
const NUMBER_OF_NODES = 100;
|
||||||
|
|
||||||
const ScalarGraph = () => {
|
const ScalarGraph = () => {
|
||||||
const timeRange = UnixTime.fromTicks(1682085650)
|
const timeRange = createTimes(
|
||||||
.rangeBefore(TimeSpan.fromDays(1))
|
UnixTime.fromTicks(1682085650).rangeBefore(TimeSpan.fromDays(1)),
|
||||||
.sample(TimeSpan.fromMinutes(30));
|
NUMBER_OF_NODES
|
||||||
|
);
|
||||||
const [timeSeries, setTimeSeries] = useState<RecordSeries>([]);
|
const [timeSeries, setTimeSeries] = useState<RecordSeries>([]);
|
||||||
const [uiRevision, setUiRevision] = useState(Math.random());
|
const [uiRevision, setUiRevision] = useState(Math.random());
|
||||||
const [range, setRange] = useState([
|
const [range, setRange] = useState([
|
||||||
timeRange[0].toDate(),
|
timeRange[0].toDate(),
|
||||||
timeRange[timeRange.length - 1].toDate(),
|
timeRange[timeRange.length - 1].toDate(),
|
||||||
]);
|
]);
|
||||||
const [toggles, setToggles] = useState<Object | null>(null);
|
const [toggles, setToggles] = useState<TreeElement[] | null>(null);
|
||||||
|
|
||||||
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
|
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
|
||||||
|
|
||||||
|
@ -30,6 +49,24 @@ const ScalarGraph = () => {
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function insert(
|
||||||
|
children: TreeElement[] = [],
|
||||||
|
[head, ...tail]: string[]
|
||||||
|
): TreeElement[] {
|
||||||
|
let child = children.find((child) => child.name === head);
|
||||||
|
if (!child)
|
||||||
|
children.push(
|
||||||
|
(child = {
|
||||||
|
id: head + tail.join("_"),
|
||||||
|
name: head,
|
||||||
|
checked: false,
|
||||||
|
children: [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (tail.length > 0) insert(child.children, tail);
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const subscription = cache.gotData
|
const subscription = cache.gotData
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -39,15 +76,76 @@ const ScalarGraph = () => {
|
||||||
)
|
)
|
||||||
.subscribe(([_, times]) => {
|
.subscribe(([_, times]) => {
|
||||||
const timeSeries = cache.getSeries(times);
|
const timeSeries = cache.getSeries(times);
|
||||||
console.log("GOT DATA", _, times, timeSeries);
|
|
||||||
setTimeSeries(timeSeries);
|
setTimeSeries(timeSeries);
|
||||||
if (toggles === null) setToggles(timeSeries);
|
const toggleValues = timeSeries.find((timeStamp) => timeStamp.value);
|
||||||
|
|
||||||
|
if (toggles === null && toggleValues && toggleValues.value) {
|
||||||
|
setToggles(
|
||||||
|
Object.keys(toggleValues.value)
|
||||||
|
.map((path) => path.split("/").slice(1))
|
||||||
|
.reduce(
|
||||||
|
(children, path) => insert(children, path),
|
||||||
|
[] as TreeElement[]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => subscription.unsubscribe();
|
return () => subscription.unsubscribe();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const roundToNearest30 = (date: Date) => {
|
interface TreeElement {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
children: TreeElement[];
|
||||||
|
checked: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNodes = (element: TreeElement): null | ReactNode => {
|
||||||
|
return element.children.length > 0 ? renderTree(element.children) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTree = (data: TreeElement[]): ReactNode => {
|
||||||
|
return data.map((element) => {
|
||||||
|
return (
|
||||||
|
<TreeItem
|
||||||
|
id={"checkbox-tree-" + element.name}
|
||||||
|
key={element.name}
|
||||||
|
nodeId={element.name}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={element.checked}
|
||||||
|
onClick={() => {
|
||||||
|
if (toggles) {
|
||||||
|
const togglesValue = toggles;
|
||||||
|
const index = toggles?.findIndex((toggle) => {
|
||||||
|
return element.id === toggle.id;
|
||||||
|
});
|
||||||
|
if (index > 0) {
|
||||||
|
togglesValue[index] = {
|
||||||
|
...element,
|
||||||
|
checked: !element.checked,
|
||||||
|
};
|
||||||
|
setToggles(togglesValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{element.name}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
".MuiTreeItem-content": { paddingY: "12px" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getNodes(element)}
|
||||||
|
</TreeItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const round = (date: Date) => {
|
||||||
const minutes = 30;
|
const minutes = 30;
|
||||||
const ms = 1000 * 60 * minutes;
|
const ms = 1000 * 60 * minutes;
|
||||||
|
|
||||||
|
@ -72,7 +170,6 @@ const ScalarGraph = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e);
|
|
||||||
return Promise.resolve(FetchResult.tryLater);
|
return Promise.resolve(FetchResult.tryLater);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -116,20 +213,19 @@ const ScalarGraph = () => {
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
onRelayout={(params) => {
|
onRelayout={(params) => {
|
||||||
console.log("PARAMS", params);
|
|
||||||
const xaxisRange0 = params["xaxis.range[0]"];
|
const xaxisRange0 = params["xaxis.range[0]"];
|
||||||
const xaxisRange1 = params["xaxis.range[1]"];
|
const xaxisRange1 = params["xaxis.range[1]"];
|
||||||
|
|
||||||
if (xaxisRange0 && xaxisRange1) {
|
if (xaxisRange0 && xaxisRange1) {
|
||||||
const epoch0 =
|
|
||||||
roundToNearest30(new Date(xaxisRange0)).getTime() / 1000;
|
|
||||||
const epoch1 =
|
|
||||||
roundToNearest30(new Date(xaxisRange1)).getTime() / 1000;
|
|
||||||
setRange([new Date(xaxisRange0), new Date(xaxisRange1)]);
|
setRange([new Date(xaxisRange0), new Date(xaxisRange1)]);
|
||||||
setUiRevision(Math.random());
|
setUiRevision(Math.random());
|
||||||
const times = UnixTime.fromTicks(epoch1)
|
const times = createTimes(
|
||||||
.rangeBefore(TimeSpan.fromSeconds(epoch1 - epoch0))
|
TimeRange.fromTimes(
|
||||||
.sample(TimeSpan.fromMinutes(30));
|
UnixTime.fromDate(new Date(xaxisRange0)),
|
||||||
|
UnixTime.fromDate(new Date(xaxisRange1))
|
||||||
|
),
|
||||||
|
NUMBER_OF_NODES
|
||||||
|
);
|
||||||
cache.getSeries(times);
|
cache.getSeries(times);
|
||||||
times$.next(times);
|
times$.next(times);
|
||||||
}
|
}
|
||||||
|
@ -139,6 +235,25 @@ const ScalarGraph = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return <>{renderGraphs()}</>;
|
return (
|
||||||
|
<>
|
||||||
|
{renderGraphs()}
|
||||||
|
{toggles !== null && (
|
||||||
|
<TreeView
|
||||||
|
aria-label="rich object"
|
||||||
|
defaultCollapseIcon={<ExpandMoreIcon />}
|
||||||
|
defaultExpandIcon={<ChevronRightIcon />}
|
||||||
|
sx={{
|
||||||
|
height: 480,
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: "auto",
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderTree(toggles)}
|
||||||
|
</TreeView>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default ScalarGraph;
|
export default ScalarGraph;
|
||||||
|
|
|
@ -40,7 +40,6 @@ export const transformToGraphData = (timeStampData: RecordSeries) => {
|
||||||
},
|
},
|
||||||
{} as GraphData
|
{} as GraphData
|
||||||
);
|
);
|
||||||
console.log("acc", acc, timeStampObj);
|
|
||||||
return mergeDeep(acc, timeStampObj);
|
return mergeDeep(acc, timeStampObj);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
|
|
Loading…
Reference in New Issue