Echarts实现自定义每个系列数量不相等柱状图

483 阅读3分钟

前言

最近实现一个柱状图要求每个系列上的柱子数量不相等的需求,比如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": ""
    }
  ]
}

预览

image.png