first commit
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
李启源
2026-07-20 10:21:30 +08:00
commit ea832229da
75 changed files with 16864 additions and 0 deletions

161
src/App.vue Normal file
View File

@@ -0,0 +1,161 @@
<script setup lang="ts">
import { InputNumber, Radio, Tag } from 'ant-design-vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import {
WaveformChart,
type WaveformAnnotation,
type WaveformData,
type WaveformDisplayMode,
type WaveformInteractionMode,
type WaveformSeries,
} from './components'
import waveformJson from './data/wData.json'
interface WaveformSourceRow {
chnl: string
chnl_id: number
dat_unit: string
data: number[]
dev: number
shot: number
time: number[]
time_unit: 'ms'
}
const importedSourceRows = waveformJson as unknown as WaveformSourceRow[]
const testChannelRows: WaveformSourceRow[] = importedSourceRows.slice(0, 2).map((row, index) => ({
...row,
chnl: `TEST_CH_${index + 1}`,
chnl_id: 9001 + index,
data: row.data.map(
(value, sampleIndex) =>
value * (index === 0 ? 0.72 : 1.12) +
Math.sin(sampleIndex / (index === 0 ? 11 : 18)) * (index === 0 ? 0.015 : 0.01),
),
}))
const sourceRows = [...importedSourceRows, ...testChannelRows]
const visibleRange = ref<[number, number] | null>(null)
const displayMode = ref<WaveformDisplayMode>('independent')
const rowCount = ref(2)
const columnCount = ref(1)
const annotations = ref<WaveformAnnotation[]>([])
const annotationsVisible = ref(true)
const interactionMode = ref<WaveformInteractionMode>('zoom')
const resolveChartHeight = () =>
Math.min(800, Math.max(560, (typeof window === 'undefined' ? 750 : window.innerHeight) - 190))
const chartHeight = ref(resolveChartHeight())
const waveformSeries: WaveformSeries[] = sourceRows.map((row) => {
const pointCount = Math.min(row.time.length, row.data.length)
return {
id: String(row.chnl_id),
name: row.chnl,
unit: row.dat_unit,
data: {
kind: 'points',
points: Array.from({ length: pointCount }, (_, index) => ({
x: row.time[index] / 1000,
y: row.data[index],
})),
},
}
})
const chartData: WaveformData = { kind: 'series', series: waveformSeries }
const totalPointCount = waveformSeries.reduce((total, series) => {
const seriesPointCount =
series.data.kind === 'points' ? series.data.points.length : series.data.values.length
return total + seriesPointCount
}, 0)
const initialTimeRange: [number, number] = [
Math.min(...sourceRows.flatMap((row) => row.time)) / 1000,
Math.max(...sourceRows.flatMap((row) => row.time)) / 1000,
]
const displayedRange = computed(() => visibleRange.value ?? initialTimeRange)
const formatMilliseconds = (seconds: number) =>
(seconds * 1000).toLocaleString('zh-CN', { maximumFractionDigits: 1 })
function updateChartHeight() {
chartHeight.value = resolveChartHeight()
}
watch(displayMode, () => {
visibleRange.value = null
})
watch([rowCount, columnCount], () => {
visibleRange.value = null
})
onMounted(() => {
window.addEventListener('resize', updateChartHeight)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateChartHeight)
})
</script>
<template>
<main class="workspace">
<header class="workspace__header">
<div>
<p class="workspace__eyebrow">Vue 3 · TypeScript · D3</p>
<h1>波形分析组件</h1>
</div>
</header>
<section class="control-bar" aria-label="波形图控制与摘要">
<div class="control-bar__leading">
<Tag color="blue">真实 + 测试数据</Tag>
<Radio.Group
v-model:value="displayMode"
class="display-mode-control"
button-style="solid"
size="small"
aria-label="波形展示方式"
>
<Radio.Button value="independent">单独坐标</Radio.Button>
<Radio.Button value="separated">多道分离</Radio.Button>
<Radio.Button value="compact">多道紧凑</Radio.Button>
</Radio.Group>
<div class="grid-size-control" aria-label="波形网格尺寸">
<span>网格</span>
<InputNumber v-model:value="rowCount" :min="1" :max="10" size="small" />
<span> ×</span>
<InputNumber v-model:value="columnCount" :min="1" :max="10" size="small" />
<span></span>
</div>
</div>
<div class="metrics">
<span>{{ sourceRows.length }} 通道</span>
<span>{{ totalPointCount.toLocaleString() }} 数据点</span>
<span>{{ annotations.length }} 标注</span>
<span>炮号 {{ sourceRows[0]?.shot }}</span>
<span>设备 {{ sourceRows[0]?.dev }}</span>
<span>
范围 {{ formatMilliseconds(displayedRange[0]) }}{{
formatMilliseconds(displayedRange[1])
}}
ms
</span>
</div>
</section>
<section class="chart-panel">
<WaveformChart
:data="chartData"
:display-mode="displayMode"
:grid="{ rowCount, columnCount, showPagination: true }"
:height="chartHeight"
:frame-number="1"
v-model:annotations="annotations"
v-model:annotations-visible="annotationsVisible"
v-model:interaction-mode="interactionMode"
@zoom-change="visibleRange = $event"
/>
</section>
</main>
</template>