feat: 添加数值类型的波形显示
This commit is contained in:
parent
6c1bda50ce
commit
f200d90fc0
|
@ -39,6 +39,7 @@ import {
|
||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
AxisPointerComponent,
|
AxisPointerComponent,
|
||||||
ToolboxComponent,
|
ToolboxComponent,
|
||||||
|
MarkLineComponent,
|
||||||
} from "echarts/components";
|
} from "echarts/components";
|
||||||
import { CanvasRenderer } from "echarts/renderers";
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
import type { ComposeOption } from "echarts/core";
|
import type { ComposeOption } from "echarts/core";
|
||||||
|
@ -48,6 +49,7 @@ import type {
|
||||||
TooltipComponentOption,
|
TooltipComponentOption,
|
||||||
GridComponentOption,
|
GridComponentOption,
|
||||||
DataZoomComponentOption,
|
DataZoomComponentOption,
|
||||||
|
MarkLineComponentOption,
|
||||||
} from "echarts/components";
|
} from "echarts/components";
|
||||||
import type {
|
import type {
|
||||||
ToolboxComponentOption,
|
ToolboxComponentOption,
|
||||||
|
@ -66,6 +68,7 @@ use([
|
||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
LineChart,
|
LineChart,
|
||||||
CanvasRenderer,
|
CanvasRenderer,
|
||||||
|
MarkLineComponent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
type EChartsOption = ComposeOption<
|
type EChartsOption = ComposeOption<
|
||||||
|
@ -75,6 +78,7 @@ type EChartsOption = ComposeOption<
|
||||||
| GridComponentOption
|
| GridComponentOption
|
||||||
| DataZoomComponentOption
|
| DataZoomComponentOption
|
||||||
| LineSeriesOption
|
| LineSeriesOption
|
||||||
|
| MarkLineComponentOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const analyzer = useRequiredInjection(useWaveformManager);
|
const analyzer = useRequiredInjection(useWaveformManager);
|
||||||
|
@ -90,7 +94,9 @@ const option = computed((): EChartsOption => {
|
||||||
if (isUndefined(analyzer.logicData.value)) return {};
|
if (isUndefined(analyzer.logicData.value)) return {};
|
||||||
|
|
||||||
// 只获取启用的通道,使用y数据结构
|
// 只获取启用的通道,使用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
|
const enabledChannelIndices = analyzer.logicData.value.y
|
||||||
.map((channel, index) => (channel.enabled ? index : -1))
|
.map((channel, index) => (channel.enabled ? index : -1))
|
||||||
.filter((index) => index !== -1);
|
.filter((index) => index !== -1);
|
||||||
|
@ -149,77 +155,141 @@ const option = computed((): EChartsOption => {
|
||||||
|
|
||||||
// 创建系列数据
|
// 创建系列数据
|
||||||
const series: LineSeriesOption[] = [];
|
const series: LineSeriesOption[] = [];
|
||||||
enabledChannelIndices.forEach((originalIndex: number, displayIndex: number) => {
|
enabledChannelIndices.forEach(
|
||||||
const channel = analyzer.logicData.value!.y[originalIndex];
|
(originalIndex: number, displayIndex: number) => {
|
||||||
if (channel.type === "logic") {
|
const channel = analyzer.logicData.value!.y[originalIndex];
|
||||||
// logic类型,原样显示
|
if (channel.type === "logic") {
|
||||||
series.push({
|
// logic类型,原样显示
|
||||||
name: channel.name,
|
series.push({
|
||||||
type: "line",
|
name: channel.name,
|
||||||
data: channel.value.map(
|
type: "line",
|
||||||
(value: number) => value + displayIndex * channelSpacing + 0.2,
|
data: channel.value.map(
|
||||||
),
|
(value: number) => value + displayIndex * channelSpacing + 0.2,
|
||||||
step: "end",
|
),
|
||||||
lineStyle: {
|
step: "end",
|
||||||
width: 2,
|
lineStyle: {
|
||||||
color: channel.color,
|
width: 2,
|
||||||
},
|
color: channel.color,
|
||||||
areaStyle: {
|
},
|
||||||
opacity: 0.3,
|
areaStyle: {
|
||||||
origin: displayIndex * channelSpacing,
|
opacity: 0.3,
|
||||||
color: channel.color,
|
origin: displayIndex * channelSpacing,
|
||||||
},
|
color: channel.color,
|
||||||
symbol: "none",
|
},
|
||||||
sampling: "lttb",
|
symbol: "none",
|
||||||
animation: false,
|
sampling: "lttb",
|
||||||
});
|
animation: false,
|
||||||
} else if (channel.type === "number") {
|
});
|
||||||
// number类型,VCD仿真样式:两个线条(1和0),变化时有斜率(过渡点),无areaStyle
|
} else if (channel.type === "number") {
|
||||||
const values = channel.value;
|
const values = channel.value;
|
||||||
const xArr = analyzer.logicData.value!.x;
|
const xArr = analyzer.logicData.value!.x;
|
||||||
// 构造带过渡的点序列
|
// 构造带过渡的点序列
|
||||||
function buildVcdLine(valArr: number[], high: number, low: number) {
|
function buildVcdLine(valArr: number[], high: number, low: number) {
|
||||||
const points: {x: number, y: number}[] = [];
|
const points: { x: number; y: number }[] = [];
|
||||||
let lastValue = high;
|
let lastValue = high;
|
||||||
points.push({x: xArr[0], y: lastValue});
|
points.push({ x: xArr[0], y: lastValue });
|
||||||
for (let i = 1; i < valArr.length; i++) {
|
for (let i = 1; i < valArr.length; i++) {
|
||||||
const v = valArr[i] !== valArr[i-1] ? (lastValue === high ? low : high) : lastValue;
|
const v =
|
||||||
points.push({x: xArr[i], y: v});
|
valArr[i] !== valArr[i - 1]
|
||||||
lastValue = v;
|
? lastValue === high
|
||||||
|
? low
|
||||||
|
: high
|
||||||
|
: lastValue;
|
||||||
|
points.push({ x: xArr[i], y: v });
|
||||||
|
lastValue = v;
|
||||||
|
}
|
||||||
|
return points.map((p) => p.y);
|
||||||
}
|
}
|
||||||
// 返回y数组,x由category轴控制
|
|
||||||
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 {
|
return {
|
||||||
animation: false,
|
animation: false,
|
||||||
|
@ -237,18 +307,20 @@ const option = computed((): EChartsOption => {
|
||||||
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
|
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
|
||||||
const dataIndex = params[0].dataIndex;
|
const dataIndex = params[0].dataIndex;
|
||||||
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
|
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
|
||||||
enabledChannelIndices.forEach((originalIndex: number, displayIndex: number) => {
|
enabledChannelIndices.forEach(
|
||||||
const channel = analyzer.logicData.value!.y[originalIndex];
|
(originalIndex: number, displayIndex: number) => {
|
||||||
if (channel.type === "logic") {
|
const channel = analyzer.logicData.value!.y[originalIndex];
|
||||||
const channelName = channel.name;
|
if (channel.type === "logic") {
|
||||||
const originalValue = channel.value[dataIndex];
|
const channelName = channel.name;
|
||||||
tooltip += `${channelName}: ${originalValue}<br/>`;
|
const originalValue = channel.value[dataIndex];
|
||||||
} else if (channel.type === "number") {
|
tooltip += `${channelName}: ${originalValue}<br/>`;
|
||||||
const channelName = channel.name;
|
} else if (channel.type === "number") {
|
||||||
const originalValue = channel.value[dataIndex];
|
const channelName = channel.name;
|
||||||
tooltip += `${channelName}: ${originalValue}<br/>`;
|
const originalValue = channel.value[dataIndex];
|
||||||
}
|
tooltip += `${channelName}: ${originalValue}<br/>`;
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="card">
|
<div class="card m-5 bg-base-200 shadow-2xl">
|
||||||
<WaveformDisplay />
|
<WaveformDisplay />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue