1. 效果图:
2. 功能
1. 根据选项动态修改图表显示
2. 动态修改颜色、Y轴单位
3. 可根据配置项动态修改x轴数据为年月日,年(Y)默认展示最近五年,月(M)展示12个月或展示到当前月份,日(D)展示当前月份的天数或展示到当前月当前天
3.话不多说直接上代码,具体说明在最后
c-line-chart.vue
<template>
<div :id="randomId" :style="`width: ${width};height: ${height}`"></div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts'
import { ECharts } from 'echarts'
import { merge, debounce } from 'lodash'
import { parseColorString } from '@/utils/tools'
import { ref, onMounted, watch, shallowRef } from 'vue'
import dayjs from 'dayjs'
interface configXDataType {
allXData?: boolean
xDataType?: 'Y' | 'M' | 'D'
}
interface Props {
width?: string
height?: string
option?: any
unit?: string
configXData: configXDataType
}
const props = withDefaults(defineProps<Props>(), {
width: '100%',
height: '100%',
configXData: () => {
return {
xDataType: 'D',
allXData: false
}
}
})
const randomId = (Math.random() * 100000).toFixed(0)
let color = ref<string[]>([
'#5470c6',
'#91cc75',
'#fac858',
'#ee6666',
'#73c0de',
'#3ba272',
'#fc8452',
'#9a60b4',
'#ea7ccc'
])
let myChart = shallowRef<ECharts>()
const hexToRgba = (hex: any, opacity: any) => {
let rgbaColor = ''
let reg = /^#[\da-f]{6}$/i
const colorTest = parseColorString(hex)
if (reg.test(hex)) {
rgbaColor = `rgba(${colorTest.r},${colorTest.g},${colorTest.b},${opacity})`
}
return rgbaColor
}
const option = (color: string[], xData?: string[]) => {
return {
color,
legend: {
padding: [20, 20, 0, 0],
icon: 'rect',
itemWidth: 15,
itemHeight: 4,
x: 'right',
y: 'top',
textStyle: {
color: '#BFD5E0',
fontSize: 14
}
},
tooltip: {
show: true,
trigger: 'axis',
borderColor: '#000',
backgroundColor: 'rgba(0, 0, 0, 0.50)',
formatter: function (params: any) {
let html = ''
params.forEach((v: any) => {
html += `<div style="color: #fff;font-size: 18px;line-height: 25px;">
<span style="margin-right:8px"> ${v.axisValue}</span>
<span style="color:${color[v.componentIndex]};
font-weight:700;font-size: 18px;font-family: QuartzEF;">${
v.value
}</span>
<span style='color:#97A5C5;font-size: 15px'>${
props.unit || ''
}</span>`
})
return html
},
axisPointer: {
type: 'line',
lineStyle: {
type: 'solid',
color: 'rgba(168, 181, 189, 0.8)'
}
}
},
grid: {
top: '18%',
left: '12%',
right: '5%',
bottom: '15%'
},
xAxis: [
{
type: 'category',
interval: 1,
splitNumber: 4,
// boundaryGap: false,
axisLabel: {
margin: 15,
textStyle: {
color: '#BFD5E0',
fontSize: 14
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
data: xData
}
],
yAxis: [
{
type: 'value',
name: props.unit,
axisLabel: {
textStyle: {
color: '#BFD5E0',
fontSize: 14
}
},
nameTextStyle: {
color: '#BFD5E0',
fontSize: 14,
padding: [0, 0, 0, -40]
},
splitLine: {
lineStyle: {
type: 'solid',
width: 1,
color: 'rgba(0, 179, 254, 0.12)'
}
},
axisLine: {
show: false
}
}
],
series: [
{
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
normal: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: hexToRgba(color[0], 0.6)
},
{
offset: 1,
color: hexToRgba(color[0], 0.2)
}
]
}
}
},
data: []
},
{
type: 'line',
smooth: true,
symbol: 'none',
symbolSize: 8,
zlevel: 3,
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: hexToRgba(color[1], 0.6)
},
{
offset: 1,
color: hexToRgba(color[1], 0.2)
}
],
false
)
}
},
data: []
},
{
type: 'line',
smooth: true,
symbol: 'none',
symbolSize: 8,
zlevel: 3,
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: hexToRgba(color[2], 0.6)
},
{
offset: 1,
color: hexToRgba(color[2], 0.2)
}
],
false
)
}
},
data: []
},
{
type: 'line',
smooth: true,
symbol: 'none',
symbolSize: 8,
zlevel: 3,
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: hexToRgba(color[3], 0.6)
},
{
offset: 1,
color: hexToRgba(color[3], 0.2)
}
],
false
)
}
},
data: []
}
]
}
}
const drawChart = debounce(() => {
myChart.value = echarts.init(document.getElementById(randomId) as HTMLElement)
color.value = props.option?.color
? [...props.option?.color, ...color.value]
: [
'#5470c6',
'#91cc75',
'#fac858',
'#ee6666',
'#73c0de',
'#3ba272',
'#fc8452',
'#9a60b4',
'#ea7ccc'
]
myChart.value.setOption(
merge(option(color.value, getXData(props.configXData)), props.option)
)
}, 500)
onMounted(() => {
drawChart()
})
watch(
() => props,
() => {
console.log(props.option)
drawChart()
},
{
deep: true
}
)
// 获取x轴数据
const getXData = (configXData: configXDataType) => {
const allVal = configXData.allXData
const xDataType = configXData.xDataType
let xArr: any[] = []
// 获取近五年数据 // [2019, 2020, 2021, 2022, 2023]
if (xDataType == 'Y') {
// 获取近五年数据
const year = parseInt(dayjs().format('YYYY'))
for (let i = year; i > year - 5; i--) {
xArr.unshift(i)
}
}
// 获取今年 所有月份
if (xDataType == 'M') {
if (!allVal) {
console.log(dayjs().format('M'))
for (let i = 1; i <= parseInt(dayjs().format('M')); i++) {
xArr.push(i)
}
} else {
for (let i = 1; i <= 12; i++) {
xArr.push(i)
}
}
}
// 获取本月所有天
if (xDataType == 'D') {
if (!allVal) {
for (let i = 1; i <= parseInt(dayjs().format('D')); i++) {
xArr.push(i)
}
} else {
let dayLength = parseFloat(dayjs().endOf('month').format('DD'))
for (let i = 1; i <= dayLength; i++) {
xArr.push(i)
}
}
}
return xArr
}
</script>
<style scoped lang="scss">
:deep(.charts-bg) {
// padding: 23px 32px;
background-size: 100% 100%;
font-family: 'Source Han Sans CN';
position: absolute;
display: block;
.charts-value {
font-family: QuartzEF;
}
}
</style>
------------------------------------- tools.ts -----------------------------------------------
方法用于颜色转换
export const parseColorString = (color: string) => {
if (color.startsWith('#')) {
return parseHexColor(color)
} else if (color.startsWith('rgb')) {
return parseRgbaColor(color)
} else if (color === 'transparent') {
return parseHexColor('#00000000')
}
throw new Error(`color string error: ${color}`)
}
/**
* 16进制颜色字符串解析为颜色对象
* @param color 颜色字符串
* @returns IColorObj
*/
export const parseHexColor = (color: string) => {
let hex = color.slice(1)
let a = 1
if (hex.length === 3) {
hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`
}
if (hex.length === 8) {
a = parseInt(hex.slice(6), 16) / 255
hex = hex.slice(0, 6)
}
const bigint = parseInt(hex, 16)
return {
r: (bigint >> 16) & 255,
g: (bigint >> 8) & 255,
b: bigint & 255,
a
} as IColorObj
}
/**
* rgba颜色字符串解析为颜色对象
* @param color 颜色字符串
* @returns IColorObj
*/
export const parseRgbaColor = (color: string) => {
const arr = color.match(/(\d(\.\d+)?)+/g) || []
const res = arr.map((s: string) => parseInt(s, 10))
return {
r: res[0],
g: res[1],
b: res[2],
a: parseFloat(arr[3])
} as IColorObj
}
组件说明
组件名称 c-line-chart
依赖包 echarts、dayjs、lodash
传参
width?: 图表宽度、默认父盒子宽度
height?: 图表高度、默认父盒子高度
option: 图表配置项、与echarts官网配置相同,具体配置见 echarts官网
unit?: 图表Y轴单位
configXData: {
allXData?: boolean 是否展示x轴xDataType类型的所有值,true:展示所有 false:展示到当前日期
xDataType?: 'Y' | 'M' | 'D' Y:默认展示最近五年、M:展示月份、D:当前月的天
}
注意事项
-
option 默认提供颜色选项,如要修改图表中颜色,在 option 中添加属性 color 即可,动态修改可指定 option 为 reactive 类型, 使用 option.color= [“#ff0000”,“#2e375s”] 即可动态修改
颜色建议使用 AEX(“#FF0000”)类型const option =reactive({ color:[""] // 指定默认值,不指定删除即可,使用echarts默认颜色 }) option.color = ["#ff0000","#2e375s"] // 修改颜色
-
修改折线图渐变, 在开发中折线图图表渐变样式一般都统一,暂不做配置项修改,直接修改代码 option.series.areaStyle.colorStops 设置颜色透明度,达到满意即可
colorStops: [
{
offset: 0,
color: hexToRgba(color[0], 0.6)
},
{
offset: 1,
color: hexToRgba(color[0], 0.2)
}
]
- 图表数据改变时,图例依然保持上一个图表的数据,举个例子:数据一三条线三个图例,数据二两条线两个图例,由数据一的图表切换到数据二的图表时,option 中的 series 的第三条数据依然存在,这是因为传入组件的 series 只有前两条改变了数据,第三条没有变化。解决:切换到第二个图表时手动将整个 series 重置(可以先置空,然后对 name 和 data 赋值),对于 series 有很多自定义配置项时,可将其他非本图表的所有 series 的 name 和 data 手动置空
options.series=[]
options.series[0].data = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]
options.series[1].data = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
或者
options.series[2] = { name: '', data: [] }
本文只提供一种封装思路,有更好的方法或问题欢迎评论或私聊🙂