Test radiosonde.mjs
This commit is contained in:
151
client/src/components/Altitude.vue
Normal file
151
client/src/components/Altitude.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<script setup lang="ts">
|
||||
import {computed} from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
history: any[]
|
||||
currentAltitude: number | null
|
||||
unit: string
|
||||
}>()
|
||||
|
||||
const WIDTH = 320
|
||||
const HEIGHT = 120
|
||||
const PAD = {top: 10, right: 12, bottom: 24, left: 42}
|
||||
|
||||
const points = computed(() => {
|
||||
const history = [...(props.history || [])]
|
||||
.filter(p => p.ts != null && p.altitude != null && !p.live)
|
||||
.sort((a, b) => Number(a.ts) - Number(b.ts))
|
||||
|
||||
if (props.currentAltitude != null && history.length) {
|
||||
const last = history[history.length - 1]
|
||||
history.push({
|
||||
ts: Math.max(Number(last.ts) + 1, Math.floor(Date.now() / 1000)),
|
||||
altitude: props.currentAltitude,
|
||||
live: true,
|
||||
})
|
||||
}
|
||||
|
||||
return history
|
||||
})
|
||||
|
||||
const graph = computed(() => {
|
||||
const pts = points.value
|
||||
if (pts.length < 2) return null
|
||||
|
||||
const minTs = Number(pts[0].ts)
|
||||
const maxTs = Number(pts[pts.length - 1].ts)
|
||||
const rawAltitudes = pts.map(p => Number(p.altitude))
|
||||
const minAlt = Math.min(...rawAltitudes)
|
||||
const maxAlt = Math.max(...rawAltitudes)
|
||||
const altRange = Math.max(maxAlt - minAlt, 1)
|
||||
const timeRange = Math.max(maxTs - minTs, 1)
|
||||
|
||||
const x = (ts: number) => PAD.left + ((ts - minTs) / timeRange) * (WIDTH - PAD.left - PAD.right)
|
||||
const y = (alt: number) => PAD.top + (1 - (alt - minAlt) / altRange) * (HEIGHT - PAD.top - PAD.bottom)
|
||||
|
||||
const line = pts.map(p => `${x(Number(p.ts)).toFixed(1)},${y(Number(p.altitude)).toFixed(1)}`).join(' ')
|
||||
const latest = pts[pts.length - 1]
|
||||
const latestX = x(Number(latest.ts))
|
||||
const latestY = y(Number(latest.altitude))
|
||||
|
||||
const formatTime = (ts: number) => {
|
||||
const d = new Date(ts * 1000)
|
||||
return d.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})
|
||||
}
|
||||
|
||||
return {
|
||||
line,
|
||||
latestX,
|
||||
latestY,
|
||||
minAlt,
|
||||
maxAlt,
|
||||
startTime: formatTime(minTs),
|
||||
endTime: formatTime(maxTs),
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.altitude-graph {
|
||||
padding: 0 16px 12px;
|
||||
}
|
||||
|
||||
.altitude-graph-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.altitude-graph svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.altitude-graph text {
|
||||
fill: #777;
|
||||
font-family: monospace;
|
||||
font-size: 9px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div v-if="graph" class="altitude-graph">
|
||||
<div class="altitude-graph-title">
|
||||
<span>ALTITUDE</span>
|
||||
<span>{{ unit }}</span>
|
||||
</div>
|
||||
|
||||
<svg :viewBox="`0 0 ${WIDTH} ${HEIGHT}`" preserveAspectRatio="none">
|
||||
<line
|
||||
:x1="PAD.left"
|
||||
:y1="PAD.top"
|
||||
:x2="PAD.left"
|
||||
:y2="HEIGHT - PAD.bottom"
|
||||
stroke="rgba(255,255,255,0.2)"
|
||||
/>
|
||||
|
||||
<line
|
||||
:x1="PAD.left"
|
||||
:y1="HEIGHT - PAD.bottom"
|
||||
:x2="WIDTH - PAD.right"
|
||||
:y2="HEIGHT - PAD.bottom"
|
||||
stroke="rgba(255,255,255,0.2)"
|
||||
/>
|
||||
|
||||
<text :x="PAD.left - 5" :y="PAD.top + 4" text-anchor="end">
|
||||
{{ graph.maxAlt }}
|
||||
</text>
|
||||
|
||||
<text :x="PAD.left - 5" :y="HEIGHT - PAD.bottom + 4" text-anchor="end">
|
||||
{{ graph.minAlt }}
|
||||
</text>
|
||||
|
||||
<polyline
|
||||
:points="graph.line"
|
||||
fill="none"
|
||||
stroke="#0f0"
|
||||
stroke-width="2"
|
||||
/>
|
||||
|
||||
<circle
|
||||
:cx="graph.latestX"
|
||||
:cy="graph.latestY"
|
||||
r="3"
|
||||
fill="#0f0"
|
||||
/>
|
||||
|
||||
<text :x="PAD.left" :y="HEIGHT - 6">
|
||||
{{ graph.startTime }}
|
||||
</text>
|
||||
|
||||
<text :x="WIDTH - PAD.right" :y="HEIGHT - 6" text-anchor="end">
|
||||
{{ graph.endTime }}
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user