change format settings

This commit is contained in:
2024-12-04 20:00:18 -08:00
parent 07b585f956
commit 4c2b0f454b
14 changed files with 691 additions and 665 deletions

View File

@@ -1,303 +1,321 @@
<script setup lang="ts">
import { computed, inject, provide, ref, toValue, watch } from 'vue'
import { AXIS_DATA, type AxisData, AxisSide, AxisType } from '@/graph/axis'
import { useNow } from '@/composables/ticker'
import { GRAPH_DATA, type GraphData } from '@/graph/graph'
import { computed, inject, provide, ref, toValue, watch } from 'vue';
import { AXIS_DATA, type AxisData, AxisSide, AxisType } from '@/graph/axis';
import { useNow } from '@/composables/ticker';
import { GRAPH_DATA, type GraphData } from '@/graph/graph';
const props = defineProps<{
y_limits?: [number, number]
side?: AxisSide
type?: AxisType
}>()
y_limits?: [number, number];
side?: AxisSide;
type?: AxisType;
}>();
const minor_tick_length = computed(() => 4)
const major_tick_length = computed(() => 8)
const text_offset = computed(() => 5)
const side = computed(() => props.side || AxisSide.Right)
const type = computed(() => props.type || AxisType.Linear)
const minor_tick_length = computed(() => 4);
const major_tick_length = computed(() => 8);
const text_offset = computed(() => 5);
const side = computed(() => props.side || AxisSide.Right);
const type = computed(() => props.type || AxisType.Linear);
const ticker_locations = [Math.log10(1), Math.log10(2), Math.log10(5)]
ticker_locations.reverse()
const ticker_locations = [Math.log10(1), Math.log10(2), Math.log10(5)];
ticker_locations.reverse();
const ticker = useNow(33)
const ticker = useNow(33);
const min_y = ref(Infinity)
const max_y = ref(-Infinity)
const raw_min_y = ref(Infinity)
const raw_max_y = ref(-Infinity)
const min_y = ref(Infinity);
const max_y = ref(-Infinity);
const raw_min_y = ref(Infinity);
const raw_max_y = ref(-Infinity);
const axis_update_watch = ref(0)
const axis_update_watch = ref(0);
watch([ticker], () => {
axis_update_watch.value++
min_y.value = raw_min_y.value
max_y.value = raw_max_y.value
raw_min_y.value = Infinity
raw_max_y.value = -Infinity
})
axis_update_watch.value++;
min_y.value = raw_min_y.value;
max_y.value = raw_max_y.value;
raw_min_y.value = Infinity;
raw_max_y.value = -Infinity;
});
function update_min_y(y: number) {
if (y < min_y.value) {
min_y.value = y
}
if (y < raw_min_y.value) {
raw_min_y.value = y
}
if (y < min_y.value) {
min_y.value = y;
}
if (y < raw_min_y.value) {
raw_min_y.value = y;
}
}
function update_max_y(y: number) {
if (y > max_y.value) {
max_y.value = y
}
if (y > raw_max_y.value) {
raw_max_y.value = y
}
if (y > max_y.value) {
max_y.value = y;
}
if (y > raw_max_y.value) {
raw_max_y.value = y;
}
}
// const half_diff_y_value = computed(() => (max_y.value - min_y.value) / 2.0);
// const average_y_value = computed(() => min_y.value + half_diff_y_value.value);
const min_y_value = computed(() => {
if (props.y_limits) {
return props.y_limits[0]
}
if (type.value == AxisType.Linear) {
if (max_y.value > min_y.value) {
const half_diff_y_value = (max_y.value - min_y.value) / 2.0
const average_y_value = min_y.value + half_diff_y_value
return average_y_value - half_diff_y_value * 1.05
} else {
return -1.0
if (props.y_limits) {
return props.y_limits[0];
}
} else {
if (max_y.value > min_y.value) {
const half_diff_y_value =
(Math.log(max_y.value) - Math.log(min_y.value)) / 2.0
const average_y_value = Math.log(min_y.value) + half_diff_y_value
return Math.exp(average_y_value - half_diff_y_value * 1.05)
if (type.value == AxisType.Linear) {
if (max_y.value > min_y.value) {
const half_diff_y_value = (max_y.value - min_y.value) / 2.0;
const average_y_value = min_y.value + half_diff_y_value;
return average_y_value - half_diff_y_value * 1.05;
} else {
return -1.0;
}
} else {
return 0.0
if (max_y.value > min_y.value) {
const half_diff_y_value =
(Math.log(max_y.value) - Math.log(min_y.value)) / 2.0;
const average_y_value = Math.log(min_y.value) + half_diff_y_value;
return Math.exp(average_y_value - half_diff_y_value * 1.05);
} else {
return 0.0;
}
}
}
})
});
const max_y_value = computed(() => {
if (props.y_limits) {
return props.y_limits[1]
}
if (type.value == AxisType.Linear) {
if (max_y.value > min_y.value) {
const half_diff_y_value = (max_y.value - min_y.value) / 2.0
const average_y_value = min_y.value + half_diff_y_value
return average_y_value + half_diff_y_value * 1.05
} else {
return 1.0
if (props.y_limits) {
return props.y_limits[1];
}
} else {
if (max_y.value > min_y.value) {
const half_diff_y_value =
(Math.log(max_y.value) - Math.log(min_y.value)) / 2.0
const average_y_value = Math.log(min_y.value) + half_diff_y_value
return Math.exp(average_y_value + half_diff_y_value * 1.05)
if (type.value == AxisType.Linear) {
if (max_y.value > min_y.value) {
const half_diff_y_value = (max_y.value - min_y.value) / 2.0;
const average_y_value = min_y.value + half_diff_y_value;
return average_y_value + half_diff_y_value * 1.05;
} else {
return 1.0;
}
} else {
return 1.0
if (max_y.value > min_y.value) {
const half_diff_y_value =
(Math.log(max_y.value) - Math.log(min_y.value)) / 2.0;
const average_y_value = Math.log(min_y.value) + half_diff_y_value;
return Math.exp(average_y_value + half_diff_y_value * 1.05);
} else {
return 1.0;
}
}
}
})
});
const graph_data = inject<GraphData>(GRAPH_DATA)!
const graph_data = inject<GraphData>(GRAPH_DATA)!;
const y_map = (y: number) => {
const height = toValue(graph_data.height)
const border_top_bottom = toValue(graph_data.border_top_bottom)
let max_value = toValue(max_y_value)
let min_value = toValue(min_y_value)
let y_value = y
if (type.value == AxisType.Logarithmic) {
max_value = Math.log(max_value)
min_value = Math.log(min_value)
y_value = Math.log(y_value)
}
const diff_y = max_value - min_value
return height * (1 - (y_value - min_value) / diff_y) + border_top_bottom
}
const height = toValue(graph_data.height);
const border_top_bottom = toValue(graph_data.border_top_bottom);
let max_value = toValue(max_y_value);
let min_value = toValue(min_y_value);
let y_value = y;
if (type.value == AxisType.Logarithmic) {
max_value = Math.log(max_value);
min_value = Math.log(min_value);
y_value = Math.log(y_value);
}
const diff_y = max_value - min_value;
return height * (1 - (y_value - min_value) / diff_y) + border_top_bottom;
};
provide<AxisData>(AXIS_DATA, {
axis_update_watch: axis_update_watch,
min_y_callback: update_min_y,
max_y_callback: update_max_y,
y_map: y_map,
})
axis_update_watch: axis_update_watch,
min_y_callback: update_min_y,
max_y_callback: update_max_y,
y_map: y_map,
});
const lines = computed(() => {
const diff_y_val = (max_y_value.value - min_y_value.value) / 2
const diff_log10 = Math.log10(diff_y_val)
const diff_log10_fraction = diff_log10 - Math.floor(diff_log10)
const ticker_location = ticker_locations.find(
location => location < diff_log10_fraction,
)!
const grid_spread = Math.pow(10, Math.floor(diff_log10) + ticker_location)
const major_spread = grid_spread / 2
const minor_spread = major_spread / 2
const minor_ticks = []
const major_ticks = []
const grid_lines = []
for (
let i = Math.floor(min_y_value.value / grid_spread);
i <= Math.ceil(max_y_value.value / grid_spread);
i++
) {
const y = i * grid_spread
grid_lines.push(y)
}
for (
let i = Math.floor(min_y_value.value / major_spread);
i <= Math.ceil(max_y_value.value / major_spread);
i++
) {
const y = i * major_spread
if (grid_lines.indexOf(y) < 0) {
major_ticks.push(y)
const diff_y_val = (max_y_value.value - min_y_value.value) / 2;
const diff_log10 = Math.log10(diff_y_val);
const diff_log10_fraction = diff_log10 - Math.floor(diff_log10);
const ticker_location = ticker_locations.find(
(location) => location < diff_log10_fraction,
)!;
const grid_spread = Math.pow(10, Math.floor(diff_log10) + ticker_location);
const major_spread = grid_spread / 2;
const minor_spread = major_spread / 2;
const minor_ticks = [];
const major_ticks = [];
const grid_lines = [];
for (
let i = Math.floor(min_y_value.value / grid_spread);
i <= Math.ceil(max_y_value.value / grid_spread);
i++
) {
const y = i * grid_spread;
grid_lines.push(y);
}
}
for (
let i = Math.floor(min_y_value.value / minor_spread);
i <= Math.ceil(max_y_value.value / minor_spread);
i++
) {
const y = i * minor_spread
if (grid_lines.indexOf(y) < 0 && major_ticks.indexOf(y) < 0) {
minor_ticks.push(y)
for (
let i = Math.floor(min_y_value.value / major_spread);
i <= Math.ceil(max_y_value.value / major_spread);
i++
) {
const y = i * major_spread;
if (grid_lines.indexOf(y) < 0) {
major_ticks.push(y);
}
}
}
return [minor_ticks, major_ticks, grid_lines]
})
for (
let i = Math.floor(min_y_value.value / minor_spread);
i <= Math.ceil(max_y_value.value / minor_spread);
i++
) {
const y = i * minor_spread;
if (grid_lines.indexOf(y) < 0 && major_ticks.indexOf(y) < 0) {
minor_ticks.push(y);
}
}
return [minor_ticks, major_ticks, grid_lines];
});
</script>
<template>
<template v-if="side == AxisSide.Right">
<g class="minor_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[0]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - minor_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(2) }}</text
>
</template>
<template v-if="side == AxisSide.Right">
<g class="minor_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[0]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - minor_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.max_x)) +
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(2) }}</text
>
</template>
</g>
<g class="major_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[1]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - major_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.max_x)) +
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(1) }}</text
>
</template>
</g>
<g class="grid_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[2]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.max_x)) +
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(0) }}</text
>
</template>
</g>
</template>
<template v-if="side == AxisSide.Left">
<g class="minor_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[0]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x)) + minor_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.min_x)) -
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(2) }}</text
>
</template>
</g>
<g class="major_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[1]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - major_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.min_x)) -
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(1) }}</text
>
</template>
</g>
<g class="grid_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[2]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="
graph_data.x_map(toValue(graph_data.min_x)) -
text_offset
"
:y="y_map(tick)"
>{{ tick.toFixed(0) }}</text
>
</template>
</g>
</template>
<g>
<slot></slot>
</g>
<g class="major_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[1]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - major_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(1) }}</text
>
</template>
</g>
<g class="grid_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[2]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="right_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(0) }}</text
>
</template>
</g>
</template>
<template v-if="side == AxisSide.Left">
<g class="minor_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[0]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x)) + minor_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.min_x)) - text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(2) }}</text
>
</template>
</g>
<g class="major_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[1]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.max_x)) - major_tick_length},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.min_x)) - text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(1) }}</text
>
</template>
</g>
<g class="grid_tick" clip-path="url(#y_ticker)">
<template v-for="tick of lines[2]" :key="tick">
<polyline
:points="`${graph_data.x_map(toValue(graph_data.min_x))},${y_map(tick)} ${graph_data.x_map(toValue(graph_data.max_x))},${y_map(tick)}`"
></polyline>
<text
class="left_edge middle_text"
:x="graph_data.x_map(toValue(graph_data.min_x)) - text_offset"
:y="y_map(tick)"
>{{ tick.toFixed(0) }}</text
>
</template>
</g>
</template>
<g clip-path="url(#content)">
<slot></slot>
</g>
</template>
<style scoped lang="scss">
.x_axis {
fill: #ffffff;
stroke: #ffffff;
color: #ffffff;
fill: #ffffff;
stroke: #ffffff;
color: #ffffff;
}
.right_edge {
text-anchor: start;
text-anchor: start;
}
.left_edge {
text-anchor: end;
text-anchor: end;
}
.middle_text {
alignment-baseline: middle;
font-family: Helvetica, sans-serif;
alignment-baseline: middle;
font-family: Helvetica, sans-serif;
}
.minor_tick {
stroke: #666666;
stroke-width: 1px;
fill: #666666;
color: #666666;
stroke: #666666;
stroke-width: 1px;
fill: #666666;
color: #666666;
}
.major_tick {
stroke: #aaaaaa;
stroke-width: 1px;
fill: #aaaaaa;
color: #aaaaaa;
stroke: #aaaaaa;
stroke-width: 1px;
fill: #aaaaaa;
color: #aaaaaa;
}
.grid_tick {
stroke: #ffffff;
stroke-width: 1px;
fill: #ffffff;
color: #ffffff;
stroke: #ffffff;
stroke-width: 1px;
fill: #ffffff;
color: #ffffff;
}
</style>

