CMVR-IOT-UI/src/views/device/register/components/DexHand/RightBottomCharts.vue

186 lines
5.2 KiB
Vue
Raw Normal View History

2025-08-21 14:11:58 +08:00
<template>
<div style="width: 100%;height: 100%; margin: 0 auto;">
<div class="tabs">
<div
v-for="(tab, index) in tabs"
:key="index"
class="tab"
:class="{ active: activeTab === tab.value }"
@click="switchTab(tab.value)"
>
{{ tab.label }}
</div>
</div>
<div ref="chart" style="width: 100%; height: 100%;"></div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 解构 props
const props = defineProps({
maxData: {
type: Object,
required: true,
default: () => ({
thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
indexFinger: { end: 0, tip: 0, middle: 0 },
middleFinger: { end: 0, tip: 0, middle: 0 },
ringFinger: { end: 0, tip: 0, middle: 0 },
littleFinger: { end: 0, tip: 0, middle: 0 },
palm: { touch: 0 }
})
},
avgData: {
type: Object,
required: true,
default: () => ({
thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
indexFinger: { end: 0, tip: 0, middle: 0 },
middleFinger: { end: 0, tip: 0, middle: 0 },
ringFinger: { end: 0, tip: 0, middle: 0 },
littleFinger: { end: 0, tip: 0, middle: 0 },
palm: { touch: 0 }
})
}
});
const chart = ref(null);
const activeTab = ref('avg'); // 默认选中平均值
// Tab 配置
const tabs = [
{ label: '最大值', value: 'max' },
{ label: '平均值', value: 'avg' }
];
let myChart;
const initChart = () => {
if (!chart.value) {
console.error('Chart element is null');
return;
}
myChart = echarts.init(chart.value);
const option = {
title: { text: '手指触觉数据' },
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { data: ['指端', '指尖', '指中', '指腹', '手掌触觉'] },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: ['小拇指', '无名指', '中指', '食指', '大拇指', '手掌'],
splitArea: { show: true }
},
yAxis: [{ type: 'value', name: '弯曲应力', max: 4000,interval: 1000 }],
series: [
{ name: '指端', type: 'bar', barGap: '1%', barCategoryGap: '10%', itemStyle: { color: '#FF5733' }, label: { show: true, position: 'top' }, emphasis: { focus: 'series' }, data: [] },
{ name: '指尖', type: 'bar', barGap: '1%', barCategoryGap: '10%', itemStyle: { color: '#33FF57' }, label: { show: true, position: 'top' }, emphasis: { focus: 'series' }, data: [] },
{ name: '指中', type: 'bar', barGap: '1%', barCategoryGap: '10%', itemStyle: { color: '#5733FF' }, label: { show: true, position: 'top' }, emphasis: { focus: 'series' }, data: [] },
{ name: '指腹', type: 'bar', barGap: '1%', barCategoryGap: '10%', itemStyle: { color: '#FF33A1' }, label: { show: true, position: 'top' }, emphasis: { focus: 'series' }, data: [] },
{ name: '手掌触觉', type: 'bar', barGap: '1%', barCategoryGap: '10%', itemStyle: { color: '#FFD700' }, label: { show: true, position: 'top' }, emphasis: { focus: 'series' }, data: [] }
]
};
myChart.setOption(option);
};
// 获取每个部分的数据,处理空值
const getPartData = (data, part) => {
return [
data.littleFinger[part] || null,
data.ringFinger[part] || null,
data.middleFinger[part] || null,
data.indexFinger[part] || null,
data.thumb[part] || null,
data.palm[part] || null
];
};
const updateChart = (data) => {
const seriesData = {
end: getPartData(data, 'end'),
tip: getPartData(data, 'tip'),
middle: getPartData(data, 'middle'),
palm: getPartData(data, 'palm'),
touch: getPartData(data, 'touch')
};
myChart.setOption({
series: [
{ name: '指端', data: seriesData.end },
{ name: '指尖', data: seriesData.tip },
{ name: '指中', data: seriesData.middle },
{ name: '指腹', data: seriesData.palm },
{ name: '手掌触觉', data: seriesData.touch }
]
});
};
const switchTab = (tab) => {
activeTab.value = tab;
updateChart(activeTab.value === 'max' ? props.maxData : props.avgData);
};
// 监听 props 变化,更新图表
watch([() => props.maxData, () => props.avgData, activeTab], () => {
updateChart(activeTab.value === 'max' ? props.maxData : props.avgData);
});
onMounted(() => {
initChart();
updateChart(activeTab.value === 'max' ? props.maxData : props.avgData);
// 处理窗口大小变化
const handleResize = () => {
myChart?.resize();
};
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
// 清理图表实例和事件监听器
myChart?.dispose();
window.removeEventListener('resize', () => {
myChart?.resize();
});
});
</script>
<style scoped>
.container {
display: flex;
width: 100%;
margin: 0 auto;
flex-direction: column;
}
.tabs {
position: absolute;
right: 50%;
justify-content: center;
background: rgba(0, 0, 0, 0);
border-radius: 10px 10px 0 0;
padding: 5px 0;
}
.tab {
padding: 10px 20px;
margin: 0 10px;
cursor: pointer;
font-size: 16px;
color: #333;
border-bottom: 3px solid transparent;
transition: all 0.3s ease;
}
.tab:hover {
background-color: #f5f5f5;
border-radius: 5px;
}
.tab.active {
border-bottom: 3px solid #007bff;
color: #007bff;
}
</style>