adds frontend history

This commit is contained in:
2024-12-30 21:36:46 -05:00
parent aa1763cbe7
commit ff0a578940
8 changed files with 184 additions and 63 deletions

View File

@@ -9,21 +9,24 @@ import {
shallowRef,
type ShallowRef,
toValue,
triggerRef,
watch,
} from 'vue';
import {
type TelemetryDataItem,
WEBSOCKET_SYMBOL,
type WebsocketHandle,
} from '@/composables/websocket';
import { GRAPH_DATA, type GraphData } from '@/graph/graph';
import { AXIS_DATA, type AxisData } from '@/graph/axis';
import ValueLabel from '@/components/ValueLabel.vue';
import type { Point } from '@/graph/line';
import { type Point, PointLine } from '@/graph/line';
const props = defineProps<{
data: string;
minimum_separation?: number;
class?: string;
fetch_history?: number;
}>();
const smoothing_distance_x = 5;
@@ -70,58 +73,100 @@ onUnmounted(() => {
);
});
const memo = shallowRef<Point[]>([]);
const memo = shallowRef(new PointLine());
watch([value], ([val]) => {
const min_x = toValue(graph_data.min_x);
if (val) {
const val_t = Date.parse(val.timestamp);
if (val_t >= min_x) {
// TODO: Insert this in the right spot in memo
const item_val = val.value[data.value!.data_type] as number;
const new_memo = [
{
x: val_t,
y: item_val,
},
].concat(memo.value);
const new_item = {
x: val_t,
y: item_val,
} as Point;
memo.value.insert(new_item);
if (item_val < min.value) {
min.value = item_val;
}
if (item_val > max.value) {
max.value = item_val;
}
memo.value = new_memo;
triggerRef(memo);
debounced_recompute();
}
}
});
watch(
[data, () => props.fetch_history],
async ([data]) => {
if (data) {
const uuid = data.uuid;
const type = data.data_type;
try {
const min_x = new Date(toValue(graph_data.min_x));
const max_x = new Date(toValue(graph_data.max_x));
const res = await fetch(
`/api/tlm/history/${uuid}?from=${min_x.toISOString()}&to=${max_x.toISOString()}&resolution=${props.minimum_separation || 0}`,
);
const response = (await res.json()) as TelemetryDataItem[];
for (const data_item of response) {
const val_t = Date.parse(data_item.timestamp);
const item_val = data_item.value[type] as number;
const new_item = {
x: val_t,
y: item_val,
} as Point;
memo.value.insert(new_item);
if (item_val < min.value) {
min.value = item_val;
}
if (item_val > max.value) {
max.value = item_val;
}
}
triggerRef(memo);
debounced_recompute();
} catch (e) {
// TODO: Response?
console.log(e);
}
}
},
{
immediate: true,
},
);
watch([graph_data.min_x, graph_data.max_x], ([min_x, max_x]) => {
let memo_changed = false;
const new_memo = ([] as Point[]).concat(memo.value);
if (min_x) {
while (
new_memo.length > 2 &&
new_memo[new_memo.length - 2].x < toValue(min_x)
memo.value.data.length > 2 &&
memo.value.data[1].x < toValue(min_x)
) {
new_memo.pop();
memo.value.data.shift();
memo_changed = true;
}
}
if (max_x) {
while (new_memo.length > 2 && new_memo[1].x > toValue(max_x)) {
new_memo.shift();
while (
memo.value.data.length > 2 &&
memo.value.data[memo.value.data.length - 2].x > toValue(max_x)
) {
memo.value.data.pop();
memo_changed = true;
}
}
if (memo_changed) {
let min_val = Infinity;
let max_val = -Infinity;
for (const item of new_memo) {
for (const item of memo.value.data) {
const item_val = item.y;
min_val = Math.min(min_val, item_val);
max_val = Math.max(max_val, item_val);
}
memo.value = new_memo;
triggerRef(memo);
debounced_recompute();
max.value = max_val;
min.value = min_val;
@@ -162,7 +207,7 @@ const group_transform = computed(() => {
watch([recompute_points], () => {
let new_points = '';
if (memo.value.length == 0 || data.value == null) {
if (memo.value.data.length == 0 || data.value == null) {
return '';
}
@@ -172,7 +217,8 @@ watch([recompute_points], () => {
let last_x = graph_data.x_map(future_number) + smoothing_distance_x;
old_max.value = toValue(graph_data.max_x);
for (const data_item of memo.value) {
for (let i = memo.value.data.length - 1; i >= 0; i--) {
const data_item = memo.value.data[i];
const t = data_item.x;
const v = data_item.y;
const x = graph_data.x_map(t);

View File

@@ -2,3 +2,40 @@ export interface Point {
x: number;
y: number;
}
export class PointLine {
data: Point[];
constructor() {
this.data = [];
}
find_index(x: number) {
if (this.data.length == 0) {
return 0;
}
// left should be too early to insert
// right should be too late to insert
let left = 0;
let size = this.data.length;
while (size > 1) {
const half = Math.floor(size / 2);
const mid = left + half;
const is_less = this.data[mid].x < x;
if (is_less) {
left = mid;
}
size -= half;
}
return left + (this.data[left].x < x ? 1 : 0);
}
insert(point: Point) {
const index = this.find_index(point.x);
this.data.splice(index, 0, point);
}
}