let data = [ { value: 0.5, name: 'Visit' }, { value: 0.6, name: 'Visit1' }, { value: 0.8, name: 'Visit2' }, { value: 1, name: 'Visit3' }, { value: 1.2, name: 'Visit4' }, ] // 设置颜色-因为用到事件动态setoption了自带颜色不保熟 let colors = [ { type: 'linear', x: 0, y: 0, x2: 1, y2: 1, colorStops: [{ offset: 0, color: '#ffa39e' // 0% 处的颜色 }, { offset: 1, color: '#f5222d' // 100% 处的颜色 }], global: false // 缺省为 false }, { type: 'linear', x: 0, y: 0, x2: 1, y2: 1, colorStops: [{ offset: 0, color: '#91d5ff' // 0% 处的颜色 }, { offset: 1, color: '#1890ff' // 100% 处的颜色 }], global: false // 缺省为 false }, { type: 'linear', x: 0, y: 0, x2: 1, y2: 1, colorStops: [{ offset: 0, color: '#ffd591' // 0% 处的颜色 }, { offset: 1, color: '#fa8c16' // 100% 处的颜色 }], global: false // 缺省为 false }, { type: 'linear', x: 0, y: 0, x2: 1, y2: 1, colorStops: [{ offset: 0, color: '#87e8de' // 0% 处的颜色 }, { offset: 1, color: '#13c2c2' // 100% 处的颜色 }], global: false // 缺省为 false }, { type: 'linear', x: 0, y: 0, x2: 1, y2: 1, colorStops: [{ offset: 0, color: '#0128b460' // 0% 处的颜色 }, { offset: 1, color: '#0128b4' // 100% 处的颜色 }], global: false // 缺省为 false } ] data.map((v, k) => { v['itemStyle'] = { color: colors[k] } }) let legendData = data.map((v) => v.name); // 是否平均分配宽度 let isAverageWidth_ = false; // 最大 100(表示为百分比) 可以在37行吧 '%' 去掉设置数值 let maxBarHeight = 30; /** * 函数描述 * @param {array} fnData 数据 * @param {boolean} isAverageWidth 是否固定宽度(固定的宽度根据100/fnData长度) * @param {number=} maxBarHeight 柱子的最大高度 * @return {array} 处理后的series */ const computedData = (fnData, isAverageWidth, maxBarHeight) => { let newData = []; let count = fnData.map((v) => v.value).reduce((a, b) => { return a + b; }, 0); let averageWidth = 100 / fnData.length; fnData.forEach((item, index) => { let proportion = item.value / count; let size = maxBarHeight * proportion + '%'; let barWidth = averageWidth + '%'; let leftOffset = 0; // 这里会有图例未选中状态的bug 事件部分有解释 // 这里就可以根据item.itemStyle.opacity == 0 判断隐藏的 // 如果隐藏的就不参与 width的运算和offset的运算 if (isAverageWidth) { barWidth = averageWidth + '%'; leftOffset = averageWidth * index + '%'; } else { let barWidthNum = 100 * proportion barWidth = barWidthNum + '%' for (let i = 0; i < index; i++) { let proportion_ = fnData[i].value / count; leftOffset += 100 * proportion_ } leftOffset += '%'; } let seriesItem = { name: item.name, type: 'funnel', orient: 'horizontal', width: barWidth, left: leftOffset, minSize: size, maxSize: size, top: "-20%", //上下位置 sort: 'descending', gap: 2, label: { show: true, position: 'inside', shadowBlur:0, color:"#fff", fontSize:14, backgroundColor:'rgba(255,255,255,0)' }, emphasis:{ label:{ fontSize:14 } }, labelLine: { length: 10, lineStyle: { width: 1, type: 'solid' } }, itemStyle: { borderColor: '#fff', borderWidth: 0, opacity: item.value == 0 ? 0 : 1 }, emphasis: { label: { fontSize: 14 } }, data: [ item ] } newData.push(seriesItem) }) return newData; } let resData = computedData(data, isAverageWidth_, maxBarHeight); // 可以查看series 的格式自行修改这里方便设置图例所加 console.log(resData); option = { tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c}' }, legend: { data: legendData, top: "10%" }, grid: { containLabel: true, left: 0, bottom: 0, right: 0, top: 0 }, color:colors, //把需要设置的颜色帮到全局 这里用于设置图例颜色 series: resData }; myChart.on('legendselectchanged', function (lparam) { let selects = lparam.selected; let newDataFilter = []; data.filter((item) => { if (selects[item.name]) { newDataFilter.push(item); } else { // 这里会存在一个问题 value为0的时候图例 未选中状态的icon无法显示只显示text; // 可以通过在computedData 方法内和clone的独特属性判断 设置width为0 offsetLeft同样需要判断处理 // 例如设置 itemStyle.opacity = 0; // 这里没加提供思路 let clone = { ...item, value: 0.00000000000000000000000000000000000000000000000001 //解决问题可以采用这个但是感觉有问题 // itemStyle: { // opacity: 0 // } } newDataFilter.push(clone) } }) let resData = computedData(newDataFilter, isAverageWidth_, maxBarHeight); myChart.setOption({ series: resData }) })