记录下工作中使用echarts做出的特殊组件

html
import { defineComponent } from 'vue'
import { FONT_SIZE } from './createChart'
const props = {
propData: {
type: Array,
default: () => [
['年份', '左侧(个)', '右侧(件)'],
[2044, 59.4, 55.1],
[2045, 54.2, 54.1],
[2046, 68.4, 63.2],
[2047, 64.7, 69.1],
[2048, 76.1, 74.3],
],
},
ValueMaxMin: {
type: Array,
default: () => [
[0, 100],
[0, 100],
],
},
barWidth: {
type: Number,
default: 50,
},
barLabelDistance: {
type: Number,
default: 50,
},
YAxisNameRate: {
type: Number,
default: 20,
},
YAxisNamePosition: {
type: Number,
default: 50,
},
leftTriangleColorArray: {
type: Array,
default: () => ['rgba(26, 132, 211, 0.1)', 'rgba(15, 221, 138, 1)'],
},
barColorArray: {
type: Array,
default: () => ['rgba(15, 221, 138, 1)', 'rgba(251, 190, 0, 1)'],
},
rightDiamondColorArray: {
type: Array,
default: () => ['rgba(211, 140, 26, 0)', 'rgba(251, 190, 0, 1)'],
},
}
function getModifyAlpha(color, alpha) {
return echarts.color.modifyAlpha(color, alpha)
}
export default defineComponent({
props,
data() {
return {}
},
created() {},
mounted() {
this.init()
this.$watch(
() => this.$props, // 监听整个 props 对象
() => {
this.init()
},
{ deep: true, immediate: false },
)
},
beforeDestroy() {
this.chart?.dispose?.()
},
methods: {
init() {
const label = {
show: true,
fontSize: FONT_SIZE,
color: '#fff',
}
const axisLine = {
show: true,
lineStyle: {
color: 'rgba(211, 211, 211, 0.6)', // 轴线颜色
width: 3, // 轴线宽度
type: 'solid', // 线型:solid(实线)、dashed(虚线)、dotted(点线)
},
}
const grid共同样式 = {
show: false,
top: '5%',
bottom: '10%',
}
const props = this._props
const barWidth = props.barWidth
const legendColor = props.barColorArray
const 系列名称names = props.propData[0].slice(1)
const Y轴名称names = props.propData.slice(1).map((item) => item[0])
const data1 = props.propData.slice(1).map((item) => item[1])
const data2 = props.propData.slice(1).map((item) => item[2])
const maxValue1 = Math.max(...data1)
const maxValue2 = Math.max(...data2)
const xAxisMax = Math.ceil(Math.max(maxValue1, maxValue2) / 100) * 100
const 中间y轴名称占比Proportion = props.YAxisNameRate
const 中间y轴名称离左距离 = props.YAxisNamePosition
const 左右柱子占比Proportion = (100 - 中间y轴名称占比Proportion) / 2 - 3
const 左右柱子标签偏移量offset = props.barLabelDistance
const 左侧三角形的渐变色 = props.leftTriangleColorArray.length
? props.leftTriangleColorArray
: [getModifyAlpha(legendColor[0], 0.8), getModifyAlpha(legendColor[0], 1)]
const 右侧菱形的渐变色 = props.rightDiamondColorArray.length
? props.rightDiamondColorArray
: [getModifyAlpha(legendColor[1], 0.8), getModifyAlpha(legendColor[1], 1)]
const 左侧series通用配置 = {
data: data1,
xAxisIndex: 0,
yAxisIndex: 0,
gridIndex: 0,
name: 系列名称names[0],
}
const 右侧series通用配置 = {
data: data2,
xAxisIndex: 2,
yAxisIndex: 2,
gridIndex: 2,
name: 系列名称names[1],
}
const series装饰用途通用配置 = {
tooltip: { show: false },
label: { show: false },
symbolPosition: 'end',
}
const 通用模糊效果 = {
shadowBlur: 10, // 发光模糊度
shadowOffsetX: 2,
shadowOffsetY: 4,
shadowColor: 'rgba(255, 255, 255, 0.5)',
}
const option = {
color: legendColor,
legend: {
show: true,
data: 系列名称names,
lineStyle: {
width: 10,
},
top: '0%',
left: '38%',
textStyle: {
...label,
padding: [0, 0, 0, 30],
},
itemHeight: 30,
itemWidth: 30,
itemGap: 50,
},
tooltip: {
show: Y轴名称names.length ? true : false,
trigger: 'axis',
axisPointer: {
type: 'none',
},
textStyle: {
...label,
},
appendToBody: true,
backgroundColor: '#0C3E5F',
borderColor: '#0CB6FF',
borderWidth: 4,
formatter: (params) => {
let result = ''
params.forEach((param) => {
const value = param.value || 0
const seriesName = param.seriesName
// 提取出括号中的单位
const match = param.seriesName.match(/\((.*?)\)/)
const unit = match ? match[1] : ''
// 提取出颜色
let color = param.color.colorStops[0]?.color || '#ffffff'
color = getModifyAlpha(color, 1)
const marker = `<span style="${this.getSerieSymbolStyle(color)}"></span>`
result += `${marker} ${seriesName} :${value} ${unit}<br/>`
})
return result
},
},
grid: [
{
...grid共同样式,
left: '8%',
width: `${左右柱子占比Proportion}%`,
},
{
...grid共同样式,
left: `${中间y轴名称离左距离}%`,
width: `${中间y轴名称占比Proportion}%`,
},
{
...grid共同样式,
right: '8%',
width: `${左右柱子占比Proportion}%`,
},
],
xAxis: [
{
gridIndex: 0,
type: 'value',
inverse: true,
max: this.ValueMaxMin[0][1],
min: this.ValueMaxMin[0][0],
// 轴线
axisLine: {
...axisLine,
},
axisTick: {
show: false,
},
position: 'bottom',
axisLabel: {
...label,
textStyle: {
color: '#fff',
},
},
splitLine: {
show: false,
},
},
{
gridIndex: 1,
show: false,
},
{
gridIndex: 2,
type: 'value',
inverse: false,
max: this.ValueMaxMin[1][1],
min: this.ValueMaxMin[1][0],
axisLine: {
...axisLine,
},
axisTick: {
show: false,
},
position: 'bottom',
axisLabel: {
...label,
textStyle: {
color: '#fff',
},
},
splitLine: {
show: false,
},
},
],
yAxis: [
{
gridIndex: 0,
show: true,
type: 'category',
inverse: true,
data: Y轴名称names,
position: 'right',
// 轴线
axisLine: {
...axisLine,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
},
{
gridIndex: 1,
show: true,
type: 'category',
inverse: true,
position: 'center',
data: Y轴名称names,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
...label,
align: 'center', // 或 'center'
verticalAlign: 'middle',
textStyle: {
color: '#fff',
padding: [0, 0, 0, 0],
},
formatter: (params) => {
// 这里可以自定义y轴标签样式
return params
},
},
splitLine: {
show: false,
},
},
{
gridIndex: 2,
show: true,
type: 'category',
inverse: true,
data: Y轴名称names,
// 轴线
axisLine: {
...axisLine,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
},
],
series: [
// 左侧外三角形
{
...左侧series通用配置,
...series装饰用途通用配置,
type: 'pictorialBar',
symbol: 'triangle',
symbolSize: [barWidth, barWidth * 0.7],
symbolRotate: -90,
symbolOffset: [-25, 0],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: 左侧三角形的渐变色[0],
},
{
offset: 1,
color: 左侧三角形的渐变色[1],
},
],
},
...通用模糊效果,
shadowColor: 左侧三角形的渐变色[0],
},
},
// 左侧内三角形
{
...左侧series通用配置,
...series装饰用途通用配置,
type: 'pictorialBar',
symbol: 'triangle',
symbolSize: [barWidth - 10, barWidth * 0.7 - 10],
symbolRotate: -90,
symbolOffset: [-11, 0],
itemStyle: {
color: 'transparent',
borderColor: {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: getModifyAlpha(legendColor[0], 0.1),
},
{
offset: 0.8,
color: 'rgba(255, 255, 255, 0.5)',
},
{
offset: 1,
color: 'rgba(255, 255, 255, 1)',
},
],
},
...通用模糊效果,
borderWidth: 30, // 边框宽度
borderType: 'solid',
},
},
// 左侧实际柱形
{
...左侧series通用配置,
type: 'bar',
barWidth,
label: {
...label,
offset: [-左右柱子标签偏移量offset, 0],
position: 'left',
},
itemStyle: {
color: (params) => {
return new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{
offset: 0,
color: getModifyAlpha(legendColor[0], 0.9),
},
{
offset: 1,
color: getModifyAlpha(legendColor[0], 1),
},
])
},
borderColor: getModifyAlpha(legendColor[0], 0.1),
...通用模糊效果,
},
},
// 右侧前景条
{
...右侧series通用配置,
...series装饰用途通用配置,
type: 'pictorialBar',
symbol: 'diamond',
symbolSize: [barWidth, barWidth * 0.7],
symbolRotate: 90,
symbolOffset: [35, 0],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: 右侧菱形的渐变色[0],
},
{
offset: 1,
color: 右侧菱形的渐变色[1],
},
],
},
},
},
{
...右侧series通用配置,
...series装饰用途通用配置,
type: 'pictorialBar',
symbol: 'diamond',
symbolSize: [barWidth - 6, barWidth * 0.7 - 6],
symbolRotate: 90,
symbolOffset: [60, 0],
itemStyle: {
color: 'transparent',
borderColor: {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: getModifyAlpha(legendColor[1], 0.1),
},
{
offset: 0.8,
color: 'rgba(255, 255, 255, 0.5)',
},
{
offset: 1,
color: 'rgba(255, 255, 255, 1)',
},
],
},
...通用模糊效果,
borderWidth: 30, // 边框宽度
borderType: 'solid',
},
},
// 右侧实际柱形
{
...右侧series通用配置,
type: 'bar',
barWidth,
label: {
...label,
offset: [左右柱子标签偏移量offset, 0],
position: 'right',
},
itemStyle: {
color: (params) => {
return new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{
offset: 1,
color: getModifyAlpha(legendColor[1], 0.9),
},
{
offset: 0,
color: getModifyAlpha(legendColor[1], 1),
},
])
},
borderColor: getModifyAlpha(legendColor[1], 0.1),
...通用模糊效果,
},
},
],
}
this.draw(option)
},
draw(option) {
const dom = this.$refs.chart
if (!this.chart) {
this.chart = echarts.init(dom, null, {
renderer: 'canvas',
})
}
this.chart.setOption(option, true)
},
getSerieSymbolStyle(color) {
const style = {
display: 'inline-block',
width: '30px',
height: '30px',
'border-radius': '3px',
'margin-right': '12px',
'vertical-align': 'middle',
background: color || '#fff',
}
return Object.entries(style)
.map(([key, value]) => `${key}:${value}`)
.join(';')
},
},
})