最近在使用 Echarts 完成一个漏斗图的需求,为了达到视觉的要求,过程中是用了一些 Hack 的方式,在这里总结一下。
效果如图:
需要解决4个问题:
- Label 过长展示省略号
- 中间绿色百分比的 Tag 需要动态固定在两个漏斗图之间的间隙中
- 漏斗图和坐标系相结合
- 漏斗图的数值大小应对坐标系 x 轴的长度,所以漏斗数值越大,横向需要越宽,二者是对应的
- 由于具有多个漏斗,每个漏斗的颜色不一样,按照顺序从上至下颜色变淡
- x 轴 Label 数值过大被挤在一起
首先是配置项,通过在线的示例配出,坐标轴和漏斗图
代码语言:javascript复制const globalOptions = {
xAxis: {
type: 'value',
splitLine: {
show: true,
lineStyle: {
type: 'dotted' // 控制虚线
},
color: '#D8D8D8',
},
splitNumber: 3, // 控制 x 轴 Label 过长挤在一起的情况,Echarts 会根据此值做适配,并非固定的
axisLine: {
show: true,
lineStyle: {
color: 'rgba(42, 51, 59, 0.1)'
}
},
axisLabel: {
color: 'rgba(42, 51, 59, .5)',
interval: 1
},
},
yAxis: [
{
splitLine: false,
axisLine: {
lineStyle: {
color: 'rgba(42, 51, 59, 0.1)'
}
},
axisLabel: {
show: false
},
axisTick: {
show: false
}
}
],
grid: { // 设置漏斗图图的位置
left: 140,
top: 50,
right: 50,
bottom: 20,
y: 10
},
// 默认一种颜色
color: ['rgba(63, 99, 245, 1)', 'rgba(63, 99, 245, 0.75)', 'rgba(63, 99, 245, 0.625)', 'rgba(63, 99, 245, 0.4)', 'rgba(63, 99, 245, 0.5)', 'rgba(63, 99, 245, 0.375)', 'rgba(63, 99, 245, 0.25)', 'rgba(63, 99, 245, 0.125)'],
series: [
{
name: '漏斗图',
type: 'funnel',
width: 'calc(100% - 100)',
left: 140,
top: 80,
bottom: '10%',
funnelAlign: 'left', // 漏斗图样式
gap: 1, // 漏斗间隙 1px
sort: 'none',
label: {
color: '#2A333B',
position: 'left',
verticalAlign: 'bottom',
formatter: [
'{a|{c}人}',
'{b|{b}}',
].join('n'),
rich: {
a: {
fontSize: 14,
align: 'right',
color: 'rgba(42, 51, 59, .85)',
lineHeight: 30,
},
b: {
align: 'right',
fontSize: 14,
color: 'rgba(42, 51, 59, .50)',
}
}
},
labelLine: { // 标签的视觉引导线样式
normal: {
show: false, // 是否显示引导线
}
},
data: [],
},
{
name: 'line',
type: 'line',
top: '5%',
symbolSize: 0, // symbol的大小设置为0
showSymbol: false, // 不显示symbol
lineStyle: {
width: 0, // 线宽是0
color: 'rgba(0, 0, 0, 0)' // 线的颜色是透明的
},
data: []
}
]
}
- 由于 Echarts 的配置项传入的值可以是百分比或者数值,并且直接对应 Css 的规则,所以,假设传入
left: 100
就代表left: 100px
,通过这个特征,我们就可以动态的计算出绿色标签的位置永远处于两个漏斗的中间。 - 漏斗图的每一块高度都是相同的
如何计算标签 top 的位置(这里采用 absolute 定位, 标签的 left 可以通过 css 计算)
代码语言:javascript复制const echartsPoint = [{
top: 0
}]
// 计算出每个漏斗块的高度
const each = domHeight / len;
// 标签的个数比漏斗的数据少一个
const len = echartsPoint.length;
echartsPoint.map((p, idx) => {
if (idx < len - 1) {
// 漏斗之间的间隔为 1px 故取 0.5 12 为每个 tag 的高度
p.top = `${(idx 1) * each (.5 * idx) - 12}px`
}
})
如何处理漏斗图 Label 过长的问题
上述的问题,除了 Tag 使用 DOM 去模拟外,还有漏斗图 Label 过长的问题,其余的都是可以通过配置项解决。
首先漏斗图的宽度是不能变的,所以左侧的 Label 只能采用超出使用…的方式
代码语言:javascript复制// 切割文字
formatter: function (params, index) {
// 超出省略
params = params.toString();
var maxlength= 8;
if (params.length>maxlength) {
return params.substring(0, maxlength-1) '...';
} else{
return params;
}
}
添加个 DOM,采用 absolute 定位,初始时隐藏,Echarts 实例可以监听 mousemove
事件,鼠标移入时展示完整的 Label,mouseout
时隐藏
chartInstance.on('mousemove', (params) => {
console.log(params);
if (params.componentSubType === 'funnel') {
this.$refs.labelTip[0].style.left = params.event.event.layerX 10 'px'
this.$refs.labelTip[0].style.top = params.event.event.layerY 20 'px'
this.$refs.labelTip[0].style.display = 'block'
this.$refs.labelTip[0].style.position = 'absolute'
this.$refs.labelTip[0].innerText= params.name
}
})
chartInstance.on('mouseout', (params) => {
this.$refs.labelTip[0].style.display = 'none'
})
最终效果