feat: 添加数值类型的波形显示

This commit is contained in:
SikongJueluo 2025-07-29 14:57:07 +08:00
parent 6c1bda50ce
commit f200d90fc0
No known key found for this signature in database
2 changed files with 155 additions and 83 deletions

View File

@ -39,6 +39,7 @@ import {
DataZoomComponent,
AxisPointerComponent,
ToolboxComponent,
MarkLineComponent,
} from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import type { ComposeOption } from "echarts/core";
@ -48,6 +49,7 @@ import type {
TooltipComponentOption,
GridComponentOption,
DataZoomComponentOption,
MarkLineComponentOption,
} from "echarts/components";
import type {
ToolboxComponentOption,
@ -66,6 +68,7 @@ use([
DataZoomComponent,
LineChart,
CanvasRenderer,
MarkLineComponent,
]);
type EChartsOption = ComposeOption<
@ -75,6 +78,7 @@ type EChartsOption = ComposeOption<
| GridComponentOption
| DataZoomComponentOption
| LineSeriesOption
| MarkLineComponentOption
>;
const analyzer = useRequiredInjection(useWaveformManager);
@ -90,7 +94,9 @@ const option = computed((): EChartsOption => {
if (isUndefined(analyzer.logicData.value)) return {};
// 使y
const enabledChannels = analyzer.logicData.value.y.filter(channel => channel.enabled);
const enabledChannels = analyzer.logicData.value.y.filter(
(channel) => channel.enabled,
);
const enabledChannelIndices = analyzer.logicData.value.y
.map((channel, index) => (channel.enabled ? index : -1))
.filter((index) => index !== -1);
@ -149,77 +155,141 @@ const option = computed((): EChartsOption => {
//
const series: LineSeriesOption[] = [];
enabledChannelIndices.forEach((originalIndex: number, displayIndex: number) => {
const channel = analyzer.logicData.value!.y[originalIndex];
if (channel.type === "logic") {
// logic
series.push({
name: channel.name,
type: "line",
data: channel.value.map(
(value: number) => value + displayIndex * channelSpacing + 0.2,
),
step: "end",
lineStyle: {
width: 2,
color: channel.color,
},
areaStyle: {
opacity: 0.3,
origin: displayIndex * channelSpacing,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
});
} else if (channel.type === "number") {
// numberVCD仿线10areaStyle
const values = channel.value;
const xArr = analyzer.logicData.value!.x;
//
function buildVcdLine(valArr: number[], high: number, low: number) {
const points: {x: number, y: number}[] = [];
let lastValue = high;
points.push({x: xArr[0], y: lastValue});
for (let i = 1; i < valArr.length; i++) {
const v = valArr[i] !== valArr[i-1] ? (lastValue === high ? low : high) : lastValue;
points.push({x: xArr[i], y: v});
lastValue = v;
enabledChannelIndices.forEach(
(originalIndex: number, displayIndex: number) => {
const channel = analyzer.logicData.value!.y[originalIndex];
if (channel.type === "logic") {
// logic
series.push({
name: channel.name,
type: "line",
data: channel.value.map(
(value: number) => value + displayIndex * channelSpacing + 0.2,
),
step: "end",
lineStyle: {
width: 2,
color: channel.color,
},
areaStyle: {
opacity: 0.3,
origin: displayIndex * channelSpacing,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
});
} else if (channel.type === "number") {
const values = channel.value;
const xArr = analyzer.logicData.value!.x;
//
function buildVcdLine(valArr: number[], high: number, low: number) {
const points: { x: number; y: number }[] = [];
let lastValue = high;
points.push({ x: xArr[0], y: lastValue });
for (let i = 1; i < valArr.length; i++) {
const v =
valArr[i] !== valArr[i - 1]
? lastValue === high
? low
: high
: lastValue;
points.push({ x: xArr[i], y: v });
lastValue = v;
}
return points.map((p) => p.y);
}
// yxcategory
return points.map(p => p.y);
//
function buildMarkLines(valArr: number[], yBase: number) {
const markLines: any[] = [];
let lastValue = valArr[0];
let lastIdx = 0;
//
function formatValue(val: number) {
if (channel.base === "hex") return "0x" + val.toString(16).toUpperCase();
if (channel.base === "bin") return "0b" + val.toString(2);
return val.toString();
}
for (let i = 1; i <= valArr.length; i++) {
if (i === valArr.length || valArr[i] !== lastValue) {
markLines.push([
{
xAxis: lastIdx,
yAxis: yBase,
label: {
formatter: formatValue(lastValue),
position: "insideMiddle",
color: channel.color,
fontSize: 18,
opacity: 1,
},
lineStyle: {
opacity: 0,
},
},
{
xAxis: i - 1,
yAxis: yBase,
lineStyle: {
opacity: 0,
},
},
]);
lastValue = valArr[i];
lastIdx = i;
}
}
return markLines;
}
// 1线
series.push({
name: channel.name + "_1",
type: "line",
data: buildVcdLine(
values,
displayIndex * channelSpacing + 1,
displayIndex * channelSpacing,
),
step: false,
lineStyle: {
width: 2,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
// markLine
markLine: {
data: buildMarkLines(values, displayIndex * channelSpacing + 0.5),
emphasis: {
disabled: true,
},
},
});
// 0线
series.push({
name: channel.name + "_0",
type: "line",
data: buildVcdLine(
values,
displayIndex * channelSpacing,
displayIndex * channelSpacing + 1,
),
step: false,
lineStyle: {
width: 2,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
});
}
// 1线
series.push({
name: channel.name + "_1",
type: "line",
data: buildVcdLine(values, displayIndex * channelSpacing + 1, displayIndex * channelSpacing),
step: false, // step
lineStyle: {
width: 2,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
});
// 0线
series.push({
name: channel.name + "_0",
type: "line",
data: buildVcdLine(values, displayIndex * channelSpacing, displayIndex * channelSpacing + 1),
step: false,
lineStyle: {
width: 2,
color: channel.color,
},
symbol: "none",
sampling: "lttb",
animation: false,
});
}
});
},
);
return {
animation: false,
@ -237,18 +307,20 @@ const option = computed((): EChartsOption => {
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
const dataIndex = params[0].dataIndex;
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
enabledChannelIndices.forEach((originalIndex: number, displayIndex: number) => {
const channel = analyzer.logicData.value!.y[originalIndex];
if (channel.type === "logic") {
const channelName = channel.name;
const originalValue = channel.value[dataIndex];
tooltip += `${channelName}: ${originalValue}<br/>`;
} else if (channel.type === "number") {
const channelName = channel.name;
const originalValue = channel.value[dataIndex];
tooltip += `${channelName}: ${originalValue}<br/>`;
}
});
enabledChannelIndices.forEach(
(originalIndex: number, displayIndex: number) => {
const channel = analyzer.logicData.value!.y[originalIndex];
if (channel.type === "logic") {
const channelName = channel.name;
const originalValue = channel.value[dataIndex];
tooltip += `${channelName}: ${originalValue}<br/>`;
} else if (channel.type === "number") {
const channelName = channel.name;
const originalValue = channel.value[dataIndex];
tooltip += `${channelName}: ${originalValue}<br/>`;
}
},
);
return tooltip;
}
return "";

View File

@ -1,6 +1,6 @@
<template>
<div>
<div class="card">
<div class="card m-5 bg-base-200 shadow-2xl">
<WaveformDisplay />
</div>
</div>