echarts-3D立体柱状图-多个系列的时候堆叠显示-有rich富文本显示标签

我要冲啦个人网站建设2025-01-03web前端

<template>

<div ref="chartRef"></div>

</template>

<script>

import * as echarts from "echarts";

export default {

  props: {

    showLargeBtn: {

      type: Boolean,

      default: true

    },

    colorType: {

      type: [String, Number],

      default: 1,

    },

    loopShowTip: {

      type: Boolean,

      default: false,

    },

    showLegend: {

      type: Boolean,

      default: true,

    },

    showValue: {

      type: Boolean,

      default: false,

    },

    showValueTotal: {

      type: Boolean,

      default: false,

    },

    showTop: {

      type: Boolean,

      default: false,

    },

  },

  data() {

    return {

      myChart: null,

      timer: null,

      data: { xAxisData: [], seriesData: [] },

      xAxisData: [],

    };

  },

  mounted() {

    this.initChart();

    window.addEventListener("resize", this.resize);

  },

  beforeDestroy() {

    window.removeEventListener("resize", this.resize);

    this.$refs.chartRef.onmouseout = null;

    if (this.timer) {

      clearInterval(this.timer);

      this.timer = null;

    }

    if (this.myChart && this.myChart != null) {

      this.myChart.dispose();

    }

  },

  methods: {

    initChart() {

      const vm = this;

      if (vm.myChart && vm.myChart != null) {

        vm.myChart.dispose();

        vm.myChart = null;

      }

      if (vm.data.xAxisData == false) {

        vm.$refs.chartRef.innerHTML = `<div class="el-empty"><div class="el-empty__image"><img src="${require("@/assets/empty.png")}"/></div></div>`;

        return;

      }

      // 绘制左侧面

      const CubeLeft = echarts.graphic.extendShape({

        buildPath: function (ctx, shape) {

            // 会canvas的应该都能看得懂,shape是从custom传入的

            const xAxisPoint = shape.xAxisPoint;

            const c0 = [shape.x, shape.y];

            const c1 = [shape.x - 10, shape.y - 2];

            const c2 = [xAxisPoint[0] - 10, xAxisPoint[1] - 2];

            const c3 = [xAxisPoint[0], 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({

        buildPath: function (ctx, shape) {

            const xAxisPoint = shape.xAxisPoint;

            const c1 = [shape.x, shape.y];

            const c2 = [xAxisPoint[0], xAxisPoint[1] + 2];

            const c3 = [xAxisPoint[0] + 10, xAxisPoint[1] - 2];

            const c4 = [shape.x + 10, shape.y - 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({

        buildPath: function (ctx, shape) {

            const c1 = [shape.x, shape.y + 2];

            const c2 = [shape.x + 10, shape.y - 2];

            const c3 = [shape.x, shape.y - 6];

            const c4 = [shape.x - 10, shape.y - 2];

            ctx

              .moveTo(c1[0], c1[1])

              .lineTo(c2[0], c2[1])

              .lineTo(c3[0], c3[1])

              .lineTo(c4[0], c4[1])

              .closePath();

        },

      });

      // 绘制文字

      const CubeText = echarts.graphic.extendShape({

        buildPath: function (ctx, shape) {

            const c1 = [shape.x, shape.y + 2];

            const c2 = [shape.x + 10, shape.y - 2];

            const c3 = [shape.x, shape.y - 6];

            const c4 = [shape.x - 10, shape.y - 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 itemColor1 = ["#21CBC5", "#486DEF"];

      const itemColor2 = ["#FDAD4D", "#A9D942"];

      const barColor1 = [

      {

          left: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: 'rgba(106,238,197,1)',

              },

              {

                offset: 0.8,

                color: "rgba(36,183,137,1)",

              },

          ]),

          right: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: "rgba(106,238,197,0.8)",

              },

              {

                offset: 0.8,

                color: "rgba(36,183,137,0.8)",

              },

          ]),

          top: '#55ddb3',

        },

        {

          left: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: 'rgba(131,185,255,1)',

              },

              {

                offset: 0.8,

                color: "rgba(0,111,255,1)",

              },

          ]),

          right: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: "rgba(131,185,255,0.8)",

              },

              {

                offset: 0.8,

                color: "rgba(0,111,255,0.8)",

              },

          ]),

          top: '#69AAFF',

        }

      ]

      const barColor2 = [

      {

          left: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: 'rgba(155,176,250,1)',

              },

              {

                offset: 0.8,

                color: "rgba(71,136,255,1)",

              },

          ]),

          right: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: "rgba(155,176,250,0.8)",

              },

              {

                offset: 0.8,

                color: "rgba(71,136,255,0.8)",

              },

          ]),

          top: '#79a2ed',

        },

        { // background: linear-gradient(0deg, #FFBF80 0%, #F48D27 100%);

          left: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: 'rgba(255,191,128,1)',

              },

              {

                offset: 0.8,

                color: "rgba(244,141,39,1)",

              },

          ]),

          right: new echarts.graphic.LinearGradient(0, 1, 0, 0, [

              {

                offset: 0,

                color: "rgba(255,191,128,0.8)",

              },

              {

                offset: 0.8,

                color: "rgba(244,141,39,0.8)",

              },

          ]),

          top: '#FFD6AE',

        }

      ]

      const barColor = vm.colorType == 1 ? barColor1 : barColor2

      const itemColor = vm.colorType == 1 ? itemColor1 : itemColor2

      this.xAxisData = [];

      const legendData = vm.data.seriesData.map((item,index) => {

        return {

          name: item.name,

          itemStyle: {

            color: itemColor[index]

          }

        }

      });

      vm.xAxisData = vm.data.xAxisData;

      const seriesData = [];

      let barWidth = 24;

      switch(vm.colorType) {

        case 1:

          barWidth = 24;

          break;

      }

      const itemTotalData = vm.data.seriesData[0].data.map((item0, index0) => item0 + vm.data.seriesData[1].data[index0]).map((item) => {

        return item == 0 ? null : item;

      })

      const itemHeightData = [] // [[第1个系列第1列的高度, 第1个系列第2列的高度...], [第2个系列第1列的高度, 第2个系列第2列的高度...]]

      vm.data.seriesData.forEach((item, index) => {

        const itemHeightArr = []

        item.data.forEach((item1, index1) => {

          if (index == 0) {

            itemHeightArr.push(item1)

          } else {

            itemHeightArr.push(itemHeightData[index - 1][index1] + item1)

          }

        })

        itemHeightData.push(itemHeightArr)

      })

      vm.data.seriesData.forEach((item, index) => {

        item.data = item.data.map((item) => {

          return item == 0 ? null : item;

        })

        const seriesItem = {

          name: item.name,

          type: "custom",

          renderItem: (params, api) => {

            var color = barColor[params.seriesIndex];

            const curValueTotal = itemHeightData[params.seriesIndex][params.dataIndex]

              // const location = api.coord([api.value(0), api.value(1)]); // 不叠加的时候

              const location = api.coord([api.value(0), curValueTotal]); // 叠加的时候

              let str = ''

              if (vm.showValueTotal || vm.showTop || vm.showValue) {

                if (vm.showTop) {

                  /* if (params.dataIndex == 0) {

                    str += '{top1|Top.1}' + '\n'

                  } else if (params.dataIndex == 1) {

                    str += '{top2|Top.2}' + '\n'

                  } else if (params.dataIndex == 2) {

                    str += '{top3|Top.3}' + '\n'

                  } */

                if (params.dataIndex < 3) {

                  str += `{top${params.dataIndex +1}|Top.${params.dataIndex + 1 }}` + '\n'

                }

                }

                if (vm.showValueTotal) {

                  str += '{text|' + itemTotalData[params.dataIndex] + '}'

                }

                if (vm.showValue) {

                  let itemTotal = 0

                  let itemStr = ''

                  const seriesLen = seriesData.length

                  for(let i=seriesLen-1; i>=0; i--) {

                    itemTotal += seriesData[i].data[params.dataIndex]

                    itemStr += `{name${i}|` + seriesData[i].data[params.dataIndex] + `}`

                    if (i > 0) {

                      itemStr += '\n'

                    }

                  }

                  if (itemTotal > 0) {

                    str += itemStr

                  }

                }

              }

              return {

                type: "group",

                children: [

                    {

                      type: "CubeLeft",

                      shape: {

                          api,

                          xValue: api.value(0),

                          yValue: api.value(1),

                          x: location[0],

                          y: location[1],

                          // xAxisPoint: api.coord([api.value(0), 0]), // 不叠加的时候

                          xAxisPoint: api.coord([api.value(0), curValueTotal - api.value(1)]), // 叠加的时候

                      },

                      style: {

                          fill: (color = barColor[params.seriesIndex].left),

                      },

                    },

                    {

                      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]), // 不叠加的时候

                          xAxisPoint: api.coord([api.value(0), curValueTotal - api.value(1)]), // 叠加的时候

                      },

                      style: {

                          fill: (color = barColor[params.seriesIndex].right),

                      },

                    },

                    {

                      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]), // 不叠加的时候

                          xAxisPoint: api.coord([api.value(0), curValueTotal - api.value(1)]), // 叠加的时候

                      },

                      style: {

                          fill: (color = barColor[params.seriesIndex].top),

                      },

                    },

                    {

                      type: 'text',

                      ignore: params.seriesIndex != vm.data.seriesData.length - 1,

                      style: {

                          text: str,

                          x: location[0],

                          y: location[1] - 8 - 12 * str.split('\n').length - (str.includes('Top') ? 5 : 0),

                          textAlign: 'center',

                          rich: {

                            top1: {

                              fill: '#F76060',

                              fontWeight: 'bold',

                              padding: [0, 0, 5, 0]

                            },

                            top2: {

                              fill: '#809DBE',

                              fontWeight: 'bold',

                              padding: [0, 0, 5, 0]

                            },

                            top3: {

                              fill: '#FC9B3C',

                              fontWeight: 'bold',

                              padding: [0, 0, 5, 0]

                            },

                            text: {

                            },

                            name0: {

                              fill: itemColor[0]

                            },

                            name1: {

                              fill: itemColor[1]

                            },

                            name2: {

                              fill: itemColor[2]

                            },

                            name3: {

                              color: itemColor[3]

                            }

                          }

                      },

                    }

                ],

              };

          },

          stack: "group",

          data: item.data,

        }

        if (item.avg !== undefined) {

          seriesItem.markLine = {

            symbol: 'none',

            label: {

              show: false

              // color: 'rgba(30, 144, 245, 1)',

              // formatter: function (params) {

              //   return item.name.replace('数量','平均值') + ':' + lwTavg

              // }

            },

            lineStyle: {

              // color: 'rgba(30, 144, 245, 1)',

              shadowColor: '#ffffff', // 阴影颜色

              shadowBlur: 3, // 阴影的模糊大小

              shadowOffsetX: 0, // 阴影的水平偏移

              shadowOffsetY: 0, // 阴影的垂直偏移

            },

            data: [{ name: item.name.replace('数量','平均值'), yAxis: item.avg, type: 'average' }]

          }

        }

        seriesData.push(seriesItem);

      });

      vm.myChart = echarts.init(vm.$refs.chartRef);

      let dataZoomTnterval = 11

      let option = {

        color: itemColor,

        tooltip: {

          trigger: "axis",

          axisPointer: {

            type: "shadow",

          },

          borderWidth: 0,

          confine: true,

        },

        legend: {

          top: "5px",

          right: 0,

          icon: "circle",

          itemWidth: 12,

          itemHeight: 12,

          show: vm.showLegend,

          data: legendData,

        },

        grid: {

          top: vm.showLegend

            ? legendData.length > 4

              ? "70px"

              : "50px"

            : "35px",

          left: "0",

          right: "20px",

          bottom: vm.xAxisData.length > dataZoomTnterval + 1 ? "20px" : '0',

          containLabel: true,

        },

        xAxis: {

          type: "category",

          show: true,

          triggerEvent: true, // 只有加上这个,才能绑定上

          axisTick: {

            show: false,

          },

          splitLine: {

            show: false,

          },

          axisLine: {

            show: false,

          },

          axisLabel: {

            interval: 0,

            fontSize: 12,

            color: "#999999",

            overflow: "truncate",

            ellipsis: "...",

            width: 80,

            // formatter: res => {

            //   const len = res.length

            //   return len > 5 ? res.slice(0, 5) + '...' : res

            // },

            // margin: 15

          },

          boundaryGap: true,

          data: vm.xAxisData,

        },

        yAxis: {

          type: "value",

          show: true,

          splitLine: {

            show: true,

            lineStyle: {

              type: "dashed",

              color: "#ECECEC",

            },

          },

          axisTick: {

            show: false,

            alignWithLabel: false,

            inside: false,

          },

          axisLine: {

            show: false,

          },

          axisLabel: {

            fontSize: 12,

            color: "#999999",

          },

          max: function (value) {

            if (value.max < 10) {

              return 10;

            }

            // return Math.round(value.max / 50) * 50 + 50

          },

        },

        dataZoom: [

          {

            type: "slider",

            height: 0, // dataZoom 组件的高度,同样只对第一个 x 轴有效

            left: 30, // 组件距离左侧的距离

            right: 15, // 组件距离右侧的距离

            bottom: 10, // 组件距离底部的距离

            borderColor: "transparent",

            startValue: vm.xAxisData[0],

            endValue: vm.xAxisData[dataZoomTnterval],

            textStyle: {

              color: "transparent",

            },

            moveHandleIcon: "none",

            moveHandleStyle: {

              backgroundColor: "rgba(66, 104, 239, 0.1)",

              borderColor: "rgba(66, 104, 239, 1)",

              borderCap: "round",

            },

            show: vm.xAxisData.length > dataZoomTnterval + 1,

          },

        ],

        series: seriesData,

      };

      vm.myChart.setOption(option);

      if (vm.timer) {

        clearInterval(vm.timer);

      }

      let currentIndex = -1;

      let dataZoomEndValue = dataZoomTnterval;

      // 自动轮询展示提示框

      function switchTooltip(myChart) {

        const dataLen = vm.xAxisData.length;

        if (dataLen > 0) {

          currentIndex = (currentIndex + 1) % dataLen; // 取余 循环展示

          if (

            currentIndex > dataZoomEndValue ||

            currentIndex < dataZoomEndValue - dataZoomTnterval

          ) {

            myChart.dispatchAction({

              type: "dataZoom",

              // 开始位置的数值

              startValue:

                currentIndex < dataZoomTnterval

                  ? 0

                  : currentIndex - dataZoomTnterval,

              endValue:

                currentIndex < dataZoomTnterval

                  ? dataZoomTnterval

                  : currentIndex,

            });

          }

          myChart.dispatchAction({

            type: "showTip",

            seriesIndex: 0,

            dataIndex: currentIndex,

          });

        }

      }

      function startTooltipLoop(myChart) {

        clearInterval(vm.timer);

        if (vm.loopShowTip) {

          vm.timer = setInterval(() => switchTooltip(myChart), 2000);

        }

      }

      // 开始轮询

      startTooltipLoop(vm.myChart);

      // 监听dataZoom的change事件

      vm.myChart.on("datazoom", function (event) {

        if (event.endValue) {

          dataZoomEndValue = event.endValue;

        }

      });

      // 鼠标离开, 开始轮询

      /* vm.$refs.chartRef.addEventListener('mouseout', () => {

          startTooltipLoop(vm.myChart)

        }) */

      vm.$refs.chartRef.onmouseout = () => {

        startTooltipLoop(vm.myChart);

      };

      vm.myChart.on("mouseover", (params) => {

        if (vm.timer) {

          clearInterval(vm.timer);

          vm.timer = null;

        }

        currentIndex = params.dataIndex;

        // currentIndex = -1

      });

      // 点击事件

      if (vm.showLargeBtn) {

        vm.myChart.on('click', (params) => {

          this.$emit('changeTableShow', params.name)

        })

      }

    },

    setData(data) {

      this.data = data;

      this.initChart();

    },

    resize() {

      if (this.myChart) {

        this.myChart.resize();

      }

    },

  },

};

</script>

 

文章关键词
echarts
3D立体柱状图
多个系列的时候堆叠显示
rich富文本显示标签