Echarts自定义图表基础教程(柱状斜切图)📊

4,165 阅读6分钟

「这是我参与2022首次更文挑战的第N天,活动详情查看:2022首次更文挑战」。

前言

杭州最近天气一直都不是很好,有是下雨又是下雪,刚开工设计那边就给了我一版数据可视化的设计稿让我做,我从中挑了一个比较值得记录的(好像也不太值得,因为并不难🐶🐶)就是下面这张

整体也并不难,重点是在画那根柱子上面,如何画这个柱子其实用Echarts中的自定义图表手动绘制路径就可以很简单的实现出来。

从图上可以看到我们要画一个蓝色的柱子和一块黄色的菱形,所以这里就需要分开画两个路径分别渲染出来

image.png

开始绘制🔛

首先我们要定义一个custom类型的图表,如下所示 接下来我们要关心的是renderItem这里要返回什么,还有paramsapi参数分别都有什么,因为内容有点多,这里不过解释具体可以看官方文档,这里我们要用到的是api.value()api.coord()两个方法

要知道上图中data的每一个数据项都会调用一次renderItem

  • api.value():得到给定维度的数据值,说白了就是获取当前数据项的下标和值

  • @return {number} 给定维度上的值。

    • api.value(0):获取数据项的下标 -- 第执行得到 0 (对应上图第一个data数据项)
    • api.value(1):获取数据项的值 -- 第执行得到 120(对应上图第一个data数据项)
  • api.coord():将数据值映射到坐标系上。也就是将上面所得到的数据当作数组传入其中

    • @param {Array.} data 数据值。

    • @return {Array.} 画布上的点的坐标,至少包含:[x, y] 对于polar坐标系,还会包含其他信息: polar: [x, y, radius, angle]

使用自定义图表 💚

renderItem: function (params, api) {
  //这里获取到的是柱状图顶部的坐标
  const topAxis = api.coord([api.value(0), api.value(1)]);
  //这里获取的是柱状图底部的坐标
  const bottomAxis = api.coord([api.value(0), 0]);
  return {
    type: 'InclinedRoofBar', //这里是自定义类型,
    shape: {  //这里是传递的参数
      topAxis,
      bottomAxis
    }
  };
}

注意:x轴和y轴的 [0, 0] 点在左上角 上面获取的到的 topAxisbottomAxis 属性分别是顶部点的x轴和y轴、底部点的x轴和y轴

根据上面获取到的两个坐标点,我们就能根据坐标点进行绘制图形,这里涉及到canvas绘制路径,所以不熟的可以先看一下这篇文章:🚪传送门:canvas教程✈️

还有下面编写绘制自定义图形的方法,下面会用到以下两个方法,参考🚪传送门:Echarts文档✈️

绘制蓝色柱子路径并注册使用 💙

const InclinedRoofBar = echarts.graphic.extendShape({
  //ctx : 当成canvas来绘制路径即可
  // shape:renderItem返回的shape参数中包含的数据
  buildPath: function (ctx, shape) {
    // topAxis,bottomAxis
    let topAxis = shape.topAxis;
    let bottomAxis = shape.bottomAxis;
    // 绘制的初始点
    const path0 = [topAxis[0] + 10, topAxis[1]];
    // 绘制的第一条线
    const path1 = [topAxis[0] - 10, topAxis[1] + 10];
    // 绘制第二条线
    const path2 = [bottomAxis[0] - 10, bottomAxis[1]];
    // 绘制第三条线
    const path3 = [bottomAxis[0] + 10, bottomAxis[1]];
    // 斜切柱子
    ctx
      .moveTo(path0[0], path0[1])
      .lineTo(path1[0], path1[1])
      .lineTo(path2[0], path2[1])
      .lineTo(path3[0], path3[1])
      //闭合路径
      .closePath();
  }
});
//绘制完成之后需要注册出来使用
echarts.graphic.registerShape('InclinedRoofBar', InclinedRoofBar);



option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [120, 200, 150, 80, 70, 110, 130],
      type: 'custom',
      renderItem: function (params, api) {
        const topAxis = api.coord([api.value(0), api.value(1)]);
        const bottomAxis = api.coord([api.value(0), 0]);
        return {
          type: 'InclinedRoofBar', //使用自定义注册类型!!!!!
          shape: {
            topAxis,
            bottomAxis
          },
          style:{ //给柱子添加颜色样式
             fill:'blue'
          }
        };
      }
    }
  ]
};

上面的代码中主要是graphic.extendShape()方法中传递的buildPath方法,该参数需要分析和绘制路径,方法接收两个参数

  • ctx : 当成canvas来绘制路径即可
  • shape:renderItem返回的shape参数中包含的数据

