diff --git a/frontend/src/components/GraphAxis.vue b/frontend/src/components/GraphAxis.vue index 464d6c2..339b85b 100644 --- a/frontend/src/components/GraphAxis.vue +++ b/frontend/src/components/GraphAxis.vue @@ -3,6 +3,7 @@ import { computed, inject, provide, ref, toValue, watch } from 'vue'; import { AXIS_DATA, type AxisData, AxisType } from '@/graph/axis'; import { GRAPH_DATA, type GraphData, GraphSide } from '@/graph/graph'; import NumericText from '@/components/NumericText.vue'; +import { useNow } from '@/composables/ticker'; const props = defineProps<{ y_limits?: [number, number]; @@ -28,7 +29,9 @@ const raw_max_y = ref(-Infinity); const axis_update_watch = ref(0); -watch([graph_data.min_x, graph_data.max_x], () => { +const axis_update_ticker = useNow(50); + +watch([graph_data.min_x, graph_data.max_x, axis_update_ticker], () => { axis_update_watch.value++; min_y.value = raw_min_y.value; max_y.value = raw_max_y.value; diff --git a/frontend/src/components/SvgGraph.vue b/frontend/src/components/SvgGraph.vue index 01421cd..1c78bd3 100644 --- a/frontend/src/components/SvgGraph.vue +++ b/frontend/src/components/SvgGraph.vue @@ -11,6 +11,7 @@ import { import { useNow } from '@/composables/ticker'; import { GRAPH_DATA, type GraphData, GraphSide } from '@/graph/graph'; import TimeText from '@/components/TimeText.vue'; +import { getDateString } from '@/datetime'; const props = defineProps<{ duration?: number; @@ -107,11 +108,47 @@ const border_right = computed( const border_top = computed(() => 6); const border_bottom = computed(() => (props.hide_time_labels ? 6 : 24)); -const max_x = now; +const max_x = ref(now.value); const min_x = computed(() => max_x.value - window_duration.value); +const fetch_history = ref(0); + const diff_x = computed(() => max_x.value - min_x.value); +const live = ref(true); +watch([live], ([live_value]) => { + if (live_value) { + fetch_history.value++; + } +}); +const valid_max_x_text = ref(true); +watch([now], ([now_value]) => { + if (live.value) { + max_x.value = now_value; + valid_max_x_text.value = true; + } +}); + +const max_x_text = computed({ + // getter + get() { + return getDateString(new Date(max_x.value), props.utc, true); + }, + // setter + set(newValue) { + const new_max_x = Date.parse( + newValue.replace('/', '-').replace('/', '-').replace(' ', 'T'), + ); + if (!Number.isNaN(new_max_x)) { + fetch_history.value++; + max_x.value = new_max_x; + valid_max_x_text.value = true; + } else { + valid_max_x_text.value = false; + } + }, +}); + const x_map = (x: number) => { return ( ((width.value - border_left.value - border_right.value) * @@ -203,7 +240,9 @@ const should_fade = ref(false); provide(GRAPH_DATA, { border_top: border_top, min_x: min_x, - max_x: now, + max_x: max_x, + live: live, + fetch_history: fetch_history, width: () => Math.max(width.value - border_left.value - border_right.value, 0), height: () => @@ -231,7 +270,17 @@ provide(GRAPH_DATA, { >
- Duration Dropdown + +
+
+ +
(); const smoothing_distance_x = 5; @@ -42,13 +41,17 @@ const min_sep = computed(() => Math.min(props.minimum_separation || 0, maximum_minimum_separation_live), ); -const { data: telemetry_data } = useTelemetry(() => props.data); -const websocket = inject>(WEBSOCKET_SYMBOL)!; -const value = websocket.value.listen_to_telemetry(telemetry_data, min_sep); - const graph_data = inject(GRAPH_DATA)!; const axis_data = inject(AXIS_DATA)!; +const { data: telemetry_data } = useTelemetry(() => props.data); +const websocket = inject>(WEBSOCKET_SYMBOL)!; +const value = websocket.value.listen_to_telemetry( + telemetry_data, + min_sep, + graph_data.live, +); + const min = ref(Infinity); const max = ref(-Infinity); @@ -104,8 +107,9 @@ watch([value], ([val]) => { } } }); +const recompute_bounds = ref(0); watch( - [telemetry_data, () => props.fetch_history], + [telemetry_data, () => toValue(graph_data.fetch_history)], async ([data]) => { if (data) { const uuid = data.uuid; @@ -137,9 +141,10 @@ watch( ); triggerRef(memo); debounced_recompute(); + recompute_bounds.value++; } catch (e) { // TODO: Response? - console.log(e); + console.error(e); } } }, @@ -170,19 +175,22 @@ watch([graph_data.min_x, graph_data.max_x], ([min_x, max_x]) => { } } if (memo_changed) { - let min_val = Infinity; - let max_val = -Infinity; - for (let i = 1; i < memo.value.data.length; i++) { - const item_val = memo.value.data[i].y; - min_val = Math.min(min_val, item_val); - max_val = Math.max(max_val, item_val); - } - triggerRef(memo); - debounced_recompute(); - max.value = max_val; - min.value = min_val; + recompute_bounds.value++; } }); +watch([recompute_bounds], () => { + let min_val = Infinity; + let max_val = -Infinity; + for (let i = 1; i < memo.value.data.length; i++) { + const item_val = memo.value.data[i].y; + min_val = Math.min(min_val, item_val); + max_val = Math.max(max_val, item_val); + } + triggerRef(memo); + debounced_recompute(); + max.value = max_val; + min.value = min_val; +}); watch( [min, axis_data.axis_update_watch], @@ -354,7 +362,7 @@ function onMouseExit(event: MouseEvent) { :cx="marker_radius" :cy="marker_radius" :r="marker_radius" - :class="`indexed-color color-${index}`" + :class="`indexed-color color-${index} marker`" /> @@ -446,6 +454,10 @@ function onMouseExit(event: MouseEvent) {