adds legend tooltips
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
type ShallowRef,
|
||||
toValue,
|
||||
triggerRef,
|
||||
useTemplateRef,
|
||||
watch,
|
||||
} from 'vue';
|
||||
import {
|
||||
@@ -21,6 +22,7 @@ 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, PointLine } from '@/graph/line';
|
||||
import TooltipDialog from '@/components/TooltipDialog.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
data: string;
|
||||
@@ -39,9 +41,9 @@ const min_sep = computed(() =>
|
||||
Math.min(props.minimum_separation || 0, maximum_minimum_separation_live),
|
||||
);
|
||||
|
||||
const { data } = useTelemetry(() => props.data);
|
||||
const { data: telemetry_data } = useTelemetry(() => props.data);
|
||||
const websocket = inject<ShallowRef<WebsocketHandle>>(WEBSOCKET_SYMBOL)!;
|
||||
const value = websocket.value.listen_to_telemetry(data, min_sep);
|
||||
const value = websocket.value.listen_to_telemetry(telemetry_data, min_sep);
|
||||
|
||||
const graph_data = inject<GraphData>(GRAPH_DATA)!;
|
||||
const axis_data = inject<AxisData>(AXIS_DATA)!;
|
||||
@@ -82,7 +84,9 @@ watch([value], ([val]) => {
|
||||
if (val) {
|
||||
const val_t = Date.parse(val.timestamp);
|
||||
if (val_t >= min_x) {
|
||||
const item_val = val.value[data.value!.data_type] as number;
|
||||
const item_val = val.value[
|
||||
telemetry_data.value!.data_type
|
||||
] as number;
|
||||
const new_item = {
|
||||
x: val_t,
|
||||
y: item_val,
|
||||
@@ -100,7 +104,7 @@ watch([value], ([val]) => {
|
||||
}
|
||||
});
|
||||
watch(
|
||||
[data, () => props.fetch_history],
|
||||
[telemetry_data, () => props.fetch_history],
|
||||
async ([data]) => {
|
||||
if (data) {
|
||||
const uuid = data.uuid;
|
||||
@@ -213,7 +217,7 @@ const group_transform = computed(() => {
|
||||
|
||||
watch([recompute_points], () => {
|
||||
let new_points = '';
|
||||
if (memo.value.data.length == 0 || data.value == null) {
|
||||
if (memo.value.data.length == 0 || telemetry_data.value == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -246,7 +250,7 @@ watch([recompute_points], () => {
|
||||
const current_value = computed(() => {
|
||||
const val = value.value;
|
||||
if (val) {
|
||||
return val.value[data.value!.data_type] as number;
|
||||
return val.value[telemetry_data.value!.data_type] as number;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
@@ -270,7 +274,7 @@ const legend_text = computed(() => {
|
||||
(toValue(graph_data.legend_width) -
|
||||
legend_line_length -
|
||||
legend_text_offset * 2) /
|
||||
7;
|
||||
6.5;
|
||||
const start_text = props.data;
|
||||
if (start_text.length > max_chars) {
|
||||
return (
|
||||
@@ -284,9 +288,27 @@ const legend_text = computed(() => {
|
||||
|
||||
const legend_line = computed(() => {
|
||||
const x = legend_x.value;
|
||||
const y = legend_y.value;
|
||||
const y = legend_y.value + 1 + toValue(graph_data.legend_y_stride) / 2;
|
||||
return `${x},${y} ${x + legend_line_length},${y}`;
|
||||
});
|
||||
|
||||
const is_selected = ref(false);
|
||||
const legendRectRef = useTemplateRef<SVGRectElement>('legend-ref');
|
||||
|
||||
function onOpenLegend() {
|
||||
if (!is_selected.value) {
|
||||
setTimeout(() => {
|
||||
is_selected.value = true;
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
function onCloseLegend() {
|
||||
if (is_selected.value) {
|
||||
setTimeout(() => {
|
||||
is_selected.value = false;
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -306,13 +328,61 @@ const legend_line = computed(() => {
|
||||
>
|
||||
</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"
|
||||
<rect
|
||||
ref="legend-ref"
|
||||
:class="`legend ${is_selected ? 'selected' : ''}`"
|
||||
:x="legend_x - legend_text_offset"
|
||||
:y="legend_y"
|
||||
:width="toValue(graph_data.legend_width)"
|
||||
:height="toValue(graph_data.legend_y_stride)"
|
||||
@click="onOpenLegend"
|
||||
>
|
||||
</rect>
|
||||
<polyline
|
||||
class="legend"
|
||||
fill="none"
|
||||
:points="legend_line"
|
||||
@click="onOpenLegend"
|
||||
></polyline>
|
||||
<text
|
||||
class="legend"
|
||||
:x="legend_x + legend_line_length + legend_text_offset"
|
||||
:y="legend_y + 1 + toValue(graph_data.legend_y_stride) / 2"
|
||||
@click="onOpenLegend"
|
||||
>
|
||||
{{ legend_text }}
|
||||
</text>
|
||||
<foreignObject height="0" width="0">
|
||||
<TooltipDialog
|
||||
:show="is_selected"
|
||||
:element="legendRectRef"
|
||||
@close="onCloseLegend"
|
||||
>
|
||||
<div class="column">
|
||||
<div class="row header">
|
||||
<div
|
||||
:class="`indexed-color color-${index} colored dash`"
|
||||
></div>
|
||||
<span class="large">{{ props.data }}</span>
|
||||
</div>
|
||||
<template v-if="telemetry_data">
|
||||
<div class="row">
|
||||
<span class="small">{{
|
||||
telemetry_data?.uuid
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>{{ telemetry_data?.data_type }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="row">
|
||||
<span>Unknown Signal</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</TooltipDialog>
|
||||
</foreignObject>
|
||||
</template>
|
||||
</g>
|
||||
</template>
|
||||
@@ -333,4 +403,59 @@ text {
|
||||
dominant-baseline: middle;
|
||||
font-size: variables.$small-monospace-text-size;
|
||||
}
|
||||
|
||||
rect.legend {
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
rect.legend.selected,
|
||||
rect.legend:hover,
|
||||
rect.legend:has(~ .legend:hover) {
|
||||
stroke: variables.$gray-2;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.legend {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
div.column {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-content: flex-start;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
div.row {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
div.header.row {
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
||||
div.colored.dash {
|
||||
background-color: var(--indexed-color);
|
||||
width: 0.75em;
|
||||
height: 2px;
|
||||
display: inline;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
span.large {
|
||||
font-size: variables.$large-text-size;
|
||||
}
|
||||
|
||||
span.small {
|
||||
font-size: variables.$small-text-size;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user