View File

@@ -1,141 +1,142 @@
<script setup lang="ts">
import { computed, provide } from 'vue'
import { useNow } from '@/composables/ticker'
import { GRAPH_DATA, type GraphData } from '@/graph/graph'
import { computed, provide } from 'vue';
import { useNow } from '@/composables/ticker';
import { GRAPH_DATA, type GraphData } from '@/graph/graph';
const props = defineProps<{
width: number
height: number
border_left_right?: number
border_top_bottom?: number
// min_x?: number
// max_x?: number
}>()
width: number;
height: number;
border_left_right?: number;
border_top_bottom?: number;
// min_x?: number
// max_x?: number
}>();
const svg_viewbox = computed(() => {
return `0 0 ${props.width} ${props.height}`
})
const now = useNow(33)
const window_duration = 30 * 1000 // 30 seconds
return `0 0 ${props.width} ${props.height}`;
});
const now = useNow(33);
const window_duration = 30 * 1000; // 30 seconds
const time_lines = [
1, // 1ms
10, // 10ms
100, // 100ms
1000, // 1s
5000, // 5s
10000, // 10s
30000, // 30s
60000, // 1m
300000, // 5m
6000000, // 10m
18000000, // 30m
36000000, // 1h
144000000, // 4h
216000000, // 6h
432000000, // 12h
864000000, // 1d
6048000000, // 1w
]
time_lines.reverse()
const text_offset = computed(() => 5)
1, // 1ms
10, // 10ms
100, // 100ms
1000, // 1s
5000, // 5s
10000, // 10s
30000, // 30s
60000, // 1m
300000, // 5m
6000000, // 10m
18000000, // 30m
36000000, // 1h
144000000, // 4h
216000000, // 6h
432000000, // 12h
864000000, // 1d
6048000000, // 1w
];
time_lines.reverse();
const text_offset = computed(() => 5);
const border_left_right = computed(() => props.border_left_right || 0)
const border_top_bottom = computed(() => props.border_top_bottom || 0)
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 max_x = now;
const min_x = computed(() => max_x.value - window_duration);
const x_map = (x: number) => {
const diff_x = max_x.value - min_x.value
return (
((props.width - 2 * border_left_right.value) * (x - min_x.value)) / diff_x +
border_left_right.value
)
}
const diff_x = max_x.value - min_x.value;
return (
((props.width - 2 * border_left_right.value) * (x - min_x.value)) /
diff_x +
border_left_right.value
);
};
provide<GraphData>(GRAPH_DATA, {
border_top_bottom: border_top_bottom,
min_x: min_x,
max_x: now,
width: () => props.width - 2 * border_left_right.value,
height: () => props.height - 2 * border_top_bottom.value,
x_map: x_map,
})
border_top_bottom: border_top_bottom,
min_x: min_x,
max_x: now,
width: () => props.width - 2 * border_left_right.value,
height: () => props.height - 2 * border_top_bottom.value,
x_map: x_map,
});
const lines = computed(() => {
const diff_x = max_x.value - min_x.value
const duration = time_lines.find(duration => diff_x / duration >= 3)!
const result = []
for (
let i = Math.ceil(max_x.value / duration);
i >= Math.ceil(min_x.value / duration) - 5;
i--
) {
const x = i * duration
result.push(x)
}
return result
})
const diff_x = max_x.value - min_x.value;
const duration = time_lines.find((duration) => diff_x / duration >= 3)!;
const result = [];
for (
let i = Math.ceil(max_x.value / duration);
i >= Math.ceil(min_x.value / duration) - 5;
i--
) {
const x = i * duration;
result.push(x);
}
return result;
});
</script>
<template>
<svg :viewBox="svg_viewbox" :width="props.width" :height="props.height">
<defs>
<clipPath id="content">
<rect
:x="border_left_right"
:y="border_top_bottom"
:width="width - border_left_right * 2"
:height="height - border_top_bottom * 2"
></rect>
</clipPath>
<clipPath id="y_ticker">
<rect
:x="0"
:y="border_top_bottom"
:width="width"
:height="height - border_top_bottom * 2"
></rect>
</clipPath>
<clipPath id="x_ticker">
<rect
:x="border_left_right"
:y="0"
:width="width - border_left_right * 2"
:height="height"
></rect>
</clipPath>
</defs>
<g class="time_tick" clip-path="url(#x_ticker)">
<template v-for="tick of lines" :key="tick">
<polyline
:points="`${x_map(tick)},${border_top_bottom} ${x_map(tick)},${height - border_top_bottom}`"
></polyline>
<text
class="bottom_edge"
:transform="`translate(${x_map(tick)},${height - border_top_bottom + text_offset}) rotate(0)`"
>
{{ new Date(tick).toLocaleString() }}
</text>
</template>
</g>
<slot></slot>
</svg>
<svg :viewBox="svg_viewbox" :width="props.width" :height="props.height">
<defs>
<clipPath id="content">
<rect
:x="border_left_right"
:y="border_top_bottom"
:width="width - border_left_right * 2"
:height="height - border_top_bottom * 2"
></rect>
</clipPath>
<clipPath id="y_ticker">
<rect
:x="0"
:y="border_top_bottom"
:width="width"
:height="height - border_top_bottom * 2"
></rect>
</clipPath>
<clipPath id="x_ticker">
<rect
:x="border_left_right"
:y="0"
:width="width - border_left_right * 2"
:height="height"
></rect>
</clipPath>
</defs>
<g class="time_tick" clip-path="url(#x_ticker)">
<template v-for="tick of lines" :key="tick">
<polyline
:points="`${x_map(tick)},${border_top_bottom} ${x_map(tick)},${height - border_top_bottom}`"
></polyline>
<text
class="bottom_edge"
:transform="`translate(${x_map(tick)},${height - border_top_bottom + text_offset}) rotate(0)`"
>
{{ new Date(tick).toLocaleString() }}
</text>
</template>
</g>
<slot></slot>
</svg>
</template>
<style scoped lang="scss">
.bottom_edge {
text-anchor: middle;
alignment-baseline: text-before-edge;
font-family: Helvetica, sans-serif;
text-anchor: middle;
alignment-baseline: text-before-edge;
font-family: Helvetica, sans-serif;
}
.time_tick {
stroke: #ffffff;
stroke-width: 1px;
fill: #ffffff;
color: #ffffff;
font-size: 16px;
stroke: #ffffff;
stroke-width: 1px;
fill: #ffffff;
color: #ffffff;
font-size: 16px;
}
</style>

