Echarts 画3D立体柱状图

  • 在一个vue项目中使用到, 这边写个笔记记录下
  • 3d立体柱状图(单个柱子)


    单个柱子
// 立体柱状图
function threeDimensionalLine() {
  let divId = document.getElementById('元素id');
  let myChart = echarts.init(divId);
  // x y 用来设置柱状的大小
  const offsetX = 12;
  const offsetY = 6;
  // 绘制左侧面
  const CubeLeft = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      // 会canvas的应该都能看得懂,shape是从custom传入的
      const xAxisPoint = shape.xAxisPoint;
      // console.log(shape);
      const c0 = [shape.x, shape.y];
      const c1 = [shape.x - offsetX, shape.y - offsetY];
      const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY];
      const c3 = [xAxisPoint[0], xAxisPoint[1]];
      ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath();
    }
  });
  // 绘制右侧面
  const CubeRight = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const xAxisPoint = shape.xAxisPoint;
      const c1 = [shape.x, shape.y];
      const c2 = [xAxisPoint[0], xAxisPoint[1]];
      const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY];
      const c4 = [shape.x + offsetX, shape.y - offsetY];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 绘制顶面
  const CubeTop = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const c1 = [shape.x, shape.y];
      const c2 = [shape.x + offsetX, shape.y - offsetY]; // 右点
      const c3 = [shape.x, shape.y - offsetX];
      const c4 = [shape.x - offsetX, shape.y - offsetY];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 注册三个面图形
  echarts.graphic.registerShape('CubeLeft', CubeLeft);
  echarts.graphic.registerShape('CubeRight', CubeRight);
  echarts.graphic.registerShape('CubeTop', CubeTop);

  const VALUE = [100, 200, 300, 400, 300, 200, 100];
  let option = {
    tooltip: {
      show: false,
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      },
      formatter: function (params, ticket, callback) {
        const item = params[1];
        return item.name + ' : ' + item.value;
      }
    },
    grid: {
      top: '12%',
      left: '3%',
      right: '5%',
      bottom: '10%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      data: ['测试名字1', '测试名字2', '测试名字3', '测试名字4', '测试名字5', '测试名字6', '测试名字7'],
      axisLine: {
        show: true,
        lineStyle: {
          width: 1,
          color: '#344761'
        }
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        color: '#fff',
        rotate: 40,
        formatter: function (value) { // 自定义文字超出部分 ...
          if (value.length > 5) {
            return `${value.slice(0, 5)}...`;
          }
          return value;
        }
      }
    },
    yAxis: {
      type: 'value',
      name: '签约完成率%',
      nameTextStyle: {
        color: '#fff'
      },
      axisLine: {
        show: true,
        lineStyle: {
          width: 1,
          color: '#344761'
        }
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: '#172749'
        }
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        color: '#fff'
      }
    },
    series: [
      {
        type: 'custom',
        renderItem: (params, api) => {
          const location = api.coord([api.value(0), api.value(1)]);
          return {
            type: 'group',
            children: [
              {
                type: 'CubeLeft',
                barWidth: 20,
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                      offset: 0,
                      color: '#01f0ff'
                    },
                    {
                      offset: 1,
                      color: '#005559'
                    }
                  ])
                }
              },
              {
                type: 'CubeRight',
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                      offset: 0,
                      color: '#01f0ff'
                    },
                    {
                      offset: 1,
                      color: '#005559'
                    }
                  ])
                }
              },
              {
                type: 'CubeTop',
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                      offset: 0,
                      color: '#01f0ff'
                    },
                    {
                      offset: 1,
                      color: '#005559'
                    }
                  ])
                }
              }
            ]
          };
        },
        data: VALUE
      },
      {
        type: 'bar',
        label: {
          normal: {
            show: true,
            position: 'top',
            fontSize: 16,
            color: '#fff',
            offset: [0, -5]
          }
        },
        itemStyle: {
          color: 'transparent'
        },
        tooltip: {},
        data: VALUE
      }
    ]
  };
  myChart.setOption(option);
  window.addEventListener('resize', function () {
    myChart.resize();
  });
};
  • 3d立体柱状图(多个柱子, 且自定义柱状图的弹出框 tooltip )


    多个柱子
