add graph legends
This commit is contained in:
@@ -31,6 +31,12 @@ $major-tick: $gray-4;
|
||||
$minor-tick: $gray-5;
|
||||
|
||||
$text-font: Helvetica, sans-serif;
|
||||
$normal-text-size: 16px;
|
||||
$small-text-size: 12px;
|
||||
|
||||
$monospace-text-font: Monaco, monospace, monospace;
|
||||
$normal-monospace-text-size: 12px;
|
||||
$small-monospace-text-size: 10px;
|
||||
|
||||
$colors: (
|
||||
$red-1,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, provide, ref } from 'vue';
|
||||
import { useNow } from '@/composables/ticker';
|
||||
import { GRAPH_DATA, type GraphData } from '@/graph/graph';
|
||||
import { GRAPH_DATA, type GraphData, GraphSide } from '@/graph/graph';
|
||||
import TimeText from '@/components/TimeText.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -13,6 +13,7 @@ const props = defineProps<{
|
||||
right_axis?: boolean;
|
||||
hide_time_labels?: boolean;
|
||||
hide_time_ticks?: boolean;
|
||||
legend?: GraphSide;
|
||||
}>();
|
||||
|
||||
const width = computed(() => {
|
||||
@@ -62,8 +63,9 @@ const time_lines = [
|
||||
time_lines.reverse();
|
||||
const text_offset = computed(() => 5);
|
||||
|
||||
const border_left = computed(() => props.left_axis ? 96 : 0);
|
||||
const border_right = computed(() => props.right_axis ? 80 : 0);
|
||||
const legend_width = 160;
|
||||
const border_left = computed(() => (props.left_axis ? 96 : 0) + (props.legend == GraphSide.Left ? legend_width : 0));
|
||||
const border_right = computed(() => (props.right_axis ? 80 : 0) + (props.legend == GraphSide.Right ? legend_width : 0));
|
||||
const border_top = computed(() => 6);
|
||||
const border_bottom = computed(() => props.hide_time_labels ? 6 : 24);
|
||||
|
||||
@@ -81,6 +83,13 @@ const x_map = (x: number) => {
|
||||
|
||||
const telemetry_lines = ref([]);
|
||||
|
||||
const legend_enabled = computed(() => props.legend === GraphSide.Left || props.legend === GraphSide.Right);
|
||||
const legend_x = computed(() => (props.legend === GraphSide.Left) ? (8) : (width.value - legend_width + 8));
|
||||
const legend_y = computed(() => border_top.value);
|
||||
const legend_x_stride = computed(() => 0);
|
||||
const legend_y_stride = computed(() => 16);
|
||||
const legend_width_output = computed(() => legend_width - 8);
|
||||
|
||||
provide<GraphData>(GRAPH_DATA, {
|
||||
border_top: border_top,
|
||||
min_x: min_x,
|
||||
@@ -90,6 +99,12 @@ provide<GraphData>(GRAPH_DATA, {
|
||||
x_map: x_map,
|
||||
lines: telemetry_lines,
|
||||
max_update_rate: 1000 / 10,
|
||||
legend_enabled: legend_enabled,
|
||||
legend_x: legend_x,
|
||||
legend_y: legend_y,
|
||||
legend_x_stride: legend_x_stride,
|
||||
legend_y_stride: legend_y_stride,
|
||||
legend_width: legend_width_output,
|
||||
});
|
||||
|
||||
const line_duration = computed(() => {
|
||||
|
||||
@@ -31,6 +31,8 @@ const props = defineProps<{
|
||||
|
||||
const smoothing_distance_x = 5;
|
||||
const maximum_minimum_separation_live = 100; // ms
|
||||
const legend_line_length = 8;
|
||||
const legend_text_offset = 4;
|
||||
|
||||
const text_offset = computed(() => 10);
|
||||
const min_sep = computed(() => Math.min(props.minimum_separation || 0, maximum_minimum_separation_live));
|
||||
@@ -247,6 +249,30 @@ const current_value = computed(() => {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const legend_x = computed(() => {
|
||||
return toValue(graph_data.legend_x) + toValue(graph_data.legend_x_stride) * index.value;
|
||||
});
|
||||
|
||||
const legend_y = computed(() => {
|
||||
return toValue(graph_data.legend_y) + toValue(graph_data.legend_y_stride) * index.value;
|
||||
});
|
||||
|
||||
const legend_text = computed(() => {
|
||||
const max_chars = (toValue(graph_data.legend_width) - legend_line_length - legend_text_offset * 2) / 7;
|
||||
const start_text = props.data;
|
||||
if (start_text.length > max_chars) {
|
||||
return start_text.substring(0, 3) + "..." + start_text.substring(start_text.length - max_chars + 6);
|
||||
}
|
||||
return start_text;
|
||||
});
|
||||
|
||||
const legend_line = computed(() => {
|
||||
let x = legend_x.value;
|
||||
let y = legend_y.value;
|
||||
return `${x},${y} ${x + legend_line_length},${y}`;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -265,6 +291,17 @@ const current_value = computed(() => {
|
||||
:value="current_value"
|
||||
>
|
||||
</ValueLabel>
|
||||
<template v-if="toValue(graph_data.legend_enabled)">
|
||||
<polyline
|
||||
fill="none"
|
||||
:points="legend_line"
|
||||
></polyline>
|
||||
<text
|
||||
:x="legend_x + legend_line_length + legend_text_offset"
|
||||
:y="legend_y">
|
||||
{{ legend_text }}
|
||||
</text>
|
||||
</template>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
@@ -275,4 +312,14 @@ polyline {
|
||||
stroke-width: 1px;
|
||||
stroke: var(--indexed-color);
|
||||
}
|
||||
|
||||
text {
|
||||
font-family: variables.$monospace-text-font;
|
||||
text-anchor: start;
|
||||
stroke: variables.$text-color;
|
||||
fill: variables.$text-color;
|
||||
dominant-baseline: middle;
|
||||
font-size: variables.$small-monospace-text-size;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { MaybeRefOrGetter, Ref } from 'vue';
|
||||
|
||||
export enum GraphSide {
|
||||
Hidden,
|
||||
Right,
|
||||
Left,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
export const GRAPH_DATA = Symbol();
|
||||
@@ -17,4 +17,10 @@ export interface GraphData {
|
||||
x_map: (x: number) => number;
|
||||
lines: Ref<symbol[]>;
|
||||
max_update_rate: MaybeRefOrGetter<number>;
|
||||
legend_enabled: MaybeRefOrGetter<boolean>;
|
||||
legend_x: MaybeRefOrGetter<number>;
|
||||
legend_x_stride: MaybeRefOrGetter<number>;
|
||||
legend_y: MaybeRefOrGetter<number>;
|
||||
legend_y_stride: MaybeRefOrGetter<number>;
|
||||
legend_width: MaybeRefOrGetter<number>;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { provide } from 'vue';
|
||||
import Graph from '@/components/SvgGraph.vue';
|
||||
import Axis from '@/components/GraphAxis.vue';
|
||||
import Line from '@/components/TelemetryLine.vue';
|
||||
import { GraphSide } from '@/graph/graph';
|
||||
|
||||
const websocket = useWebsocket();
|
||||
provide(WEBSOCKET_SYMBOL, websocket);
|
||||
@@ -15,6 +16,7 @@ provide(WEBSOCKET_SYMBOL, websocket);
|
||||
:width="800"
|
||||
:height="400"
|
||||
:right_axis="true"
|
||||
:legend="GraphSide.Left"
|
||||
>
|
||||
<Axis>
|
||||
<Line data="simple_producer/time_offset"></Line>
|
||||
@@ -27,6 +29,7 @@ provide(WEBSOCKET_SYMBOL, websocket);
|
||||
:height="400"
|
||||
:duration="60 * 1000 * 10"
|
||||
:right_axis="true"
|
||||
:legend="GraphSide.Right"
|
||||
>
|
||||
<Axis>
|
||||
<Line
|
||||
|
||||
Reference in New Issue
Block a user