View File

@@ -1,120 +1,121 @@
<script setup lang="ts">
import { useTelemetry } from '@/composables/telemetry'
import { useTelemetry } from '@/composables/telemetry';
import {
computed,
inject,
ref,
shallowRef,
type ShallowRef,
toValue,
watch,
} from 'vue'
computed,
inject,
ref,
shallowRef,
type ShallowRef,
toValue,
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'
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';
const props = defineProps<{
data: string
color: string
}>()
data: string;
color: string;
}>();
const smoothing_distance = 0.15 * 1000
const smoothing_distance = 0.15 * 1000;
const { data } = useTelemetry(() => props.data)
const websocket = inject<ShallowRef<WebsocketHandle>>(WEBSOCKET_SYMBOL)!
const value = websocket.value.listen_to_telemetry(data)
const { data } = useTelemetry(() => props.data);
const websocket = inject<ShallowRef<WebsocketHandle>>(WEBSOCKET_SYMBOL)!;
const value = websocket.value.listen_to_telemetry(data);
const graph_data = inject<GraphData>(GRAPH_DATA)!
const axis_data = inject<AxisData>(AXIS_DATA)!
const graph_data = inject<GraphData>(GRAPH_DATA)!;
const axis_data = inject<AxisData>(AXIS_DATA)!;
const min = ref(Infinity)
const max = ref(-Infinity)
const min = ref(Infinity);
const max = ref(-Infinity);
const memo = shallowRef<TelemetryDataItem[]>([])
const memo = shallowRef<TelemetryDataItem[]>([]);
watch([value], ([val]) => {
const min_x = toValue(graph_data.min_x)
if (val) {
const new_memo = [val].concat(memo.value)
while (
new_memo.length > 2 &&
Date.parse(new_memo[new_memo.length - 2].timestamp) < min_x
) {
new_memo.pop()
const min_x = toValue(graph_data.min_x);
if (val) {
const new_memo = [val].concat(memo.value);
while (
new_memo.length > 2 &&
Date.parse(new_memo[new_memo.length - 2].timestamp) < min_x
) {
new_memo.pop();
}
memo.value = new_memo;
let min_val = Infinity;
let max_val = -Infinity;
for (const item of new_memo) {
const item_val = item.value[data.value!.data_type] as number;
min_val = Math.min(min_val, item_val);
max_val = Math.max(max_val, item_val);
}
max.value = max_val;
min.value = min_val;
}
memo.value = new_memo
let min_val = Infinity
let max_val = -Infinity
for (const item of new_memo) {
const item_val = item.value[data.value!.data_type] as number
min_val = Math.min(min_val, item_val)
max_val = Math.max(max_val, item_val)
}
max.value = max_val
min.value = min_val
}
})
});
watch(
[min, axis_data.axis_update_watch],
([min_val]) => {
axis_data.min_y_callback(min_val)
},
{
immediate: true,
},
)
[min, axis_data.axis_update_watch],
([min_val]) => {
axis_data.min_y_callback(min_val);
},
{
immediate: true,
},
);
watch(
[max, axis_data.axis_update_watch],
([max_val]) => {
axis_data.max_y_callback(max_val)
},
{
immediate: true,
},
)
[max, axis_data.axis_update_watch],
([max_val]) => {
axis_data.max_y_callback(max_val);
},
{
immediate: true,
},
);
const points = computed(() => {
let points = ''
if (memo.value.length == 0 || data.value == null) {
return ''
}
let last_x = graph_data.x_map(toValue(graph_data.max_x))
let last_t = toValue(graph_data.max_x) + smoothing_distance
for (const data_item of memo.value) {
const t = Date.parse(data_item.timestamp)
const v = data_item.value[data.value.data_type]
const x = graph_data.x_map(t)
const y = axis_data.y_map(v)
if (last_t - t < smoothing_distance) {
points += ` ${x},${y}`
} else {
points += ` ${last_x},${y} ${x},${y}`
let points = '';
if (memo.value.length == 0 || data.value == null) {
return '';
}
last_x = x
last_t = t
if (last_x <= 0.0) {
break
let last_x = graph_data.x_map(toValue(graph_data.max_x));
let last_t = toValue(graph_data.max_x) + smoothing_distance;
for (const data_item of memo.value) {
const t = Date.parse(data_item.timestamp);
const v = data_item.value[data.value.data_type];
const x = graph_data.x_map(t);
const y = axis_data.y_map(v);
if (last_t - t < smoothing_distance) {
points += ` ${x},${y}`;
} else {
points += ` ${last_x},${y} ${x},${y}`;
}
last_x = x;
last_t = t;
if (last_x <= 0.0) {
break;
}
}
}
return points
})
return points;
});
</script>
<template>
<polyline
fill="none"
:stroke="color"
stroke-width="1"
:points="points"
></polyline>
<polyline
fill="none"
clip-path="url(#content)"
:stroke="color"
stroke-width="1"
:points="points"
></polyline>
</template>
<style></style>