关于Echarts横向柱状图的自定义加标记点

1,668 阅读4分钟

在最近某个怨种开发接到产品和UI给的新需求,实现如下横向柱状图Echarts:

产品需求

image.png

拿到设计稿后第一时间觉得应该不难,但是在实现的时候才发现,还是有一些小坑

实现效果

echarts官网示例编辑器实现效果如下:

image.png

源码

废话不多说,上源码!echarts版本:5.2.0 (可直接复制至echarts官网查看效果自行调试)

option = {
  title: {
    text: 'World Population'
  },
  // 提示框组件
  tooltip: {
    // position: this.tooltip,
    trigger: 'axis',
    axisPointer: {
      type: 'cross',
      label: {
        backgroundColor: '#6a7985'
      }
    }
  },

  // 直角坐标系内绘图网格
  grid: {
    left: '15',
    right: '15',
    bottom: '5',
    top: '25',
    containLabel: true
  },
  // X轴
  xAxis: {
    type: 'value',
    show: false,
    axisTick: {
      show: false
    },
    nameTextStyle: {
      fontSize: 10,
      color: '#1f1f1f',
      align: 'center'
    },

    axisLine: {
      show: false,
      lineStyle: {
        color: '#B3B3B3'
      }
    }
  },
  // Y轴
  yAxis: {
    type: 'category',
    // 轴线设置
    axisLine: {
      show: false,
      lineStyle: {
        // color: "#B3B3B3"
      }
    },
    // 坐标轴刻度相关设置
    axisTick: {
      show: false
    },
    // 坐标轴刻度标签的相关设置
    axisLabel: {
      show: true,
      padding: [0, 0, 48, 0],
      formatter(value, index) {
        return [`{number|No.${6 - index}} {value|${value}}`];
      },
      rich: {
        number: {
          fontSize: 20,
          fontWeight: 'bold',
          color: '#3595F3'
        },
        value: {
          fontSize: 19,
          color: '#333333'
        }
      },
      interval: 0,
      margin: 0,
      inside: true
    },
    data: ['Brazil', 'Indonesia', 'USA', 'India', 'China', 'World']
  },
  series: [
    {
      name: '数量',
      type: 'bar',
      itemStyle: {
        borderRadius: [0, 10, 10, 0] //圆角位置,左上、右上、右下、左下圆角
      },
      label: {
        show: true,
        distance: -2,
        position: 'top',
        formatter: (params) => {
          return [`{value|${params.data}} {unit|件}`];
        },
        rich: {
          value: {
            fontSize: 24,
            fontWeight: 'bold',
            color: '#333333'
          },
          unit: {
            fontSize: 18,
            color: '#333333'
          }
        }
      },
      // label的布局 ps:labelLayout是echarts5后才有的属性
      labelLayout(params) {
        // 此处的1100为你图表的宽度,想要动态布局可以使用
        // eechartsInstance.getWidth()方法,但要减去自己gird的左右距离
        // 图表的宽度减去label容器的宽度
        return {
          x: 750 - 15- params.labelRect.width ,
          y: params.rect.y - params.labelRect.height -10
        };
      },
      barWidth: 12,
      markPoint: {
        silent: true,
        // data=>coord分别代表axis.data  index和当前标记点的位置。
        // 此处y轴为类目轴,所以coord理解为 [x轴位置,yAxis.data的索引]
        data: [
          {
            coord: [18203, 0]
          },
          {
            coord: [23489, 1]
          },
          {
            coord: [29034, 2]
          },
          {
            coord: [104970, 3]
          },
          {
            coord: [131744, 4]
          },
          {
            coord: [630230, 5]
          }
        ],
        symbol:
          'image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAABAxJREFUSEvFV11oHFUU/s7M7Jq0mTTRXfGh4goVf+hDk51FpRESrNCHiPWhGPFJaF+6G21REMGQDfVFqESanSBU8EVppC9K8yBUSKUpVjKbCBYbaKUrBgR3NWlm262bmXvkbro6O9ndDBto5nHuPee73zn3fOdcQoAvlr7Z1h2J7leJD4Gxl4hjDESkKQEFZsqBcNVl+nq5kL+cSz9+dzO31GzDvvHlLi2svQ0gBWCRmaaJ+UfHcXLl8FpB2obLoYimaTEmepaIBwE8BSBzB6WPf0k+XGzkvyFwr2m/pjJOCaLv3PLa2E8nunObsZDr+8aXY2o4NKqAD7rA8fmk/lU9u7rAiYx9kglDrnBfXxjusoIA+vf0TKwYqqKeJcbUXEof8a/XAqdZM6LFs2BE+C4fzr7bWQlnq1/81GqE2ugcCAUrqR/2+qkBrjAF+qxCx0tIk9MqYI2dJBMpXiBg1sv8P2CZUwX4kEv8fCOmPZniixp4iMH9IDxSAWAsEWgWCr6YO6Z/X++wFebt9IMAPqjmvAIsb28opP3ssPtqvZwak6tPQtCnROhvFgVmXGQROpJ9q+3XejnXFPX8bZSekLe9AmyY9iiDYtlkx5t+A2Pizn6QM01EXUFCz8wrYG3QGt5x2b8/bhY/J3DOSupjJMUhEo387pSdhL9k1pniSlDQKpAEF8SJ+eSuG15wWWpaWJsr5AuPUuJ08QCrPGol9Rc2sM3YM5uFt1EUZNitlD6wwadpXyKXxsgw7QlmWsqmOj7ybuo5vXJAU9ULQcLbEFxgwBrWL3rX45nie0S8m4xJe4aZR7LJzlnvhkTGPgPCka0Ag/HZXEo/6vVhTNj9UDFKCbN4c628NrAhv6Z9nYA9WwFmxqKV0p/25zkUDs1QwrRL+Xyh299RDHPVJlDHloDBRSvZqXt9PGP+2bEDbX9sJ3CDUGfsa0SVFtfy1zTUhmlfYvD79/1yNSoneftIwUzLdKWMNyunbROQZpLZa97ao7AyR4RAOv2/ZGJFkGgumZs1ifgnq32k0fmg4MxYYYdfzh6vFSSJU9Mk5A9ZWzu5/ZqrKIfmj+3M+vN6j/mZzXRb6rMgcdTfHKS/3snbcZXFdE1blAs9mVtDKiknmw0ClQtHeENOKSDeXTkg05KcLpjxpV+XqwSqg4DLYmQhtWtK/t/+0ad6OsO0z933Ya8Kvj7e8pAgdahezoPUtsypwu4UMQUYbz0eZc41UsYF87cCofRCqv23IIA9mdJjCtbSCtFBh8WJak79tk2fMOudpP2dyhOGscigaUXhK47Qcv+Q/Zd09gDrD2mKExOCniPwINb1vfUnjPeEUmSiD0b7WOVXQNhLTDGGuPdoUwpMnAPjKrn0Tf7v/GyQR9u/zkhJdQf5PYwAAAAASUVORK5CYII=',
        symbolSize: 28,
        symbolOffset: [-2, 0],
        label: {
          show: true
        },
        symbolRotate: 0
      },

      showBackground: true,
      backgroundStyle: {
        color: '#E8F4FF'
      },
      color: {
        type: 'linear',
        x: 0,
        y: 0,
        x2: 1,
        y2: 0,
        colorStops: [
          {
            offset: 0,
            color: '#A8D4FF' // 0% 处的颜色
          },
          {
            offset: 1,
            color: '#3595F3' // 100% 处的颜色
          }
        ],
        global: false // 缺省为 false
      },
      barCategoryGap: '80%',
      data: [18203, 23489, 29034, 104970, 131744, 630230]
    }
  ]
};

难点归纳

其中的几个难点我罗列了一下:

  1. 各个标签的formatter函数配合rich富文本属性实现文字内容和样式的自定义;
  2. 柱状图labelLayout属性的使用,需要计算宽度,理解回调函数中各个参数的含义和容器的区分
  3. markPoint(标记点)的使用,也就是柱状图末尾加的小圆点,难点在于标记点的位置(data.coord)
  4. 如果你使用uniapp开发App并且使用了renderJs,那么注意所有的作为函数使用的formatter、labelLayou都建议写到视图层(render.js),因为其中作为函数使用的属性涉及到数据处理后视图的渲染,app中会不显示(猜测),这个我不知该怎么解释,如果有知道原理的大佬,可以留言解惑

写在最后

源码和实现效果都已给出,希望能给你带来一些启发,实现你想要的效果。

遇到一些奇怪的需求,不要急着吵架,静下心来仔细思考,或许是能够实现的。

俗话说得好,只要思想不滑坡,方法总比困难多加油!!