150 lines
4.9 KiB
Vue
150 lines
4.9 KiB
Vue
<script setup lang="ts">
|
||
import { computed, ref } from 'vue'
|
||
import { InputNumber, RadioButton, RadioGroup } from 'ant-design-vue'
|
||
|
||
import { WaveformChart, type WaveformData } from '../components'
|
||
|
||
type RangeMode = 'auto' | 'global' | 'channel'
|
||
|
||
const rangeMode = ref<RangeMode>('global')
|
||
const globalMinimum = ref(-80)
|
||
const globalMaximum = ref(80)
|
||
const voltageMinimum = ref(-65)
|
||
const voltageMaximum = ref(65)
|
||
const currentMinimum = ref(-260)
|
||
const currentMaximum = ref(260)
|
||
|
||
const chartData: WaveformData = {
|
||
kind: 'series',
|
||
series: [
|
||
{
|
||
id: 'voltage',
|
||
name: '电压',
|
||
unit: 'V',
|
||
color: '#1677ff',
|
||
data: {
|
||
kind: 'points',
|
||
points: Array.from({ length: 800 }, (_, index) => {
|
||
const x = index / 80
|
||
const pulse = index % 240 >= 112 && index % 240 <= 122 ? 58 : 0
|
||
return { x, y: 48 * Math.sin(x * Math.PI * 1.5) + pulse }
|
||
}),
|
||
},
|
||
},
|
||
{
|
||
id: 'current',
|
||
name: '电流',
|
||
unit: 'mA',
|
||
color: '#d4380d',
|
||
data: {
|
||
kind: 'points',
|
||
points: Array.from({ length: 800 }, (_, index) => {
|
||
const x = index / 80
|
||
const pulse = index % 300 >= 184 && index % 300 <= 192 ? -210 : 0
|
||
return { x, y: 185 * Math.cos(x * Math.PI) + pulse }
|
||
}),
|
||
},
|
||
},
|
||
],
|
||
}
|
||
|
||
function orderedDomain(minimum: number, maximum: number): [number, number] | undefined {
|
||
if (!Number.isFinite(minimum) || !Number.isFinite(maximum) || minimum === maximum) {
|
||
return undefined
|
||
}
|
||
return minimum < maximum ? [minimum, maximum] : [maximum, minimum]
|
||
}
|
||
|
||
const yDomain = computed<[number, number] | undefined>(() =>
|
||
rangeMode.value === 'global'
|
||
? orderedDomain(globalMinimum.value, globalMaximum.value)
|
||
: undefined,
|
||
)
|
||
const yDomains = computed<Record<string, [number, number]> | undefined>(() => {
|
||
if (rangeMode.value !== 'channel') return undefined
|
||
const voltage = orderedDomain(voltageMinimum.value, voltageMaximum.value)
|
||
const current = orderedDomain(currentMinimum.value, currentMaximum.value)
|
||
return {
|
||
...(voltage ? { voltage } : {}),
|
||
...(current ? { current } : {}),
|
||
}
|
||
})
|
||
const rangeSummary = computed(() => {
|
||
if (rangeMode.value === 'auto') return '自动计算'
|
||
if (rangeMode.value === 'global') {
|
||
return yDomain.value ? `${yDomain.value[0]} ~ ${yDomain.value[1]}` : '自动计算'
|
||
}
|
||
const voltage = yDomains.value?.voltage
|
||
const current = yDomains.value?.current
|
||
return `电压 ${voltage?.[0] ?? '-'} ~ ${voltage?.[1] ?? '-'} V · 电流 ${
|
||
current?.[0] ?? '-'
|
||
} ~ ${current?.[1] ?? '-'} mA`
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<main class="fixed-domain-demo">
|
||
<header class="fixed-domain-demo__toolbar">
|
||
<div>
|
||
<h1>固定振幅范围</h1>
|
||
<p>当前范围:{{ rangeSummary }}</p>
|
||
</div>
|
||
<RadioGroup v-model:value="rangeMode" button-style="solid" aria-label="Y 轴范围模式">
|
||
<RadioButton value="auto">自动</RadioButton>
|
||
<RadioButton value="global">全局固定</RadioButton>
|
||
<RadioButton value="channel">按通道固定</RadioButton>
|
||
</RadioGroup>
|
||
</header>
|
||
|
||
<section class="fixed-domain-demo__range-controls">
|
||
<template v-if="rangeMode === 'global'">
|
||
<label>
|
||
<span>下限</span>
|
||
<InputNumber v-model:value="globalMinimum" aria-label="全局振幅下限" />
|
||
</label>
|
||
<label>
|
||
<span>上限</span>
|
||
<InputNumber v-model:value="globalMaximum" aria-label="全局振幅上限" />
|
||
</label>
|
||
</template>
|
||
<template v-else-if="rangeMode === 'channel'">
|
||
<strong>电压</strong>
|
||
<label>
|
||
<span>下限</span>
|
||
<InputNumber v-model:value="voltageMinimum" aria-label="电压振幅下限" />
|
||
</label>
|
||
<label>
|
||
<span>上限</span>
|
||
<InputNumber v-model:value="voltageMaximum" aria-label="电压振幅上限" />
|
||
</label>
|
||
<strong>电流</strong>
|
||
<label>
|
||
<span>下限</span>
|
||
<InputNumber v-model:value="currentMinimum" aria-label="电流振幅下限" />
|
||
</label>
|
||
<label>
|
||
<span>上限</span>
|
||
<InputNumber v-model:value="currentMaximum" aria-label="电流振幅上限" />
|
||
</label>
|
||
</template>
|
||
<span v-else class="fixed-domain-demo__auto-state">根据可见数据自动计算</span>
|
||
</section>
|
||
|
||
<section class="fixed-domain-demo__chart">
|
||
<WaveformChart
|
||
:data="chartData"
|
||
:y-domain="yDomain"
|
||
:y-domains="yDomains"
|
||
display-mode="independent"
|
||
:grid="{ rowCount: 2, columnCount: 1, showPagination: false }"
|
||
:title="{ visible: true, text: '振幅上下限示例', align: 'left' }"
|
||
:zero-line="{ visible: true, color: '#98a2b3', width: 1, dash: '5 4' }"
|
||
:legend="{ position: 'top-right', backgroundColor: 'rgba(255,255,255,0.8)' }"
|
||
x-label="时间(s)"
|
||
time-unit="s"
|
||
:show-tooltip="true"
|
||
/>
|
||
</section>
|
||
</main>
|
||
</template>
|