more lines

This commit is contained in:
2024-12-05 20:10:31 -08:00
parent e6a52f971b
commit a353585d47
9 changed files with 269 additions and 82 deletions

View File

@@ -122,6 +122,21 @@ async fn main() -> Result<(), Box<dyn Error>> {
let sin_tlm_handle = tlm.register("simple_producer/sin".into(), TelemetryDataType::Float32).await?; let sin_tlm_handle = tlm.register("simple_producer/sin".into(), TelemetryDataType::Float32).await?;
let cos_tlm_handle = tlm.register("simple_producer/cos".into(), TelemetryDataType::Float64).await?; let cos_tlm_handle = tlm.register("simple_producer/cos".into(), TelemetryDataType::Float64).await?;
let sin2_tlm_handle = tlm.register("simple_producer/sin2".into(), TelemetryDataType::Float32).await?;
let cos2_tlm_handle = tlm.register("simple_producer/cos2".into(), TelemetryDataType::Float64).await?;
let sin3_tlm_handle = tlm.register("simple_producer/sin3".into(), TelemetryDataType::Float32).await?;
let cos3_tlm_handle = tlm.register("simple_producer/cos3".into(), TelemetryDataType::Float64).await?;
let sin4_tlm_handle = tlm.register("simple_producer/sin4".into(), TelemetryDataType::Float32).await?;
let cos4_tlm_handle = tlm.register("simple_producer/cos4".into(), TelemetryDataType::Float64).await?;
let sin5_tlm_handle = tlm.register("simple_producer/sin5".into(), TelemetryDataType::Float32).await?;
let cos5_tlm_handle = tlm.register("simple_producer/cos5".into(), TelemetryDataType::Float64).await?;
let sin6_tlm_handle = tlm.register("simple_producer/sin6".into(), TelemetryDataType::Float32).await?;
let cos6_tlm_handle = tlm.register("simple_producer/cos6".into(), TelemetryDataType::Float64).await?;
let cancellation_token = CancellationToken::new(); let cancellation_token = CancellationToken::new();
{ {
let cancellation_token = cancellation_token.clone(); let cancellation_token = cancellation_token.clone();
@@ -149,6 +164,66 @@ async fn main() -> Result<(), Box<dyn Error>> {
), ),
chrono::Utc::now(), chrono::Utc::now(),
).await?; ).await?;
sin2_tlm_handle.publish(
Value::Float32(
(f32::TAU() * (index as f32) / (500.0_f32)).sin()
),
chrono::Utc::now(),
).await?;
cos2_tlm_handle.publish(
Value::Float64(
(f64::TAU() * (index as f64) / (500.0_f64)).cos()
),
chrono::Utc::now(),
).await?;
sin3_tlm_handle.publish(
Value::Float32(
(f32::TAU() * (index as f32) / (333.0_f32)).sin()
),
chrono::Utc::now(),
).await?;
cos3_tlm_handle.publish(
Value::Float64(
(f64::TAU() * (index as f64) / (333.0_f64)).cos()
),
chrono::Utc::now(),
).await?;
sin4_tlm_handle.publish(
Value::Float32(
(f32::TAU() * (index as f32) / (250.0_f32)).sin()
),
chrono::Utc::now(),
).await?;
cos4_tlm_handle.publish(
Value::Float64(
(f64::TAU() * (index as f64) / (250.0_f64)).cos()
),
chrono::Utc::now(),
).await?;
sin5_tlm_handle.publish(
Value::Float32(
(f32::TAU() * (index as f32) / (200.0_f32)).sin()
),
chrono::Utc::now(),
).await?;
cos5_tlm_handle.publish(
Value::Float64(
(f64::TAU() * (index as f64) / (200.0_f64)).cos()
),
chrono::Utc::now(),
).await?;
sin6_tlm_handle.publish(
Value::Float32(
(f32::TAU() * (index as f32) / (166.0_f32)).sin()
),
chrono::Utc::now(),
).await?;
cos6_tlm_handle.publish(
Value::Float64(
(f64::TAU() * (index as f64) / (166.0_f64)).cos()
),
chrono::Utc::now(),
).await?;
} }
Ok(()) Ok(())

View File

