feat: echart折线图

This commit is contained in:
TsMask
2023-11-01 17:45:43 +08:00
parent dcbd75b8c9
commit 45ddbd3bc2

View File

@@ -0,0 +1,264 @@
<template>
<div ref="chartDom" :style="{ height: height, width: width }"></div>
</template>
<script lang="ts" setup>
import { nextTick, watch, onMounted, onBeforeUnmount, ref } from 'vue';
import * as echarts from 'echarts/core';
import {
TitleComponent,
ToolboxComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
} from 'echarts/components';
import { LineChart } from 'echarts/charts';
import { UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import { parseSizeFromKBs, parseSizeFromMB } from '@/utils/parse-utils';
echarts.use([
TitleComponent,
ToolboxComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
LineChart,
CanvasRenderer,
UniversalTransition,
]);
const props = defineProps({
/**
* 图表主题
*
* 'dark' | 'light'
*/
theme: {
type: String,
default: 'light', // 'dark' | 'light'
},
/**宽度默认100% */
width: {
type: String,
default: '100%',
},
/**高度 */
height: {
type: String,
default: '200px',
},
/**底部时间轴 */
dataZoom: {
type: Boolean,
default: false,
},
/**
* option: { title , xDatas, yDatas, formatStr, yAxis, grid, tooltip}
*
* grid 图偏移 列如{ left: '15%', right: '15%', bottom: '20%' }
* formatStr 支持 'KB/s'、'MB'、自定义格式
*/
option: {
type: Object,
required: true,
},
});
const seriesStyle = [
{
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(22, 119, 255, .5)',
},
{
offset: 1,
color: 'rgba(22, 119, 255, 0)',
},
]),
},
{
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(82, 196, 26, .5)',
},
{
offset: 1,
color: 'rgba(82, 196, 26, 0)',
},
]),
},
{
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(250, 173, 20, .5)',
},
{
offset: 1,
color: 'rgba(250, 173, 20, 0)',
},
]),
},
{
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(255, 77, 79, 0.5)',
},
{
offset: 1,
color: 'rgba(255, 77, 79, 0)',
},
]),
},
];
let newChart: echarts.ECharts;
const chartDom = ref<HTMLElement | undefined>(undefined);
/**初始化渲染图表 */
function initChart() {
if (!newChart) {
newChart = echarts.init(chartDom.value);
}
const series: any = [];
const yDatasLen = props.option?.yDatas?.length || 0;
if (yDatasLen > 0) {
props.option?.yDatas.forEach((item: any, index: number) => {
series.push({
name: item?.name,
type: 'line',
areaStyle: seriesStyle[index % yDatasLen],
data: item?.data,
showSymbol: false,
yAxisIndex: item.yAxisIndex ? 1 : null,
});
});
} else {
console.error('components ChartLine echarts yDatas error!');
return;
}
// 右侧y轴辅助线
const yAxis: any = [];
if (props.option.yAxis && props.option.yAxis.length > 0) {
props.option.yAxis.forEach((item: any) => {
yAxis.push({
splitLine: {
show: true,
//分隔辅助线
lineStyle: {
type: 'dashed', //线的类型 虚线0
opacity: props.theme === 'dark' ? 0.1 : 1, //透明度
},
},
...item,
});
});
}
// 把配置和数据放这里
const option = {
title: [
{
left: 'center',
text: props.option.title,
show: props.option.title,
},
],
zlevel: 1,
z: 1,
tooltip: props.option.tooltip || {
trigger: 'axis',
formatter: function (datas: any) {
let res = datas[0].name + '<br/>';
// 拼接值的格式
switch (props.option.formatStr) {
case 'KB/s':
for (const item of datas) {
res += `${item.marker} ${item.seriesName}${parseSizeFromKBs(
item.data
)}<br/>`;
}
break;
case 'MB':
for (const item of datas) {
res += `${item.marker} ${item.seriesName}${parseSizeFromMB(
item.data
)}<br/>`;
}
break;
default:
for (const item of datas) {
res += `${item.marker} ${item.seriesName}${item.data}${props.option.formatStr}<br/>`;
}
break;
}
return res;
},
},
grid: props.option.grid || { left: '8%', right: '8%', bottom: '20%' },
legend: {
right: 10,
itemWidth: 8,
textStyle: {
color: '#646A73',
},
icon: 'circle',
},
xAxis: { data: props.option.xDatas, boundaryGap: false },
yAxis: props.option.yAxis
? yAxis
: {
name: '( ' + props.option.formatStr + ' )',
splitLine: {
//分隔辅助线
lineStyle: {
type: 'dashed', //线的类型 虚线0
opacity: props.theme === 'dark' ? 0.1 : 1, //透明度
},
},
},
series: series,
dataZoom: [{ startValue: props.option?.xDatas[0], show: props.dataZoom }],
};
// 渲染数据
newChart.setOption(option, true);
}
/**重置图表尺寸 */
function changeChartSize() {
newChart.resize();
}
watch(
() => props.option,
val => {
if (val) {
nextTick(() => {
initChart();
});
}
}
);
onMounted(() => {
nextTick(() => {
initChart();
window.addEventListener('resize', changeChartSize);
});
});
onBeforeUnmount(() => {
newChart.dispose();
window.removeEventListener('resize', changeChartSize);
});
</script>
<style lang="less" scoped></style>