You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
5.1 KiB

<template>
<div class="device-data-chart">
<v-chart
class="chart"
ref="chartRef"
:option="chartOption"
:autoresize="autoresize"
:loading-options="loadingOpt"
:loading="loading"
@legendselectchanged="changeLegend"/>
</div>
</template>
<script setup lang="ts">
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import type { EChartsOption, SeriesOption } from 'echarts/types/dist/shared.js'
import { LineChart } from 'echarts/charts'
import {
TooltipComponent,
LegendComponent,
DataZoomComponent,
GridComponent,
} from 'echarts/components'
use([
CanvasRenderer,
TooltipComponent,
LineChart,
LegendComponent,
GridComponent,
DataZoomComponent,
])
const ZOOM_HEIGHT = 30
const ZOOM_BOTTOM = 10
type Legend = {
addr: string
label: string
unit?: string
}
const autoresize = {
throttle: 0,
}
const props = defineProps({
title: String,
smooth: Boolean, //当前是曲线图还是阶梯图
legends: {
type: Array as PropType<Legend[]>,
default: () => [],
},
axisData: {
type: Array as PropType<string[]>,
default: () => [],
},
chartDatas: {
type: Object as PropType<Map<string, any[]>>,
default: () => new Map(),
},
})
const loading = ref(true)
const loadingOpt = {
type: 'default',
text: '暂无数据',
color: '#c23531',
textColor: '#666',
maskColor: 'rgba(0, 0, 0, 0)',
showSpinner: false,
}
const chartRef = ref()
const chartOption = computed<EChartsOption>(() => {
if (props.chartDatas.size === 0) {
return {}
}
loading.value = false
const tmpSeries: SeriesOption[] = []
for (const legend of props.legends.filter(item => item.addr !== 'ts')) {
const entry = props.chartDatas.get(legend.addr)
const lineData: SeriesOption = {
name: legend.label,
type: 'line',
id: legend.addr,
// symbol: "none",
connectNulls: true,
data: entry,
}
if (props.smooth) {
lineData.smooth = true
} else {
lineData.step = 'middle'
}
tmpSeries.push(lineData)
}
const option: EChartsOption = {
grid: {
left: 60,
right: 198,
top: '5%',
bottom: `25%`,
},
tooltip: {
trigger: 'axis',
confine: true,
appendToBody: true,
// formatter: function (params: any) {
// var relVal = params[0].name
//
// for (var i = 0, l = params.length; i < l; i++) {
// relVal += `<div style="display: flex; justify-content: space-between; gap: 30px;">
// <div>${params[i].marker}${params[i].seriesName}:</div> <div">${params[i].value[1]}${props.legends.find(item => item.addr === params[i].seriesId)?.unit || ''}</div>
// </div>`
// }
// return relVal
// }
},
legend: {
type: 'scroll',
orient: 'vertical',
formatter: name => {
return name.length > 15 ? name.substring(0, 15) + '...' : name
},
tooltip: {
show: true,
},
right: 0,
top: 20,
itemWidth: 10,
itemHeight: 10,
pageIconSize: 12,
data: props.legends.map(item => item.label),
selected: unCheckArr.value.reduce((acc, cur) => {
acc[cur] = false
return acc
}, {} as Record<string, boolean>),
},
xAxis: {
type: 'time',
axisLine: {
//y轴线的颜色以及宽度
show: true,
lineStyle: {
width: 1,
type: 'solid',
},
},
axisLabel: {
show: false,
}
},
yAxis: {
type: 'value',
splitNumber: 6,
axisLine: {
//y轴线的颜色以及宽度
show: true,
lineStyle: {
width: 1,
type: 'solid',
},
},
axisLabel: {
margin: 12,
fontSize: 12,
},
splitLine: {
show: true,
lineStyle: {},
},
},
dataZoom: [
{
type: 'inside',
xAxisIndex: 0,
filterMode: 'filter',
start: 90,
end: 100,
},
{
type: 'slider',
xAxisIndex: 0,
filterMode: 'filter',
start: 90,
end: 100,
height: ZOOM_HEIGHT,
bottom: `20%`,
borderColor: '#88abf5',
dataBackground: {
lineStyle: {
color: '#d2dbee',
},
},
selectedDataBackground: {
lineStyle: {
color: '#2c6cf7',
},
},
moveHandleStyle: {
color: '#2c6cf7',
},
},
],
series: tmpSeries,
}
return option
})
const unCheckArr = ref<string[]>([])
function changeLegend(data: { name: string; selected: Record<string, boolean> }) {
const { name, selected } = data
if (!selected[name]) {
unCheckArr.value.push(name)
} else {
unCheckArr.value = unCheckArr.value.filter(item => item !== name)
}
}
</script>
<style scoped lang="scss">
.device-data-chart {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.chart {
width: 100%;
height: 90%;
min-height: 100px;
}
}
</style>