feat: echart折线图
This commit is contained in:
264
src/components/ChartLine/index.vue
Normal file
264
src/components/ChartLine/index.vue
Normal 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>
|
||||
Reference in New Issue
Block a user