allows restricting the streaming speed for the frontend

This commit is contained in:
2024-12-30 13:23:21 -05:00
parent be85ea3aa6
commit 10e80a0c2d
9 changed files with 234 additions and 175 deletions

View File

@@ -7,6 +7,7 @@ import TimeText from '@/components/TimeText.vue';
const props = defineProps<{
width: number;
height: number;
duration?: number;
border_left_right?: number;
border_top_bottom?: number;
utc?: boolean;
@@ -21,7 +22,12 @@ const height = computed(() => {
});
const now = useNow(33);
const window_duration = 10 * 1000; // 10 seconds
const window_duration = computed(() => {
if (props.duration) {
return props.duration;
}
return 10 * 1000; // 10 seconds
});
const time_lines = [
1, // 1ms
@@ -58,7 +64,7 @@ const border_left_right = computed(() => props.border_left_right || 0);
const border_top_bottom = computed(() => props.border_top_bottom || 0);
const max_x = now;
const min_x = computed(() => max_x.value - window_duration);
const min_x = computed(() => max_x.value - window_duration.value);
const x_map = (x: number) => {
const diff_x = max_x.value - min_x.value;
@@ -79,10 +85,10 @@ provide<GraphData>(GRAPH_DATA, {
height: () => height.value - 2 * border_top_bottom.value,
x_map: x_map,
lines: telemetry_lines,
max_update_rate: 1000 / 10
max_update_rate: 1000 / 10,
});
const duration = computed(() => {
const line_duration = computed(() => {
const diff_x = max_x.value - min_x.value;
return time_lines.find((duration) => diff_x / duration >= 2)!;
});
@@ -90,11 +96,11 @@ const duration = computed(() => {
const lines = computed(() => {
const result = [];
for (
let i = Math.ceil(max_x.value / duration.value);
i >= Math.ceil(min_x.value / duration.value) - 5;
let i = Math.ceil(max_x.value / line_duration.value);
i >= Math.ceil(min_x.value / line_duration.value) - 5;
i--
) {
const x = i * duration.value;
const x = i * line_duration.value;
result.push(x);
}
return result;
@@ -140,7 +146,7 @@ const lines = computed(() => {
:y="height - border_top_bottom + text_offset"
:timestamp="tick"
:utc="props.utc"
:show_millis="duration < 1000"
:show_millis="line_duration < 1000"
></TimeText>
</template>
</g>

View File

@@ -12,7 +12,6 @@ import {
watch,
} from 'vue';
import {
type TelemetryDataItem,
WEBSOCKET_SYMBOL,
type WebsocketHandle,
} from '@/composables/websocket';
@@ -23,16 +22,20 @@ import type { Point } from '@/graph/line';
const props = defineProps<{
data: string;
minimum_separation?: number;
class?: string;
}>();
const smoothing_distance = 0.15 * 1000;
const smoothing_distance_x = 5;
const text_offset = computed(() => 10);
const { data } = useTelemetry(() => props.data);
const websocket = inject<ShallowRef<WebsocketHandle>>(WEBSOCKET_SYMBOL)!;
const value = websocket.value.listen_to_telemetry(data);
const value = websocket.value.listen_to_telemetry(
data,
props.minimum_separation,
);
const graph_data = inject<GraphData>(GRAPH_DATA)!;
const axis_data = inject<AxisData>(AXIS_DATA)!;
@@ -46,7 +49,10 @@ function trigger_recompute() {
recompute_points.value = Date.now();
}
function debounced_recompute() {
if (recompute_points.value + toValue(graph_data.max_update_rate) < Date.now()) {
if (
recompute_points.value + toValue(graph_data.max_update_rate) <
Date.now()
) {
trigger_recompute();
}
}
@@ -72,10 +78,12 @@ watch([value], ([val]) => {
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_memo = [
{
x: val_t,
y: item_val,
},
].concat(memo.value);
if (item_val < min.value) {
min.value = item_val;
}
@@ -100,10 +108,7 @@ watch([graph_data.min_x, graph_data.max_x], ([min_x, max_x]) => {
}
}
if (max_x) {
while (
new_memo.length > 2 &&
new_memo[1].x > toValue(max_x)
) {
while (new_memo.length > 2 && new_memo[1].x > toValue(max_x)) {
new_memo.shift();
memo_changed = true;
}
@@ -137,7 +142,7 @@ watch(
watch(
[max, axis_data.axis_update_watch],
([max_val]) => {
trigger_recompute()
trigger_recompute();
axis_data.max_y_callback(max_val);
},
{
@@ -145,7 +150,7 @@ watch(
},
);
const points = ref("");
const points = ref('');
const old_max = ref(0);
@@ -153,42 +158,38 @@ const group_transform = computed(() => {
const new_max = toValue(graph_data.max_x);
const offset = graph_data.x_map(old_max.value) - graph_data.x_map(new_max);
return `translate(${offset} 0)`;
})
});
watch(
[recompute_points],
() => {
let new_points = '';
if (memo.value.length == 0 || data.value == null) {
return '';
}
const future_number = toValue(graph_data.max_x) + 99999999;
let last_x = graph_data.x_map(future_number);
old_max.value = toValue(graph_data.max_x);
let last_t = future_number + smoothing_distance;
for (const data_item of memo.value) {
const t = data_item.x;
const v = data_item.y;
const x = graph_data.x_map(t);
const y = axis_data.y_map(v);
if (last_t - t < smoothing_distance) {
new_points += ` ${x},${y}`;
} else {
new_points += ` ${last_x},${y} ${x},${y}`;
}
last_x = x;
last_t = t;
if (last_x <= 0.0) {
break;
}
}
points.value = new_points;
watch([recompute_points], () => {
let new_points = '';
if (memo.value.length == 0 || data.value == null) {
return '';
}
)
const future_number =
toValue(graph_data.max_x) + toValue(graph_data.max_update_rate);
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) {
const t = data_item.x;
const v = data_item.y;
const x = graph_data.x_map(t);
const y = axis_data.y_map(v);
if (last_x - x < smoothing_distance_x) {
new_points += ` ${x},${y}`;
} else {
new_points += ` ${last_x},${y} ${x},${y}`;
}
last_x = x;
if (last_x <= 0.0) {
break;
}
}
points.value = new_points;
});
const current_value = computed(() => {
const val = value.value;
@@ -201,9 +202,7 @@ const current_value = computed(() => {
<template>
<g :class="`indexed-color color-${index}`">
<g
clip-path="url(#content)"
>
<g clip-path="url(#content)">
<polyline
fill="none"
:transform="group_transform"

View File

@@ -94,6 +94,7 @@ export class WebsocketHandle {
listen_to_telemetry(
telemetry: MaybeRefOrGetter<TelemetryDefinition | null>,
minimum_separation_ms: MaybeRefOrGetter<number> | undefined,
) {
const value_result = ref<TelemetryDataItem | null>(null);
@@ -105,24 +106,36 @@ export class WebsocketHandle {
return null;
});
watch([uuid, this.connected], ([uuid_value, connected]) => {
if (connected && uuid_value) {
this.websocket?.send(
JSON.stringify({
RegisterTlmListener: {
uuid: uuid_value,
},
}),
);
if (!this.on_telem_value.has(uuid_value)) {
this.on_telem_value.set(uuid_value, []);
}
this.on_telem_value.get(uuid_value)?.push((value) => {
value_result.value = value;
});
const minimum_separation = computed(() => {
const min_sep = toValue(minimum_separation_ms);
if (min_sep) {
return min_sep;
}
return 0;
});
watch(
[uuid, this.connected, minimum_separation],
([uuid_value, connected, min_sep]) => {
if (connected && uuid_value) {
this.websocket?.send(
JSON.stringify({
RegisterTlmListener: {
uuid: uuid_value,
minimum_separation_ms: min_sep,
},
}),
);
if (!this.on_telem_value.has(uuid_value)) {
this.on_telem_value.set(uuid_value, []);
}
this.on_telem_value.get(uuid_value)?.push((value) => {
value_result.value = value;
});
}
},
);
return value_result;
}
}

View File

@@ -10,5 +10,5 @@ export interface GraphData {
height: MaybeRefOrGetter<number>;
x_map: (x: number) => number;
lines: Ref<symbol[]>;
max_update_rate: MaybeRefOrGetter<number>,
max_update_rate: MaybeRefOrGetter<number>;
}

View File

@@ -1,5 +1,4 @@
export interface Point {
x: number,
y: number,
x: number;
y: number;
}

View File

@@ -4,7 +4,6 @@ import { provide } from 'vue';
import Graph from '@/components/SvgGraph.vue';
import Axis from '@/components/GraphAxis.vue';
import Line from '@/components/TelemetryLine.vue';
import { AxisSide } from '@/graph/axis';
const websocket = useWebsocket();
provide(WEBSOCKET_SYMBOL, websocket);
@@ -29,16 +28,41 @@ provide(WEBSOCKET_SYMBOL, websocket);
:height="400"
:border_top_bottom="24"
:border_left_right="128"
:duration="60 * 1000"
>
<Axis>
<Line data="simple_producer/sin"></Line>
<Line data="simple_producer/cos4"></Line>
<Line data="simple_producer/sin2"></Line>
<Line data="simple_producer/cos"></Line>
<Line data="simple_producer/sin3"></Line>
<Line data="simple_producer/cos2"></Line>
<Line data="simple_producer/sin4"></Line>
<Line data="simple_producer/cos3"></Line>
<Line
data="simple_producer/sin"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/cos4"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/sin2"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/cos"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/sin3"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/cos2"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/sin4"
:minimum_separation="100"
></Line>
<Line
data="simple_producer/cos3"
:minimum_separation="100"
></Line>
</Axis>
</Graph>
<Graph
@@ -46,6 +70,7 @@ provide(WEBSOCKET_SYMBOL, websocket);
:height="400"
:border_top_bottom="24"
:border_left_right="128"
:duration="5 * 1000"
>
</Graph>
<Graph
@@ -53,6 +78,7 @@ provide(WEBSOCKET_SYMBOL, websocket);
:height="400"
:border_top_bottom="24"
:border_left_right="128"
:duration="2 * 1000"
>
</Graph>
</main>