前言
最近实现一个柱状图要求每个系列上的柱子数量不相等的需求,比如x1系列有五条数据,x2系列有2条数据,但Echarts对于数据要求是 每个系列 数据量相等, 查阅文档和示例后没看到有现成的解决方案后,通过搜索大法使用自定义渲染函数的方案实现了这个效果并记录
自定义渲染函数
function renderItem(params, api) {
let categoryIndex = api.value(0);
let start = api.coord([categoryIndex, api.value(1)]);
let end = api.coord([categoryIndex, api.value(2)]);
let width = api.size([0, api.value(2)])[0] * 0.8;
const num = api.value(4); // 每个系列柱子数
const currentIndex = api.value(3);
const isOdd = num % 2 === 0;
const midN = isOdd ? num / 2 : (num + 1) / 2;
var rect = "";
width = width / num;
let rectX = start[0] - width / 2;
const FIXED_WIDTH = 5; // 柱子间距
// 数据处理,结构为 { itemStyle: { normal: { color: 'lightgreen' } }, name: '2011', value: [0, 0, 150, 2, 5] }
// 其中value 分为五个维度,分别为{系列项}(从0开始)、y轴起始值(均为0)、实际值、同系列中索引值(从1开始)、同系列数据项总数
if (num === 1) {
width = width / 2;
rectX = start[0] - width / 2 + (currentIndex - midN) * width;
}
if (num > 1) {
if (isOdd) {
if (currentIndex <= midN) {
// 中位数左侧
rectX =
start[0] -
width / 2 -
width / 2 +
(currentIndex - midN) * width -
FIXED_WIDTH * (midN + 1 - currentIndex);
} else {
// 中位数右侧
rectX =
start[0] -
width / 2 +
width / 2 +
(currentIndex - midN - 1) * width +
FIXED_WIDTH * (currentIndex - midN);
}
} else {
rectX =
start[0] -
width / 2 +
(currentIndex - midN) * (width + FIXED_WIDTH);
}
}
rect = {
type: "rect",
shape: echarts.graphic.clipRectByRect(
{ x: rectX, y: end[1], width: width, height: start[1] - end[1] },
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height,
}
),
style: api.style(),
};
return rect;
}
数据处理
this.shiyuanXData = [];
this.shiyuanData = [];
let index = 0;
for (let key in tmpData) {
//X轴名字
let skip = false;
tmpData[key].forEach((item) => {
const tmpVal = item.value[2];
if (tmpVal) skip = true;
});
//如果一个系列下所有数据的值都为0 则过滤掉
if (!skip) continue;
this.shiyuanXData.push(key);
//颜色过滤 根据大小 显示绿色或者红色
tmpData[key].forEach((item) => {
item.value[0] = index;
const tmpVal = item.value[2];
const color =
tmpVal >= this.Max
? "#11A45B"
: tmpVal >= this.Min
? "#BFBF00"
: "#BF0000";
item.itemStyle = { normal: { color } };
});
index++;
this.shiyuanData = this.shiyuanData.concat(tmpData[key]);
}
//渲染Echarts
this.$nextTick(function () {
this.drawBar("main");
});
渲染Echarts
//drawBar函数
this.chart = echarts.init(document.getElementById(id));
this.chart.setOption({
color: ["#3398DB"],
//自定义指示器的内容显示
tooltip: {
trigger: "axis",
formatter: (params) => {
let str = `<div>${params[0].axisValueLabel}</div>`;
params.forEach((item) => {
str += `${item.marker}${item.name}:${item.value[2]}</br>`;
});
return str;
},
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
grid: {
left: "3%",
right: "4%",
bottom: "2%",
containLabel: true,
},
xAxis: {
type: "category",
data: this.shiyuanXData,
axisLine: {
lineStyle: {
color: "rgb(255,255,255)",
fontSize: "40", // 这里是为了突出显示加上的
},
},
axisLabel: {
inside: 0,
rotate: 45,
textStyle: {
color: "rgb(255,255,255)",
fontSize: 12,
},
},
},
yAxis: {
splitLine: {
show: false,
},
type: "value",
axisLine: {
lineStyle: {
color: "rgb(255,255,255)",
fontSize: "12", // 这里是为了突出显示加上的
},
},
},
series: [
{
type: "custom",
renderItem: renderItem,
itemStyle: {
normal: {
label: {
show: true,
position: "top",
textStyle: {
color: "rgb(255,255,255)",
fontSize: "20",
},
},
opacity: 0.8,
},
},
encode: { y: [1, 2], x: 0 },
data: this.shiyuanData,
},
],
});
//Echarts4 点击事件处理,防止事件多次注册,先Off一次
this.chart.off("click");
//点击跳转数据中的URL 根据实际需要变动
this.chart.on("click", (params) => {
window.open(params.data.url);
});
数据结构
{
"CVT-01": [
{
"name": "CVT-01-MI线",
"value": [
0,
0,
93,
1,
4
],
"url": ""
},
{
"name": "CVT-01-包装线",
"value": [
0,
0,
50,
2,
4
],
"url": ""
},
{
"name": "CVT-01-包装线",
"value": [
0,
0,
60,
3,
4
],
"url": ""
},
{
"name": "CVT-01-包装线",
"value": [
0,
0,
20,
4,
4
],
"url": ""
}
],
"CVT-02": [
{
"name": "CVT-02-MI线",
"value": [
1,
0,
101,
1,
2
],
"url": ""
},
{
"name": "CVT-02-包装线",
"value": [
1,
0,
93,
2,
2
],
"url": ""
}
],
"CVT-03": [
{
"name": "CVT-03-MI线",
"value": [
2,
0,
98,
1,
2
],
"url": ""
},
{
"name": "CVT-03-包装线",
"value": [
2,
0,
102,
2,
2
],
"url": ""
}
],
"CVT-04": [
{
"name": "CVT-04-MI线",
"value": [
3,
0,
77,
1,
2
],
"url": ""
},
{
"name": "CVT-04-包装线",
"value": [
3,
0,
0,
2,
2
],
"url": ""
}
],
"CVT-05": [
{
"name": "CVT-05-MI线",
"value": [
4,
0,
0,
1,
2
],
"url": ""
},
{
"name": "CVT-05-包装线",
"value": [
4,
0,
70,
2,
2
],
"url": ""
}
]
}