8 changed files with 4200 additions and 79 deletions
@ -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