需求:我们在开发过程中会遇到漏斗图的使用,如果用echarts里面自带的算法绘制渲染漏斗图时候,如果后端给的数据相差不大很接近时候,漏斗图渲染的结果不明显看不出来变化的。
优化之前的漏斗图:
优化之后的漏斗图:
首先我们要获取后端给的数据里面数量值。计算出最大的值max。然后计算每个value数量在最大值里面所占的比重大小。这样我们计算出来的漏斗比例就很均匀的分配出来了。
注意点:为了让漏斗自适应根据不同分辨率适配,我们这里使用了window.addEventListener(‘resize’, resize)进行控制,并且防止用户多次恶意操作,加了防抖的限制debounce
<template>
<div class="annualrecruit-box">
<div class="search-box">
<el-date-picker
v-model="state.annualrecruitform.year"
@change="getAnnualDoctorData"
placeholder="请选择年份"
:disabled-date="disabledDate"
type="year"
format="YYYY"
value-format="YYYY"
:clearable="false"
:editable="false"
>
</el-date-picker>
</div>
<div style="height:420px" ref="categoryChart"></div>
</div>
</template>
<script setup lang="ts" name="AnnualRecruitmentPatient">
import { GetYearRecruitTesteeConvertSummary } from '/@/api/dashboard/index'
import { reactive, onMounted, onBeforeUnmount, nextTick, ref } from 'vue';
import * as echarts from 'echarts';
import { debounce } from 'lodash-es';
const state = reactive({
annualrecruitform: {
year: ''
},
dataName: [],
dataList: [ ] as any
});
const categoryChart = ref()
var myChart = {} as any
const resize = debounce(() => myChart && myChart.resize(), 200)
onMounted (() => {
getCurrentTime()
window.addEventListener('resize', resize);
})
onBeforeUnmount(() => {
window.removeEventListener('resize', resize);
})
//禁用当前日期之后的日期
function disabledDate(time) {
return time.getTime() > Date.now() - 8.64e7;
}
//获取当前覆盖时间
function getCurrentTime() {
let currentTime = new Date(), year = currentTime.getFullYear()
state.annualrecruitform.year = year.toString()
getAnnualDoctorData()
}
function getAnnualDoctorData () {
GetYearRecruitTesteeConvertSummary({ year: Number(state.annualrecruitform.year)}).then((res:any) => {
if (res.data) {
let legendData = []
const datavallist = res.data.map((item) => {
return item.summaryVal
});
const max = Math.max(...datavallist)
if (res.data && res.data.length > 0) {
legendData = res.data.map((item) => {
return { name: item.summaryItemName, value: item.summaryVal * 100 / max, _value: item.summaryVal }
});
state.dataName = res.data.map((item) => {
return item.summaryItemName
});
}
state.dataList = legendData
nextTick(() => {
initEchartFunnel();
});
}
});
}
function initEchartFunnel () {
if (myChart != null && myChart != "" && myChart != undefined) {
echarts.dispose(categoryChart.value)
}
myChart = echarts.init(categoryChart.value);
const option = {
title: {
text: '',
subtext: ''
},
tooltip: {
trigger: 'item',
formatter(e){
return `${e.name} : ${e.data._value}`//将他动态设置 name就是名字 values是我给他新添加的真实数据
}
// formatter: "{a} <br/>{b} : {c}%"
},
toolbox: {
show: 1, x: 'right', y: 'bottom',
feature: {
// dataView: {readOnly: false},
// restore: {},
// saveAsImage: {}
}
},
legend: {
bottom: 5,//控制图例出现的距离 默认左上角
left: 'center',//控制图例的位置
data: state.dataName
},
color: [ '#316BF4', '#0CBAD3', '#7F66EB', '#F3C949', '#FA984E', '#F57373' ],
series: [
{
name:'漏斗图',
type:'funnel',
left: '5%',
top: 60,
bottom: 60,
width: '90%',
min: 0,
max: 100,
minSize: '0%',
maxSize: '100%',
gap: 2,
label: {
show: true,
position: 'inside',
formatter(e){
return `${e.name}${e.data._value}`
}
},
labelLine: {
length: 10,
lineStyle: {
width: 1,
type: 'solid'
}
},
itemStyle: {
borderColoer: '#fff',
borderWidth: 1
},
emphasis: {
label: {
fontSize: 20
}
},
data: state.dataList
}
]
};
myChart.setOption(option);
}
</script>
<style scoped lang="scss">
.annualrecruit-box {
.search-box {
text-align: right;
margin-bottom: 20px;
}
}
</style>