@@ -1,4 +1,5 @@
@use '@/assets/variables'; @use '@/assets/variables';
@use 'sass:list';
body { body {
color: variables.$text-color; color: variables.$text-color;
@@ -18,3 +19,9 @@ body {
polyline { polyline {
stroke-width: 1px; stroke-width: 1px;
} }
@for $i from 1 through list.length(variables.$colors) {
.indexed-color.color-#{$i - 1} {
#{--indexed-color}: list.nth(variables.$colors, $i);
}
}

View File

@@ -1,19 +1,48 @@
$white-1: oklch(90% 0 0); $gray-1: oklch(90% 0 0);
$white-2: oklch(80% 0 0); $gray-2: oklch(80% 0 0);
$gray-1: oklch(70% 0 0); $gray-3: oklch(70% 0 0);
$gray-2: oklch(60% 0 0); $gray-4: oklch(60% 0 0);
$gray-3: oklch(50% 0 0); $gray-5: oklch(50% 0 0);
$gray-4: oklch(40% 0 0); $gray-6: oklch(40% 0 0);
$gray-5: oklch(30% 0 0); $gray-7: oklch(30% 0 0);
$black-1: oklch(20% 0 0); $gray-8: oklch(20% 0 0);
$black-2: oklch(10% 0 0); $gray-9: oklch(10% 0 0);
$text-color: $white-1; $red-1: oklch(75% 0.4 030);
$background-color: $gray-5; $orange-1: oklch(75% 0.4 090);
$green-1: oklch(75% 0.4 150);
$cyan-1: oklch(75% 0.4 210);
$blue-1: oklch(75% 0.4 270);
$magenta-1: oklch(75% 0.4 330);
$time-tick: $white-1; $red-2: oklch(75% 0.2 030);
$grid-line: $white-1; $orange-2: oklch(75% 0.2 090);
$major-tick: $gray-2; $green-2: oklch(75% 0.2 150);
$minor-tick: $gray-3; $cyan-2: oklch(75% 0.2 210);
$blue-2: oklch(75% 0.2 270);
$magenta-2: oklch(75% 0.2 330);
$text-color: $gray-1;
$background-color: $gray-7;
$time-tick: $gray-1;
$grid-line: $gray-1;
$major-tick: $gray-4;
$minor-tick: $gray-5;
$text-font: Helvetica, sans-serif; $text-font: Helvetica, sans-serif;
$colors: (
$red-1,
$green-1,
$blue-1,
$orange-1,
$cyan-1,
$magenta-1,
$red-2,
$green-2,
$blue-2,
$orange-2,
$cyan-2,
$magenta-2
);

View File

@@ -267,9 +267,7 @@ const lines = computed(() => {
</template> </template>
</g> </g>
</template> </template>
<g> <slot></slot>
<slot></slot>
</g>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, provide } from 'vue'; import { computed, provide, ref } from 'vue';
import { useNow } from '@/composables/ticker'; import { useNow } from '@/composables/ticker';
import { GRAPH_DATA, type GraphData } from '@/graph/graph'; import { GRAPH_DATA, type GraphData } from '@/graph/graph';
@@ -8,8 +8,7 @@ const props = defineProps<{
height: number; height: number;
border_left_right?: number; border_left_right?: number;
border_top_bottom?: number; border_top_bottom?: number;
// min_x?: number utc?: boolean;
// max_x?: number
}>(); }>();
const width = computed(() => { const width = computed(() => {
@@ -20,9 +19,6 @@ const height = computed(() => {
return props.height; return props.height;
}); });
// const svg_viewbox = computed(() => {
// return `0 0 ${props.width} ${props.height}`;
// });
const now = useNow(33); const now = useNow(33);
const window_duration = 10 * 1000; // 10 seconds const window_duration = 10 * 1000; // 10 seconds
@@ -72,6 +68,8 @@ const x_map = (x: number) => {
); );
}; };
const telemetry_lines = ref([]);
provide<GraphData>(GRAPH_DATA, { provide<GraphData>(GRAPH_DATA, {
border_top_bottom: border_top_bottom, border_top_bottom: border_top_bottom,
min_x: min_x, min_x: min_x,
@@ -79,26 +77,78 @@ provide<GraphData>(GRAPH_DATA, {
width: () => width.value - 2 * border_left_right.value, width: () => width.value - 2 * border_left_right.value,
height: () => height.value - 2 * border_top_bottom.value, height: () => height.value - 2 * border_top_bottom.value,
x_map: x_map, x_map: x_map,
lines: telemetry_lines,
});
const duration = computed(() => {
const diff_x = max_x.value - min_x.value;
return time_lines.find((duration) => diff_x / duration >= 3)!;
}); });
const lines = computed(() => { const lines = computed(() => {
const diff_x = max_x.value - min_x.value;
const duration = time_lines.find((duration) => diff_x / duration >= 3)!;
const result = []; const result = [];
for ( for (
let i = Math.ceil(max_x.value / duration); let i = Math.ceil(max_x.value / duration.value);
i >= Math.ceil(min_x.value / duration) - 5; i >= Math.ceil(min_x.value / duration.value) - 5;
i-- i--
) { ) {
const x = i * duration; const x = i * duration.value;
result.push(x); result.push(x);
} }
return result; return result;
}); });
function getDateString(date: Date) {
const year = props.utc ? date.getUTCFullYear() : date.getFullYear();
const month = (
(props.utc ? date.getMonth() : date.getMonth()) + 1
).toLocaleString('en-US', {
minimumIntegerDigits: 2,
useGrouping: false,
maximumFractionDigits: 0,
});
const day = (props.utc ? date.getUTCDate() : date.getDate()).toLocaleString(
'en-US',
{
minimumIntegerDigits: 2,
useGrouping: false,
maximumFractionDigits: 0,
},
);
const hour = (
props.utc ? date.getUTCHours() : date.getHours()
).toLocaleString('en-US', {
minimumIntegerDigits: 2,
useGrouping: false,
maximumFractionDigits: 0,
});
const minute = (
props.utc ? date.getUTCMinutes() : date.getMinutes()
).toLocaleString('en-US', {
minimumIntegerDigits: 2,
useGrouping: false,
maximumFractionDigits: 0,
});
const second = (
props.utc ? date.getUTCSeconds() : date.getSeconds()
).toLocaleString('en-US', {
minimumIntegerDigits: 2,
useGrouping: false,
maximumFractionDigits: 0,
});
const milliseconds = (
props.utc ? date.getUTCMilliseconds() : date.getMilliseconds()
).toLocaleString('en-US', {
minimumIntegerDigits: 3,
useGrouping: false,
maximumFractionDigits: 0,
});
return `${year}/${month}/${day} ${hour}:${minute}:${second}${duration.value < 1000 ? `.${milliseconds}` : ''}${props.utc ? 'Z' : ''}`;
}
</script> </script>
<template> <template>
<svg ref="svg_graph" :width="width" :height="height"> <svg ref="svg_graph" class="graph" :width="width" :height="height">
<defs> <defs>
<clipPath id="content"> <clipPath id="content">
<rect <rect
@@ -135,7 +185,7 @@ const lines = computed(() => {
:x="x_map(tick)" :x="x_map(tick)"
:y="height - border_top_bottom + text_offset" :y="height - border_top_bottom + text_offset"
> >
{{ new Date(tick).toLocaleString() }} {{ getDateString(new Date(tick)) }}
</text> </text>
</template> </template>
</g> </g>

View File

@@ -3,6 +3,8 @@ import { useTelemetry } from '@/composables/telemetry';
import { import {
computed, computed,
inject, inject,
onMounted,
onUnmounted,
ref, ref,
shallowRef, shallowRef,
type ShallowRef, type ShallowRef,
@@ -20,7 +22,7 @@ import { AXIS_DATA, type AxisData } from '@/graph/axis';
const props = defineProps<{ const props = defineProps<{
data: string; data: string;
color: string; class?: string;
}>(); }>();
const smoothing_distance = 0.15 * 1000; const smoothing_distance = 0.15 * 1000;
@@ -38,6 +40,19 @@ const axis_data = inject<AxisData>(AXIS_DATA)!;
const min = ref(Infinity); const min = ref(Infinity);
const max = ref(-Infinity); const max = ref(-Infinity);
const line = ref(Symbol());
const index = computed(() => {
return graph_data.lines.value.indexOf(line.value);
});
onMounted(() => {
graph_data.lines.value.push(line.value);
});
onUnmounted(() => {
graph_data.lines.value = graph_data.lines.value.filter(
(x) => x != line.value,
);
});
const memo = shallowRef<TelemetryDataItem[]>([]); const memo = shallowRef<TelemetryDataItem[]>([]);
watch([value], ([val]) => { watch([value], ([val]) => {
const min_x = toValue(graph_data.min_x); const min_x = toValue(graph_data.min_x);
@@ -119,64 +134,57 @@ const current_value = computed(() => {
} }
return undefined; return undefined;
}); });
const test = computed(() => {
if (labelRef.value) {
const boundingBox = labelRef.value.getBBox();
return boundingBox.top;
}
return undefined;
});
watch([test], (x) => {
console.log(x);
});
</script> </script>
<template> <template>
<polyline <g :class="`indexed-color color-${index}`">
fill="none" <polyline
clip-path="url(#content)" fill="none"
:stroke="color" clip-path="url(#content)"
stroke-width="1" :points="points"
:points="points" ></polyline>
></polyline> <template v-if="current_value">
<template v-if="current_value"> <rect
<rect v-if="labelRef"
v-if="labelRef" :x="
:x=" graph_data.x_map(toValue(graph_data.max_x)) +
graph_data.x_map(toValue(graph_data.max_x)) + text_offset -
text_offset - background_offset
background_offset "
" :y="axis_data.y_map(current_value) - 9 - background_offset"
:y="axis_data.y_map(current_value) - 9 - background_offset" :width="labelRef.getBBox().width + background_offset * 2"
:width="labelRef.getBBox().width + background_offset * 2" :height="16 + background_offset * 2"
:height="16 + background_offset * 2" ></rect>
:stroke="color" <text
></rect> ref="label-ref"
<text :x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset"
ref="label-ref" :y="axis_data.y_map(current_value)"
:x="graph_data.x_map(toValue(graph_data.max_x)) + text_offset" >
:y="axis_data.y_map(current_value)" {{ current_value.toFixed(2) }}
:fill="color" </text>
:stroke="color" </template>
> </g>
{{ current_value.toFixed(2) }}
</text>
</template>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@use '@/assets/variables'; @use '@/assets/variables';
text { polyline {
alignment-baseline: middle; stroke-width: 1px;
font-family: variables.$text-font; stroke: var(--indexed-color);
text-anchor: start;
} }
rect { rect {
fill: variables.$background-color; fill: variables.$background-color;
stroke-width: 1px; stroke-width: 1px;
stroke: var(--indexed-color);
}
text {
alignment-baseline: middle;
font-family: variables.$text-font;
text-anchor: start;
stroke: var(--indexed-color);
fill: var(--indexed-color);
} }
</style> </style>

View File

@@ -1,4 +1,4 @@
import type { MaybeRefOrGetter } from 'vue'; import type { MaybeRefOrGetter, Ref } from 'vue';
export const GRAPH_DATA = Symbol(); export const GRAPH_DATA = Symbol();
@@ -9,4 +9,5 @@ export interface GraphData {
width: MaybeRefOrGetter<number>; width: MaybeRefOrGetter<number>;
height: MaybeRefOrGetter<number>; height: MaybeRefOrGetter<number>;
x_map: (x: number) => number; x_map: (x: number) => number;
lines: Ref<symbol[]>;
} }

View File

@@ -18,11 +18,23 @@ provide(WEBSOCKET_SYMBOL, websocket);
:border_left_right="128" :border_left_right="128"
> >
<Axis> <Axis>
<Line data="simple_producer/sin" color="#FF0000"></Line> <Line data="simple_producer/sin"></Line>
<Line data="simple_producer/cos" color="#00FF00"></Line> <Line data="simple_producer/cos"></Line>
<!-- <Line data="simple_producer/sin2"></Line>-->
<!-- <Line data="simple_producer/cos2"></Line>-->
<!-- <Line data="simple_producer/sin3"></Line>-->
<!-- <Line data="simple_producer/cos3"></Line>-->
<!-- <Line data="simple_producer/sin4"></Line>-->
<!-- <Line data="simple_producer/cos4"></Line>-->
<!-- <Line data="simple_producer/sin5"></Line>-->
<!-- <Line data="simple_producer/cos5"></Line>-->
<!-- <Line data="simple_producer/sin6"></Line>-->
<!-- <Line data="simple_producer/cos6"></Line>-->
</Axis> </Axis>
</Graph> </Graph>
</main> </main>
</template> </template>
<style></style> <style lang="scss">
@use '@/assets/variables';
</style>

View File

@@ -25,5 +25,12 @@ export default defineConfig({
rewriteWsOrigin: true, rewriteWsOrigin: true,
} }
} }
},
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
} }
}) })