<script lang="ts" setup name="LineChart"> import * as echarts from 'echarts/core' import type { ECharts } from 'echarts' import { init } from 'echarts' import type { Ref } from 'vue' import type { ECBasicOption } from 'echarts/types/dist/shared' import type { lineDataI, lineOption, lineSeriesOption } from './echart-interface' import tdTheme from './theme.json' // 引入默认主题 import { formatColor, getAlphaColor } from './utils' const props = defineProps({ // id id: { type: String, default: 'chart', }, loading: { type: Boolean, default: false, }, // 图例是否显示 legendShow: { type: Boolean, default: false, }, // 图例 legend: { type: Array<string>, default: () => { return [] }, }, // 图表宽 width: { type: String, default: '100%', }, // 图表高 height: { type: String, default: '100%', }, // X轴数据 xAxisData: { type: Array<string>, default: () => { return [] }, }, // X轴类型 xAxisType: { type: String, default: 'category', validator: (value: string) => { return ['category', 'value', 'time', 'log'].includes(value) }, }, // 数据 data: { type: Array<lineDataI>, default: () => { return [] }, }, // 单位 unit: { type: String, default: '', }, // 颜色 colors: { type: Array, default: () => { return [] }, }, // 实虚线 axisLineType: { type: String, default: '', }, // 轴线颜色 axisLineColor: { type: String, default: '#96989b', }, // 轴线上文字颜色 fontColor: { type: String, default: '#000000', }, // 是否为渐变折线图 gradient: { type: Boolean, default: true, }, // 标题 title: { type: String, default: '', }, // 平滑 smooth: { type: Boolean, default: true, }, }) // 图表对象 let chart: ECharts const chartRef: Ref<HTMLElement | null> = ref(null) // 监听数据变化 watch( [() => props.xAxisData, props.data], ([newName, newNums], [oldName, oldNums]) => { refreshChart() }, { immediate: true, deep: true, }, ) // 构建option function buildOption() { const option: lineOption = { grid: { show: false, // 是否显示直角坐标系网格 left: 10, right: 30, bottom: 5, top: 30, containLabel: true, // grid 区域是否包含坐标轴的刻度标签 }, // 网格 legend: { show: props.legendShow, orient: 'horizontal', // 图例方向 align: 'left', // 图例标记和文本的对齐,默认自动 top: 5, padding: [0, 0, 0, 120], right: 130, }, // 图例 tooltip: { trigger: 'axis', textStyle: { fontSize: 16, }, axisPointer: { type: 'cross', label: { fontSize: 13, }, }, valueFormatter: (value: string | number) => { return value ? value + props.unit : '' }, }, // 提示框 xAxis: [ { type: props.xAxisType, boundaryGap: true, axisLine: { lineStyle: { color: props.axisLineColor, // 轴线的颜色 }, }, axisLabel: { color: props.fontColor, // X轴名称颜色 fontSize: 14, }, splitLine: { show: false, lineStyle: { color: ['#7a6b74'], type: props.axisLineType, }, }, }, ], yAxis: [ { name: props.unit, type: 'value', boundaryGap: true, axisLine: { show: false, lineStyle: { color: props.axisLineColor, // 轴线的颜色 }, }, nameTextStyle: { color: props.fontColor, fontSize: 14, verticalAlign: 'middle', }, splitLine: { show: true, lineStyle: { color: ['#7a6b74'], type: 'dashed', }, }, }, ], series: [] as lineSeriesOption[], } // 标题 if (props.title) { option.title = { show: true, text: props.title, } } // 图例 if (props.legend && props.legend.length > 0) { option.legend!.data = props.legend } // x轴数据 if (props.xAxisData && props.xAxisData.length > 0) { if (Array.isArray(option.xAxis) && option.xAxis.length > 0) { option.xAxis[0].data = props.xAxisData // 横轴 } } // 数据 if (props.data) { const newSeries: lineSeriesOption[] = [] // 遍历data, 拆分轴线名称,数据和颜色 for (const itemIndex in props.data) { const item = props.data[itemIndex] const series: lineSeriesOption = { name: item.name, // 线系列名 type: 'line', symbol: 'none', // 去掉折线节点 smooth: props.smooth, // 曲线平滑设置 lineStyle: { width: 2, }, data: item.data, } // 线段颜色 if (item.color || props.colors.length > 0) { series.itemStyle = { color: item.color ? formatColor(item.color) : formatColor(props.colors[itemIndex] as string), } // 如果开启渐变 if (props.gradient) { series.areaStyle = { color: new echarts.graphic.LinearGradient( 0, 0, 0, 1, // 变化度 ,渐变方向 [ { offset: 0.1, color: item.color ? getAlphaColor(item.color, 0.6) : getAlphaColor(props.colors[itemIndex] as string, 0.6), }, { offset: 1, color: '#fff', }, ], ), } } } newSeries.push(series) } option.series = newSeries } return option } // 初始化图表 function initChart() { chart = init(chartRef.value as HTMLElement, tdTheme) chart.setOption({}) } // 刷新图表 function refreshChart() { if (chart) { const option = buildOption() chart.setOption(option as unknown as ECBasicOption, true) } } window.addEventListener('resize', () => { chart.resize() }) onMounted(() => { initChart() }) </script> <template> <div :id="id" ref="chartRef" v-loading="loading" class="chart" :style="{ height, width }" /> </template> <style lang="scss" scoped> .chart { width: 100%; height: 100%; } </style>