8 changed files with 4200 additions and 79 deletions
@ -0,0 +1,234 @@
@@ -0,0 +1,234 @@
|
||||
<template> |
||||
<div class="device-data-chart"> |
||||
<v-chart |
||||
class="chart" |
||||
:option="chartOption" |
||||
:autoresize="autoresize" |
||||
:loading-options="loadingOpt" |
||||
:loading="loading" |
||||
ref="chartRef" |
||||
@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 |
||||
} |
||||
|
||||
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', |
||||
// 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, |
||||
}, |
||||
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) |
||||
} |
||||
|
||||
console.log(unCheckArr.value) |
||||
} |
||||
// useWindowResize(handleResize) |
||||
</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> |
Loading…
Reference in new issue