<script setup lang="ts">
|
import { ref, onMounted, onUnmounted} from 'vue';
|
import * as echarts from 'echarts';
|
import { sendToPipe } from '../pipe_client';
|
|
const props = defineProps<{
|
pipeName: string;
|
}>();
|
|
const chartContainer = ref<HTMLElement | null>(null);
|
let chart: echarts.ECharts | null = null;
|
|
// 存储六轴力数据的历史记录
|
const dataHistory = ref<number[][]>([[], [], [], [], [], []]);
|
const maxDataPoints = 100; // 最多显示100个数据点
|
|
// 时间轴数据
|
const timeData = ref<string[]>([]);
|
|
// 初始化图表
|
function initChart() {
|
if (!chartContainer.value) return;
|
|
chart = echarts.init(chartContainer.value);
|
|
const option = {
|
title: {
|
text: '六维力传感器数据',
|
left: 'center'
|
},
|
tooltip: {
|
trigger: 'axis',
|
formatter: function(params: any[]) {
|
let result = params[0].name + '<br/>';
|
params.forEach(item => {
|
// 根据系列名称判断单位
|
const unit = item.seriesName.startsWith('M') ? 'Nm' : 'N';
|
result += item.marker + ' ' + item.seriesName + ': ' + item.value.toFixed(2) + unit + '<br/>';
|
});
|
return result;
|
}
|
},
|
legend: {
|
data: ['Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'],
|
top: 30
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
boundaryGap: false,
|
data: timeData.value
|
},
|
yAxis: {
|
type: 'value',
|
name: '力/力矩值'
|
},
|
series: [
|
{
|
name: 'Fx',
|
type: 'line',
|
data: dataHistory.value[0],
|
smooth: true
|
},
|
{
|
name: 'Fy',
|
type: 'line',
|
data: dataHistory.value[1],
|
smooth: true
|
},
|
{
|
name: 'Fz',
|
type: 'line',
|
data: dataHistory.value[2],
|
smooth: true
|
},
|
{
|
name: 'Mx',
|
type: 'line',
|
data: dataHistory.value[3],
|
smooth: true
|
},
|
{
|
name: 'My',
|
type: 'line',
|
data: dataHistory.value[4],
|
smooth: true
|
},
|
{
|
name: 'Mz',
|
type: 'line',
|
data: dataHistory.value[5],
|
smooth: true
|
}
|
]
|
};
|
|
chart.setOption(option);
|
|
// 响应窗口大小变化
|
window.addEventListener('resize', handleResize);
|
}
|
|
// 更新图表数据
|
function updateChart(forceData: number[]) {
|
if (!chart) return;
|
|
// 添加时间戳
|
const now = new Date();
|
const timeStr = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
|
timeData.value.push(timeStr);
|
|
// 限制时间轴数据点数量
|
if (timeData.value.length > maxDataPoints) {
|
timeData.value.shift();
|
}
|
|
// 更新六轴力数据
|
for (let i = 0; i < 6; i++) {
|
dataHistory.value[i].push(forceData[i]);
|
|
// 限制每条线的数据点数量
|
if (dataHistory.value[i].length > maxDataPoints) {
|
dataHistory.value[i].shift();
|
}
|
}
|
|
// 更新图表
|
chart.setOption({
|
xAxis: {
|
data: timeData.value
|
},
|
series: [
|
{ data: dataHistory.value[0] },
|
{ data: dataHistory.value[1] },
|
{ data: dataHistory.value[2] },
|
{ data: dataHistory.value[3] },
|
{ data: dataHistory.value[4] },
|
{ data: dataHistory.value[5] }
|
]
|
});
|
}
|
|
// 处理窗口大小变化
|
function handleResize() {
|
chart?.resize();
|
}
|
|
// 状态变量,用于控制错误显示频率
|
const errorCount = ref(0);
|
const maxConsecutiveErrors = 5;
|
const showingError = ref(false);
|
|
// 接收管道数据的函数
|
async function receiveForceData() {
|
try {
|
// 从管道接收数据
|
const response = await sendToPipe(props.pipeName, 'GET_FORCE_DATA');
|
|
// 成功接收数据,重置错误计数
|
errorCount.value = 0;
|
if (showingError.value) {
|
showingError.value = false;
|
console.log('管道通信已恢复');
|
}
|
|
// 解析接收到的数据
|
try {
|
const forceData = JSON.parse(response);
|
if (Array.isArray(forceData) && forceData.length === 6) {
|
updateChart(forceData);
|
}
|
} catch (e) {
|
console.warn('解析数据失败:', e);
|
}
|
} catch (err) {
|
// 增加错误计数
|
errorCount.value++;
|
|
// 只在连续错误达到阈值时显示错误信息,避免日志刷屏
|
if (errorCount.value >= maxConsecutiveErrors && !showingError.value) {
|
showingError.value = true;
|
console.error('管道通信持续失败,请检查服务端状态:', err);
|
}
|
}
|
}
|
|
// 定时获取数据
|
let dataTimer: number | null = null;
|
|
onMounted(() => {
|
initChart();
|
|
// 每秒获取一次数据
|
dataTimer = window.setInterval(receiveForceData, 1000);
|
});
|
|
onUnmounted(() => {
|
// 清理定时器和事件监听
|
if (dataTimer !== null) {
|
clearInterval(dataTimer);
|
}
|
|
window.removeEventListener('resize', handleResize);
|
|
// 销毁图表实例
|
chart?.dispose();
|
chart = null;
|
});
|
</script>
|
|
<template>
|
<div class="chart-container" ref="chartContainer"></div>
|
</template>
|
|
<style scoped>
|
.chart-container {
|
width: 100%;
|
height: 540px;
|
margin: 20px 0;
|
}
|
</style>
|