// 多项立体柱状图
function threeDimensionalMoreBar() {
  let divId = document.getElementById('元素id');
  let myChart = echarts.init(divId);
  // 绘制左侧面
  const wid = 14;
  const w1 = Math.sin(Math.PI / 6) * wid; // 4
  const w2 = Math.sin(Math.PI / 3) * wid; // 6.8
  const snapHeight = wid / 4;
  const CubeLeft = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      // 会canvas的应该都能看得懂,shape是从custom传入的
      const xAxisPoint = shape.xAxisPoint;
      const c0 = [shape.x, shape.y - 2];
      const c1 = [shape.x - w2, shape.y - w1 + snapHeight - 2];
      const c2 = [shape.x - w2, xAxisPoint[1] - w1 + snapHeight - 2];
      const c3 = [shape.x, xAxisPoint[1] - 2];
      ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath();
    }
  });
  // 绘制右侧面
  const CubeRight = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const xAxisPoint = shape.xAxisPoint;
      const c1 = [shape.x, shape.y - 2];
      const c2 = [shape.x, xAxisPoint[1] - 2];
      const c3 = [shape.x + w1, xAxisPoint[1] - w2 + snapHeight - 2];
      const c4 = [shape.x + w1, shape.y - w2 + snapHeight - 2];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 绘制顶面
  const CubeTop = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const c1 = [shape.x, shape.y - 2];
      const c2 = [shape.x + w1, shape.y - w2 + snapHeight - 2]; // 右点
      const c3 = [shape.x - w2 + w1, shape.y - w1 - w2 + snapHeight * 2 - 2];
      const c4 = [shape.x - w2, shape.y - w1 + snapHeight - 2];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 注册三个面图形
  echarts.graphic.registerShape('CubeLeft', CubeLeft);
  echarts.graphic.registerShape('CubeRight', CubeRight);
  echarts.graphic.registerShape('CubeTop', CubeTop);

  const VALUE = [{value: 100, rate: 20}, {value: 70, rate: 70}, {value: 200, rate: 90}, {value: 200, rate: 90}];
  const VALUE2 = [{value: 30, rate: 40}, {value: 60, rate: 30}, {value: 100, rate: 80}, {value: 200, rate: 90}];
  const VALUE3 = [{value: 300, rate: 60}, {value: 100, rate: 60}, {value: 150, rate: 70}, {value: 200, rate: 90}];
  let option = {
    legend: {
      data: ['签约率', '腾空率', '拆除率'],
      selectedMode: false,
      right: '5%',
      top: '2%',
      textStyle: {
        color: '#fff'
      }
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      },
      formatter: function (data) {
        console.log(data);
        let total = data.reduce(function (total, currentValue, currentIndex, arr) {
          return total + currentValue.value;
        }, 0);
        let str = `

总户数:${total}

`; data.reverse().forEach(item => { str += `

${item.marker}签约率:${item.data.rate}% ${item.seriesName}:${item.value}

`; }); return str; } }, grid: { top: '15%', left: '3%', right: '5%', bottom: '10%', containLabel: true }, xAxis: { type: 'category', data: ['测试名字1', '测试名字2', '测试名字3', '测试名字4'], axisLine: { show: true, lineStyle: { width: 1, color: '#344761' } }, axisTick: { show: false }, axisLabel: { color: '#fff', formatter: function (value) { // 自定义文字超出部分 ... if (value.length > 13) { return `${value.slice(0, 12)}...`; } return value; } } }, yAxis: { type: 'value', name: '签约完成率%', nameTextStyle: { color: '#fff' }, axisLine: { show: true, lineStyle: { width: 1, color: '#344761' } }, splitLine: { show: true, lineStyle: { color: '#172749' } }, axisTick: { show: false }, axisLabel: { color: '#fff' } }, series: [{ name: '签约率', type: 'custom', renderItem: (params, api) => { const location = api.coord([api.value(0), api.value(1)]); location[0] = location[0] + wid * (-2); const xlocation = api.coord([api.value(0), 0]); xlocation[0] = xlocation[0] + wid * (-2); return { type: 'group', children: [{ type: 'CubeLeft', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#22c6fc' }, { offset: 1, color: '#052e44' } ]) } }, { type: 'CubeRight', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#22c6fc' }, { offset: 1, color: '#052e44' }]) } }, { type: 'CubeTop', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#22c6fc' }, { offset: 1, color: '#052e44' }]) } }] }; }, color: '#22c6fc', data: VALUE }, { name: '腾空率', type: 'custom', renderItem: (params, api) => { const location = api.coord([api.value(0), api.value(1)]); location[0] = location[0] + wid * 0; const xlocation = api.coord([api.value(0), 0]); xlocation[0] = xlocation[0] + wid * 0; return { type: 'group', children: [{ type: 'CubeLeft', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#fdc81e' }, { offset: 1, color: '#464704' }]) } }, { type: 'CubeRight', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#fdc81e' }, { offset: 1, color: '#464704' }]) } }, { type: 'CubeTop', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#fdc81e' }, { offset: 1, color: '#464704' }]) } }] }; }, color: '#fdc81e', data: VALUE2 }, { name: '拆除率', type: 'custom', renderItem: (params, api) => { const location = api.coord([api.value(0), api.value(1)]); location[0] = location[0] + wid * 2; const xlocation = api.coord([api.value(0), 0]); xlocation[0] = xlocation[0] + wid * 2; return { type: 'group', children: [{ type: 'CubeLeft', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#27e6ab' }, { offset: 1, color: '#03302f' }]) } }, { type: 'CubeRight', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#27e6ab' }, { offset: 1, color: '#03302f' }]) } }, { type: 'CubeTop', shape: { api, xValue: api.value(0), yValue: api.value(1), x: location[0], y: location[1], xAxisPoint: xlocation }, style: { fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#27e6ab' }, { offset: 1, color: '#03302f' }]) } }] }; }, color: '#27e6ab', data: VALUE3 }] }; myChart.setOption(option); window.addEventListener('resize', function () { myChart.resize(); }); }
  • 3d立体柱状图自定义每根柱子的颜色


    自定义每根柱子的颜色
function threeDimensionaBarCustomColor(divId) {
  let divId = document.getElementById('元素id');
  let myChart = echarts.init(divId);
  // x y 用来设置柱状的大小
  const offsetX = 12;
  const offsetY = 6;
  // 绘制左侧面
  const CubeLeft = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      // 会canvas的应该都能看得懂,shape是从custom传入的
      const xAxisPoint = shape.xAxisPoint;
      // console.log(shape);
      const c0 = [shape.x, shape.y];
      const c1 = [shape.x - offsetX, shape.y - offsetY];
      const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY];
      const c3 = [xAxisPoint[0], xAxisPoint[1]];
      ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath();
    }
  });
  // 绘制右侧面
  const CubeRight = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const xAxisPoint = shape.xAxisPoint;
      const c1 = [shape.x, shape.y];
      const c2 = [xAxisPoint[0], xAxisPoint[1]];
      const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY];
      const c4 = [shape.x + offsetX, shape.y - offsetY];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 绘制顶面
  const CubeTop = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0
    },
    buildPath: function (ctx, shape) {
      const c1 = [shape.x, shape.y];
      const c2 = [shape.x + offsetX, shape.y - offsetY]; // 右点
      const c3 = [shape.x, shape.y - offsetX];
      const c4 = [shape.x - offsetX, shape.y - offsetY];
      ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
    }
  });
  // 注册三个面图形
  echarts.graphic.registerShape('CubeLeft', CubeLeft);
  echarts.graphic.registerShape('CubeRight', CubeRight);
  echarts.graphic.registerShape('CubeTop', CubeTop);

  const VALUE = [100, 200, 300];
  let option = {
    // backgroundColor: '#012366',
    tooltip: {
      show: false,
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      },
      formatter: function (params, ticket, callback) {
        const item = params[1];
        return item.name + ' : ' + item.value;
      }
    },
    grid: {
      top: '12%',
      left: '3%',
      right: '5%',
      bottom: '0',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      data: ['已签约户数', '已腾空户数', '已拆除户数'],
      axisLine: {
        show: true,
        lineStyle: {
          width: 1,
          color: '#344761'
        }
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        color: '#fff'
      }
    },
    yAxis: {
      type: 'value',
      name: '户',
      nameTextStyle: {
        color: '#fff'
      },
      axisLine: {
        show: true,
        lineStyle: {
          width: 1,
          color: '#344761'
        }
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: '#172749'
        }
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        color: '#fff'
      }
    },
    series: [
      {
        type: 'custom',
        renderItem: (params, api) => {
          const location = api.coord([api.value(0), api.value(1)]);
          // 自定义每根柱状的颜色, 通过柱子的下表来判定
          let CubeLeftColor = [{ offset: 0, color: '#22c6fc' }, { offset: 1, color: '#052e44' }];
          if (params.dataIndex === 0) {
            CubeLeftColor = [{ offset: 0, color: '#22c6fc' }, { offset: 1, color: '#052e44' }];
          } else if (params.dataIndex === 1) {
            CubeLeftColor = [{ offset: 0, color: '#fdc81e' }, { offset: 1, color: '#464704' }];
          } else {
            CubeLeftColor = [{ offset: 0, color: '#27e6ab' }, { offset: 1, color: '#03302f' }];
          }
          console.log(params.dataIndex);
          return {
            type: 'group',
            children: [
              {
                type: 'CubeLeft',
                barWidth: 20,
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, CubeLeftColor)
                }
              },
              {
                type: 'CubeRight',
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, CubeLeftColor)
                }
              },
              {
                type: 'CubeTop',
                shape: {
                  api,
                  xValue: api.value(0),
                  yValue: api.value(1),
                  x: location[0],
                  y: location[1],
                  xAxisPoint: api.coord([api.value(0), 0])
                },
                style: {
                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, CubeLeftColor)
                }
              }
            ]
          };
        },
        data: VALUE
      },
      {
        type: 'bar',
        label: {
          normal: {
            show: true,
            position: 'top',
            fontSize: 16,
            color: '#fff',
            offset: [0, -5]
          }
        },
        itemStyle: {
          color: 'transparent'
        },
        tooltip: {},
        data: VALUE
      }
    ]
  };
  myChart.setOption(option);
  window.addEventListener('resize', function () {
    myChart.resize();
  });
};
Tip:
// 添加该段代码, 当页面大小发生变化时, echarts 会进行自适应
window.addEventListener('resize', function () {
  myChart.resize();
});
  • 当在vue是中使用 echarts 时, 自定义 echarts 的弹出框 tooltip, 在里面添加的点击事件需要挂在到 window 对象上才会生效
image.png

你可能感兴趣的:(Echarts 画3D立体柱状图)