需要注意的是canvas中 x轴和y轴的起始点是左上角 [ 0 , 0 ] ,x轴+10会坐标会往右移,y轴+10坐标会往下移。这样我们会会得到以下图表

绘制黄色菱形路径并注册使用

上面我们已经画过了蓝色柱子了,接下来可以直接复制修改即可,因为黄色菱形的第一个点和第二个点与蓝色柱子是重合的,所以只需要修改第三第四个点即可

// 绘制第二条线
const path2 = [topAxis[0]- 10, topAxis[1] + 20];
// 绘制第三条线
const path3 = [topAxis[0] + 10,  topAxis[1] + 10];

将注册好的菱形路径替换掉原来的柱子查看效果

合并两个自定义类型 💛

使用 group类型组合两个自定义类型

group 是唯一的可以有子节点的容器。group 可以用来整体定位一组图形元素。

renderItem: function (params, api) {
  const topAxis = api.coord([api.value(0), api.value(1)]);
  const bottomAxis = api.coord([api.value(0), 0]);
  return {
    type: 'group', //使用自定义注册类型
    children: [
      {
        type: 'InclinedRoofBar', //柱子路径
        shape: {
          topAxis,
          bottomAxis
        },
        style: {
          //上色
          fill: 'blue'
        }
      },
      {
        type: 'InclinedRoofBar2', //菱形路径
        shape: {
          topAxis,
          bottomAxis
        },
        style: {
          //上色
          fill: '#fee082'
        }
      }
    ]
  };
}

最终代码(可粘贴到Echarts实例)🧡

const InclinedRoofBar = echarts.graphic.extendShape({
  //ctx : 当成canvas来绘制路径即可
  // shape:renderItem返回的shape参数中包含的数据
  buildPath: function (ctx, shape) {
    // topAxis,bottomAxis
    let topAxis = shape.topAxis;
    let bottomAxis = shape.bottomAxis;
    // 绘制的初始点
    const path0 = [topAxis[0] + 10, topAxis[1]];
    // 绘制的第一条线
    const path1 = [topAxis[0] - 10, topAxis[1] + 10];
    // 绘制第二条线
    const path2 = [bottomAxis[0] - 10, bottomAxis[1]];
    // 绘制第三条线
    const path3 = [bottomAxis[0] + 10, bottomAxis[1]];
    // 斜切柱子
    ctx
      .moveTo(path0[0], path0[1])
      .lineTo(path1[0], path1[1])
      .lineTo(path2[0], path2[1])
      .lineTo(path3[0], path3[1])
      //闭合路径
      .closePath();
  }
});
//绘制完成之后需要注册出来使用
echarts.graphic.registerShape('InclinedRoofBar', InclinedRoofBar);

// 黄色菱形
const InclinedRoofBar2 = echarts.graphic.extendShape({
  //ctx : 当成canvas来绘制路径即可
  // shape:renderItem返回的shape参数中包含的数据
  buildPath: function (ctx, shape) {
    // topAxis,bottomAxis
    let topAxis = shape.topAxis;
    let bottomAxis = shape.bottomAxis;
    // 绘制的初始点
    const path0 = [topAxis[0] + 10, topAxis[1]];
    // 绘制的第一条线
    const path1 = [topAxis[0] - 10, topAxis[1] + 10];
    // 绘制第二条线
    const path2 = [topAxis[0]- 10, topAxis[1] + 20];
    // 绘制第三条线
    const path3 = [topAxis[0] + 10,  topAxis[1] + 10];
    // 斜切柱子
    ctx
      .moveTo(path0[0], path0[1])
      .lineTo(path1[0], path1[1])
      .lineTo(path2[0], path2[1])
      .lineTo(path3[0], path3[1])
      //闭合路径
      .closePath();
  }
});
//绘制完成之后需要注册出来使用
echarts.graphic.registerShape('InclinedRoofBar2', InclinedRoofBar2);

option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [120, 200, 150, 80, 70, 110, 130],
      type: 'custom',
      renderItem: function (params, api) {
        const topAxis = api.coord([api.value(0), api.value(1)]);
        const bottomAxis = api.coord([api.value(0), 0]);
        return {
          type: 'group', //使用自定义注册类型
          children: [
            {
              type: 'InclinedRoofBar', //使用自定义注册类型
              shape: {
                topAxis,
                bottomAxis
              },
              style: {
                //上色
                fill: 'blue'
              }
            },
            {
              type: 'InclinedRoofBar2', //使用自定义注册类型
              shape: {
                topAxis,
                bottomAxis
              },
              style: {
                //上色
                fill: '#fee082'
              }
            }
          ]
        };
      }
    }
  ]
};

共勉 💯

文章写的不太好,如果有问题可以评论回复😅