Waveform Analysis
基于 Vue 3、TypeScript 和 D3 的响应式 SVG 波形图组件。适合展示单通道、多通道和大规模采样 数据,内置缩放、tooltip、图例、误差棒、标注、分页和多 Y 轴叠加。
当前稳定版本:v0.1.15。
组件使用不可变数据模型:替换 data 引用后会重新计算数据域和视口;大数据会按当前可见范围
和屏幕像素自动保峰降采样,而 tooltip、最近点查询和标注仍使用完整原始数据。
在线示例
最新稳定版 Demo:https://lqycustomsite.online/waveform-analysis/
特性
- Vue 3 Composition API + TypeScript,支持按需导入
WaveformChart - 采样值、显式坐标点和多系列数据模型
independent、separated、compact三种布局模式- 曲线、阶梯线、点符号和对称/非对称误差棒
- 实线、虚线和点划线,可按系列独立配置
- 缩放过程事件、缩放结束按可视区间加载和视口重置
- 可选的空格拖拽平移,默认关闭并隔离多图表实例
- 多系列图例、受控显隐、网格分页和最多四根 Y 轴
- 按轨道控制水平/垂直网格线的显隐与颜色
- 受控标注、右键编辑、拖拽避让和自定义颜色
- 标题、图框、坐标轴、零值参考线、净图和渲染参数可配置
安装
组件库将 Vue、D3、Ant Design Vue 和 vue3-colorpicker 作为 peer dependency;直接安装到业务项目时请一并 安装这些依赖:
pnpm add waveform-analysis vue d3 ant-design-vue vue3-colorpicker
运行时版本要求
组件库支持以下运行时版本:
| 依赖 | 支持版本 |
|---|---|
| Vue | >=3.2.33 <4 |
| Ant Design Vue | >=3.2.20 <4 |
| D3 | >=7.9.0 <8 |
| vue3-colorpicker | >=2.3.0 <3 |
安装时请确保业务项目中的 peer dependency 版本均满足上述范围。
发布
发布由推送版本 tag 触发。package.json 的 version 必须与 tag 去掉 v 后完全一致。
稳定版使用 vX.Y.Z,预发布版使用 vX.Y.Z-rc.1;稳定版发布为 npm latest,预发布版发布为
next。流水线会创建 Gitea Release,并上传包文件与 SHA-256 校验文件。
最小示例
<script setup lang="ts">
import { ref } from 'vue'
import { WaveformChart, type WaveformData } from 'waveform-analysis'
import 'waveform-analysis/style.css'
const data = ref<WaveformData>({
kind: 'points',
points: [
{ x: 0, y: 0.2 },
{ x: 0.001, y: 0.4 },
{ x: 0.002, y: 0.1 },
],
})
</script>
<template>
<div class="chart-container">
<WaveformChart :data="data" />
</div>
</template>
<style scoped>
.chart-container {
height: 420px;
}
</style>
父容器需要有明确高度;未指定 width 或 height 时,组件会填充父容器,并保持最小高度
180px。WaveformChart 的正式入口为 src/index.ts,样式入口为 waveform-analysis/style.css。
API 速查
Props
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
data |
WaveformData |
必填 | 波形数据 |
displayMode |
'independent' | 'separated' | 'compact' |
'independent' |
图框布局 |
overlayMode |
'single-axis' | 'multi-axis' |
'single-axis' |
叠加曲线的 Y 轴模式 |
timeUnit |
's' | 'ms' |
'ms' |
坐标轴和 tooltip 展示单位 |
xLabel / yLabel |
string |
时间(timeUnit) / '幅值' |
坐标轴名称 |
lineColor |
string |
'#0960bd' |
单波形默认颜色 |
width / height |
number |
自适应 | 组件总尺寸,单位为 CSS 像素 |
zoomable / showTooltip |
boolean |
true / true |
缩放和数值 tooltip 开关 |
pannable |
boolean |
false |
空格拖拽平移开关 |
minZoomSpan |
number |
未设置 | 最小缩放跨度,使用原始 X 数据单位 |
minVisiblePoints |
number |
0 |
缩放后至少保留的不同 X 坐标数 |
initialXDomain |
[number, number] |
未设置 | 所有图框的初始 X 范围 |
initialXDomains |
Record<string, [number, number]> |
未设置 | 按 track/series ID 配置初始范围 |
grid |
WaveformGridOptions |
{ rowCount: 2, columnCount: 1, showPagination: true } |
网格和分页 |
axes |
WaveformAxesOptions |
轴线均显示 | X/Y 轴基线显隐 |
rendering |
WaveformRenderingOptions |
{} |
降采样与点/误差棒间距 |
title / legend / frameStyle |
对应公开类型 | 未设置 | 标题、图例和图框样式 |
frameNumber |
string | number |
未设置 | 图框水印内容 |
zeroLine |
WaveformZeroLineOptions |
{ visible: false } |
零值参考线显隐与样式 |
cleanView |
boolean |
false |
仅保留波形的净图模式 |
annotations |
WaveformAnnotation[] |
[] |
受控标注数据 |
annotationsVisible |
boolean |
true |
标注图层显隐 |
interactionMode |
'zoom' | 'annotation' |
'zoom' |
左键交互模式 |
hiddenSeriesIds |
string[] |
未设置 | 受控隐藏系列 ID |
defaultHiddenSeriesIds |
string[] |
[] |
非受控模式的初始隐藏系列 |
所有公开类型均可从包入口导入,例如 WaveformData、WaveformSeries、
WaveformAnnotation、WaveformLineStyle、WaveformRenderingOptions、
WaveformAxesOptions、WaveformZeroLineOptions、WaveformGridOptions 和
WaveformGridTrackLines。
数据结构
单通道可以使用采样值(sampleRate 为每秒采样数)或显式坐标点:
import type { WaveformData } from 'waveform-analysis'
const samples: WaveformData = {
kind: 'samples',
values: [0.2, 0.4, 0.1],
sampleRate: 1000,
startTime: 0,
}
const points: WaveformData = {
kind: 'points',
points: [
{ x: 0, y: 12 },
{ x: 0.001, y: 15, lowerError: 0.4, upperError: 0.8 },
],
}
多通道使用 kind: 'series'。同一个 trackId 的系列会绘制在同一图框中;没有
trackId 的系列默认各占一个图框。建议为每个系列提供全图唯一且稳定的 id。
const chartData: WaveformData = {
kind: 'series',
series: [
{ id: 'ch-a', name: '通道 A', trackId: 'group-1', data: samples },
{ id: 'ch-b', name: '通道 B', trackId: 'group-1', data: points },
],
}
波形图
组件内置缩放、悬浮取点和 tooltip。调用方只需要提供波形数据:
<script setup lang="ts">
import { WaveformChart } from 'waveform-analysis'
import 'waveform-analysis/style.css'
</script>
<template>
<WaveformChart :data="chartData" />
</template>
缩放后按可视区间加载数据
组件支持 Plotly 风格的矩形框选缩放:在 zoom 模式下按住鼠标左键拖拽,松开后同时缩放
X/Y 轴;设置 pannable 后,指针位于图表内时按住空格键拖拽可平移当前视口。
鼠标滚轮仍可放大,双击恢复完整视口。
组件会在滚轮或框选缩放结束后触发 zoom-end,调用方可以使用端点请求后端,再通过
data 传回新数据。独立分图模式还会包含 trackIndex 和稳定的 seriesIds。
<WaveformChart
ref="chart"
:data="chartData"
:initial-x-domain="initialDomain"
:min-zoom-span="initialDomainSpan / 40"
pannable
@zoom-end="loadVisibleData"
@zoom-reset="restoreInitialData"
/>
zoom-change 会在滚轮、框选和平移过程中触发,适合更新外部状态;后端请求应使用
zoom-end,或在 zoom-change 上自行防抖。标注数据应由父组件独立持有,替换波形数据时
不要清空标注,组件会根据当前数据域自动隐藏或恢复对应标注。
zoom-end.gesture 用于区分 wheel 和 box。单轨道 payload 使用 yStart/yEnd;共享
X 轴且包含多个轨道时使用按稳定 track ID 索引的 yRanges。平移不会触发 zoom-end,
因此不会自动发起新的区间加载请求。
调用方应处理加载失败的情况(网络错误、超时等),并保持旧数据或显示加载状态。生产环境建议使用
AbortController 取消过时的请求。
initialXDomain 固定首次完整数据的 X 轴缩放边界,不要将它改成后端返回的当前窗口;独立图框有不同时间范围时,可通过
initialXDomains 按 track ID 或 series ID 分别配置。minZoomSpan 使用原始 X 数据单位,
可防止每次区间数据回填后重新累计放大。双击图框会
重置组件内部缩放并触发 zoom-reset;调用方应在事件中取消区间请求并恢复首次完整数据。
外部重置按钮也可以通过模板引用调用组件公开的 resetViewport() 方法,然后执行相同的数据恢复逻辑。
独立坐标模式下,回填响应应只替换 seriesIds 对应的系列,并调用
resetViewport(trackIndex);其他图框的数据和缩放状态应保持不变。
多通道数据应为每个 WaveformSeries 提供稳定的 id。内部时间坐标始终使用秒,
timeUnit 只控制坐标轴和 tooltip 的显示单位。
线型、点型与误差棒
每条序列可以独立设置连线方式、数据点符号和误差棒:
const series = {
id: 'temperature',
name: '温度',
lineType: 'step-end',
lineStyle: 'dashed',
pointType: 'circle',
errorBar: { visible: true, width: 1.5, capWidth: 8 },
data: {
kind: 'points',
points: [
{ x: 0, y: 12, error: 0.5 },
{ x: 1, y: 15, lowerError: 0.4, upperError: 0.8 },
],
},
} satisfies WaveformSeries
lineType 支持 none、linear、step-start、step-middle 和 step-end;它控制连接线的几何形态,兼容值
step-after 与 step-end 等价。三个阶梯值分别在区间起点、中点和终点跳变。pointType
支持 none、circle、square、triangle 和 diamond。默认使用普通直线且不显示数据点;
lineStyle 控制连接线的描边样式,支持 solid、dashed 和 dash-dot,默认值为 solid;
设置 lineType: 'none' 可以隐藏数据点之间的连接线,只保留点符号和误差棒;将其改为
linear 或阶梯类型即可同时显示对应连接线。误差棒仅在 errorBar.visible 为 true 时显示,
并参与 Y 轴范围计算;当误差棒可见时,lineType 和 pointType 可以同时为 none,用于展示
纯误差棒。只有连接线、点符号和误差棒全部关闭时才会回退为普通直线。lowerError、
upperError 分别覆盖对称的 error,图例会同步显示实际线型、点型和误差棒样式。
叠加与多值轴
为多条曲线设置相同的 trackId,可将它们叠加到同一图框。overlayMode 控制叠加
曲线共享一根 Y 轴还是使用独立值轴:
<WaveformChart :data="chartData" display-mode="independent" overlay-mode="multi-axis" />
overlayMode 对应公开类型 WaveformOverlayMode,可选值为 single-axis 和
multi-axis,默认值为 single-axis。多值轴最多渲染四根 Y 轴;超过四条曲线时,
后续曲线复用第 4 根轴,该轴的范围覆盖绑定到它的全部曲线。轴顺序依次为左侧、
右侧;三轴时第 3 根位于右侧外部,四轴时顺序为左侧、左侧外部、右侧、右侧外部。
overlayMode 与 displayMode 相互独立。displayMode 仍可使用 independent、
separated 或 compact 控制图框布局和 X 轴共享方式;未共享 trackId 的单曲线
图框不会因为切换叠加方式而改变。
绘图区域尺寸
width 和 height 接收像素数值,并且可以独立设置。指定的维度使用固定尺寸,未指定的
维度自适应填满父容器:
<div class="chart-container">
<WaveformChart :data="chartData" :width="960" />
</div>
<style scoped>
.chart-container {
height: 520px;
}
</style>
自适应高度要求父容器具有明确高度;父容器未定高时,组件使用最低 180px 高度。
显式高度同样保留 180px 下限。非有限尺寸按未指定处理,负宽度归零。
图表标题
title 在整个波形网格上方渲染一次,支持显隐、对齐、字体样式和旋转:
<WaveformChart
:data="chartData"
:title="{
visible: true,
text: 'Shot:4712',
align: 'center',
textStyle: {
color: '#1f2937',
fontSize: 14,
fontFamily: '"Microsoft YaHei", "微软雅黑", sans-serif',
rotation: 0,
fontWeight: 400,
fontStyle: 'normal',
textDecoration: 'none',
letterSpacing: '1px',
},
}"
/>
对应的公开类型为 WaveformTitleOptions 和 WaveformTitleTextStyle。未传 title、
visible 为 false,或 text 去除首尾空格后为空时,标题不渲染且不占高度。标题默认
居中、字号 14px、颜色 #1f2937、微软雅黑、常规字重且不旋转。标题区域高度按文字及旋转角度
在 44px 至 160px 之间计算;超长文字会省略,悬浮可查看完整内容。
width 和 height 始终表示组件总尺寸。标题显示后会从总高度中扣除标题区域,剩余高度
用于 SVG 绘图区,因此启用标题不会扩大组件或破坏父容器布局。
Demo 左侧控制面板提供标题实时预览,可配置标题名称、显隐、对齐、字体、字号、粗体、
斜体、下划线、旋转和颜色。字号范围为 8–72px,旋转范围为 -180–180°;样式栏中的
A 用于恢复常规字重、非斜体和无下划线,关闭标题不会清除已经填写的配置。
图框样式
frameStyle 统一设置所有非空图框的边框和背景,颜色支持带 alpha 的 CSS 颜色值:
<WaveformChart
:data="chartData"
:frame-style="{
borderColor: 'rgba(31, 41, 55, 0.8)',
borderWidth: 2,
borderStyle: 'dashed',
backgroundColor: 'rgba(14, 165, 233, 0.08)',
}"
/>
frameStyle.borderStyle 支持 solid(实线)、dashed(虚线)和 dotted(点虚线)。
对应的公开类型为 WaveformFrameStyle。默认边框颜色为 #1f2937、线宽为 1、线型为
solid,背景透明。borderWidth 为 0 时隐藏边框;非有限值或负数会回退到默认线宽。
图例与曲线显隐
legend.backgroundColor 设置多曲线图例的背景颜色。该字段接受任意有效 CSS 颜色值,
可通过 rgba(...) 或 hsla(...) 中的 alpha 通道调整透明度:
<script setup lang="ts">
import { ref } from 'vue'
const hiddenSeriesIds = ref<string[]>([])
</script>
<WaveformChart
:data="chartData"
v-model:hidden-series-ids="hiddenSeriesIds"
:legend="{
position: 'top-right',
trackPositions: {
'group-1': 'top-left',
'group-2': 'bottom',
},
orientation: 'auto',
backgroundColor: 'rgba(255, 255, 255, 0.45)',
interactive: true,
}"
/>
legend.trackPositions 按图框 ID 单独覆盖图例位置;同一个 trackId 组成的图框以该
trackId 为键,未设置 trackId 时以规范化后的 series.id 为键。未命中的图框继续使用
legend.position,两者都未配置时使用 top-right。当 orientation 为 auto 时,每个图框
会根据最终位置独立选择排列方向:top、bottom 为水平排列,其余位置为垂直排列。
未配置或传入空字符串时,图例背景默认使用 rgba(255, 255, 255, 0.7)。
legend.interactive 默认为 false;开启后可以单击或使用键盘操作图例项切换曲线显隐。
调用方可通过 hiddenSeriesIds 和 update:hidden-series-ids 控制状态,也可使用
defaultHiddenSeriesIds 设置非受控模式的初始隐藏项。隐藏状态同步作用于坐标轴、tooltip、
悬浮点和标注交互;允许隐藏全部曲线,并可通过保留的图例恢复显示。
显隐状态以规范化后的 series.id 为键。要在数据刷新和重新排序后稳定保留状态,每个系列都应
提供全图唯一且稳定的显式 id;自动生成的索引 ID 或重复 ID 添加的后缀不保证跨排序稳定。
零值参考线与净图
zeroLine 用于绘制 y = 0 的水平参考线,默认隐藏。参考线只在对应 Y 轴的当前 domain
包含 0 时渲染,不会为了显示参考线而扩展数据范围。多值轴模式下,每根可见 Y 轴分别按自身
scale 定位零线:
<WaveformChart
:data="chartData"
:zero-line="{
visible: true,
color: '#98a2b3',
width: 1,
dash: '6 4',
}"
/>
dash 直接对应 SVG 的 stroke-dasharray;传入空字符串可显示实线。无效或非正数的
width 会回退到 1。
设置 cleanView 后,组件隐藏标题内容、图例、网格、坐标轴、轴标签、图框背景与边框、帧水印、
零值参考线、标注和分页器,同时保留原图的标题区域、边距和波形尺寸。缩放、悬浮、十字线和
tooltip 仍然可用,切换回普通模式后原有配置和标注不会丢失:
<WaveformChart :data="chartData" :clean-view="cleanViewEnabled" />
网格、分页与交互模式
grid 控制独立图框的行列数(范围 1–10)以及是否显示分页器。默认值为 2 行、
1 列并开启分页;当图框数量超过网格容量时,分页器会显示在图表右下角。
还可以通过 trackLines 按轨道 ID 分别控制水平/垂直网格线的显隐和颜色。颜色未配置时,
继续使用组件默认的主/次网格颜色:
<WaveformChart
:data="chartData"
:grid="{
rowCount: 2,
columnCount: 2,
showPagination: true,
trackLines: {
voltage: {
horizontal: false,
vertical: true,
verticalColor: '#2563eb',
},
},
}"
:interaction-mode="interactionMode"
/>
axes 可以分别隐藏 X/Y 轴的基线,同时保留刻度短线、刻度数字、科学计数倍率、单位和轴标题。
与关闭网格线、设置 frameStyle 组合后,可以只使用图框边框围住绘图区:
<WaveformChart
:data="chartData"
:axes="{
x: { lineVisible: false },
y: { lineVisible: false },
}"
:grid="{
trackLines: {
voltage: { horizontal: false, vertical: false },
},
}"
:frame-style="{
borderColor: '#1f2937',
borderWidth: 1,
borderStyle: 'solid',
}"
/>
interactionMode 可选 zoom 或 annotation,默认使用缩放模式。右键绘图区可直接打开
标注编辑器,无需切换交互模式。zoomable、pannable 和 showTooltip 可分别控制缩放、
空格拖拽平移和 tooltip;平移默认关闭。
空数据或过滤后没有有效点时,组件会保留图框布局并显示“暂无有效波形数据”。
大数据渲染
组件按不可变数据处理:替换 data 引用会重新过滤、排序和缓存坐标域,并重置视口;
原地修改已有数组不会触发缓存刷新。建议通过 shallowRef 保存大数据并整体替换引用。
规范化始终保留所有有效点,坐标域、误差棒、tooltip 和标注均使用完整数据;绘制路径会根据
当前视口和 rendering 配置自动降采样。调用方如需在传入组件前主动压缩数据,应自行保留
原始数据,以免影响 tooltip、标注和误差范围的精度。
默认在可见点超过 2,000 时进行降采样,每个像素最多渲染 4 个保峰点。可按业务调整:
<WaveformChart
:data="chartData"
:rendering="{
downsample: true,
downsampleThreshold: 2000,
maxPointsPerPixel: 4,
pointMinSpacing: 10,
errorBarMinSpacing: 12,
}"
/>
全量视图只绘制均匀分布的真实数据点,放大后会自动恢复更多源标记。pointMinSpacing 和
errorBarMinSpacing 分别控制点符号和误差棒的最小水平间距,单位为 CSS 像素。两者同时
显示时共用一批采样点,并采用两个间距中的较大值,确保误差棒与对应点符号保持共心;仅显示
一类装饰时仍使用各自的间距。仅显示一类装饰时可将对应间距设为 0;两者同时显示时需将
两个间距都设为 0 才会关闭共同限制。设置 downsample: false 会关闭曲线和装饰的全部降采样。
降采样仅作用于 SVG 中的曲线、点符号和误差棒。点符号和误差棒在每个系列中分别合并为 单个 SVG path;最近点查询、tooltip、标注插值、Y 轴误差范围和受控数据不会损失精度。
采样点标注
标注由父组件通过 v-model:annotations 持有,标注使用 seriesId 和 x/y 数据坐标,
不依赖数组下标:
<script setup lang="ts">
import { ref } from 'vue'
import {
parseWaveformAnnotations,
serializeWaveformAnnotations,
WaveformChart,
type WaveformAnnotation,
type WaveformInteractionMode,
} from 'waveform-analysis'
import 'waveform-analysis/style.css'
const annotations = ref<WaveformAnnotation[]>([])
const annotationsVisible = ref(true)
const interactionMode = ref<WaveformInteractionMode>('zoom')
</script>
<template>
<WaveformChart
:data="chartData"
v-model:annotations="annotations"
:annotations-visible="annotationsVisible"
:interaction-mode="interactionMode"
/>
</template>
标注默认显示。右键绘图区任意位置即可弹出居中编辑器,标注会吸附到当前 X 位置最近的真实采样点,右键已有标注可以编辑或删除。
标注框可以直接拖动进行手动避让,拖动只改变标签框位置,不会改变 x/y 数据锚点;偏移会以 labelOffsetX/labelOffsetY 像素字段保存在标注中。标注文本最多 40 个字符,边框色、文字色和背景色均支持取色与透明度调整。组件只负责内存中的受控数据,
业务层负责会话或后端持久化。
标注可以序列化为带版本号的 JSON,并在解析成功后整体替换当前数据:
const exportedJson = serializeWaveformAnnotations(annotations.value)
async function importAnnotationFile(file: File) {
annotations.value = parseWaveformAnnotations(await file.text())
}
导出格式为 { version: 1, annotations: [...] }。解析会验证全部标注;文件格式、版本或任意
字段无效时会抛出 TypeError,不会返回部分结果。导入包含未知 seriesId 的标注是允许的,
对应曲线加载后会恢复显示。文件选择、错误提示和下载由业务层实现。
X、Y 轴会根据各自完整显示域选择格式:最大绝对值在 [0.01, 100) 时显示两位普通小数;大于等于 100,或大于 0 且小于 0.01 时,刻度显示两位缩放值,并在轴末端单独显示共享倍率 E±NN。X 轴先按 timeUnit 转换为秒或毫秒再判断范围,多 Y 轴则分别计算倍率。tooltip 使用最多 4 位小数的本地化普通数字;标注编辑器的 X 坐标跟随 timeUnit 并固定 3 位小数,Y 坐标显示完整普通十进制。所有格式化都只发生在展示层,内部坐标值保持原始精度。
标注框默认布局在采样点正上方,只做绘图区边界裁剪;文本框通过连接箭头指向标注位置,多个标注重叠时可通过拖动手动避让。
事件
组件提供以下事件,名称与 Vue 模板写法一致:
| 事件 | 说明 |
|---|---|
point-hover |
当前最近点变化时触发,离开图表时传入 null |
zoom-change |
缩放过程中触发,参数为 [start, end] |
zoom-end |
滚轮或框选结束后触发;gesture 区分二者,独立模式附带轨道信息 |
zoom-reset |
双击重置视口时触发,调用方应恢复首次完整数据 |
page-change |
分页变化,参数为当前页和总页数 |
series-visibility-change |
图例切换曲线显隐时触发 |
annotation-create / annotation-update / annotation-delete |
标注新增、更新或删除 |
annotations 和 hidden-series-ids 支持 v-model;annotations-visible 与
interaction-mode 是受控输入属性。业务层应负责将标注和显隐状态持久化。
项目结构
src/index.ts:组件库公开入口和工具函数导出src/components/WaveformChart.vue:图表容器、缩放、tooltip、图例和标注编排src/components/{core,data,rendering,interaction,annotation}:数据、布局、渲染和交互模块src/App.vue:可交互 demo,src/data中提供示例波形数据
本地开发
开发环境要求 Node.js 22 和 pnpm:
pnpm install
pnpm dev
常用质量检查和构建命令:
pnpm typecheck
pnpm lint
pnpm test
pnpm test:coverage
pnpm build
pnpm build 同时生成 dist/ 组件库产物和 dist-demo/ 演示应用。正式公开入口为
src/index.ts,样式入口为 src/styles.css;dist/ 和 dist-demo/ 均为生成目录,不要手工编辑。
发布流程
发布由推送版本 tag 触发。先将 package.json 的 version 更新为目标版本并提交,再创建同版本 tag:
git tag -a v0.1.15 -m "Release v0.1.15"
git push origin main --follow-tags
支持稳定版 vX.Y.Z 与预发布版 vX.Y.Z-rc.1。tag 去掉 v 后必须与 package.json 的
version 完全一致。稳定版发布为 npm latest,预发布版发布为 npm next。流水线会创建 Gitea
Release,并上传 .tgz 与 SHA-256 校验文件。