adds frontend history
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user