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.
243 lines
5.1 KiB
243 lines
5.1 KiB
|
7 months ago
|
<template>
|
||
|
|
<div class="device-data-chart">
|
||
|
2 months ago
|
<v-chart
|
||
|
|
class="chart"
|
||
|
|
ref="chartRef"
|
||
|
|
:option="chartOption"
|
||
|
|
:autoresize="autoresize"
|
||
|
|
:loading-options="loadingOpt"
|
||
|
|
:loading="loading"
|
||
|
|
@legendselectchanged="changeLegend"/>
|
||
|
7 months ago
|
</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
|
||
|
5 months ago
|
unit?: string
|
||
|
7 months ago
|
}
|
||
|
|
|
||
|
|
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',
|
||
|
5 months ago
|
text: '暂无数据',
|
||
|
7 months ago
|
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',
|
||
|
5 months ago
|
id: legend.addr,
|
||
|
7 months ago
|
// symbol: "none",
|
||
|
|
connectNulls: true,
|
||
|
|
data: entry,
|
||
|
|
}
|
||
|
|
if (props.smooth) {
|
||
|
|
lineData.smooth = true
|
||
|
|
} else {
|
||
|
|
lineData.step = 'middle'
|
||
|
|
}
|
||
|
|
tmpSeries.push(lineData)
|
||
|
|
}
|
||
|
6 months ago
|
|
||
|
7 months ago
|
const option: EChartsOption = {
|
||
|
|
grid: {
|
||
|
|
left: 60,
|
||
|
|
right: 198,
|
||
|
|
top: '5%',
|
||
|
|
bottom: `25%`,
|
||
|
|
},
|
||
|
|
tooltip: {
|
||
|
|
trigger: 'axis',
|
||
|
|
confine: true,
|
||
|
|
appendToBody: true,
|
||
|
2 months ago
|
// 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
|
||
|
|
// }
|
||
|
7 months ago
|
},
|
||
|
|
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: 'category',
|
||
|
|
axisLine: {
|
||
|
|
//y轴线的颜色以及宽度
|
||
|
|
show: true,
|
||
|
|
lineStyle: {
|
||
|
|
width: 1,
|
||
|
|
type: 'solid',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
axisLabel: {
|
||
|
|
show: false,
|
||
|
|
},
|
||
|
|
data: props.axisData,
|
||
|
|
},
|
||
|
|
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>
|