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