echarts堆叠立体柱状图

<template>
  <div :id="echartsId" style="width: 100%"></div>
</template>

<script setup>
import { onMounted, ref, defineProps, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
  // id
  echartsId: {
    type: String,
    default: "echartsId",
  },
  // 切换重新渲染
  echartsBool: {
    type: Boolean,
    default: null,
  },
  // y轴数据上面的名字
  yAxisJsonName: {
    type: String,
    default: "单位:个数",
  },
  // y轴字体样式
  nameTextStyle: {
    type: Object,
    default: () => {
      return {
        color: "#fff",
        fontSize: 16,
        fontWeight: 400,
        verticalAlign: "bottom",
        // 左上字体位置
        padding: [0, -20, 10, 20],
      };
    },
  },
  // 主体宽度
  barWidth: {
    type: String,
    default: "40",
  },
  // x轴展示的名字
  xAxisJson: {
    type: Array,
    default: () => {
      return [];
    },
  },
  //y轴的展示名字
  yAxisJson: {
    type: Array,
    default: () => {
      return ["隐患事件", "不安全事件", "风险", "重大作业", "其他"];
    },
  },
  // data展示数据
  dataJson: {
    type: Object,
    default: () => {
      return [
        [10, 20, 30, 5, 8],
        [8, 10, 0, 30, 5],
        [30, 5, 0, 10, 20],
        [20, 30, 0, 8, 10],
        [5, 8, 10, 20, 30],
      ];
    },
  },
  // legend方向
  legendDirection: {
    type: Object,
    default: () => {
      return {
        bottom: "0",
        top: "0",
        left: "0",
        right: "0",
      };
    },
  },
  // grid方向
  gridDirection: {
    type: Object,
    default: () => {
      return {
        bottom: "10%",
        top: "25%",
        right: "0%",
        left: "4%",
      };
    },
  },
  // 柱体颜色 定义的是左右渐变 ,如果不需要传过来一样的就好了
  barColorArray: {
    type: Object,
    default: () => {
      return {
        // 从左到右
        colorArr1: ["#0E3C69", "#0E336E", "#5433FF", "#20BDFF"],
        colorArr2: ["#FE8C00", "#FE8C00", "#FE8C00", "#F83600"],
        colorArr3: ["#2CA6A6", "#2CA6A6", "#43E3E3", "#247C7D"],
        colorArr4: ["#18D4A0", "#18D4A0", "#AAFFA9", "#11FFBD"],
        colorArr5: ["#823CF4", "#823CF4", "#823CF4", "#D015E0"],
      };
    },
  },
  // 顶片颜色 同柱体颜色一样
  upColorArray: {
    type: Object,
    default: () => {
      return {
        colorArr1: ["#2484BA", "#2484BA", "#2D9DD6", "#2D9DD6"],
        colorArr2: ["#FDB600", "#FDB600", "#FDB600", "#FDB600"],
        colorArr3: ["#44E6E6", "#44E6E6", "#44E6E6", "#44E6E6"],
        colorArr4: ["#1DF9BC", "#1DF9BC", "#1DF9BC", "#1DF9BC"],
        colorArr5: ["#6515E8", "#6515E8", "#6515E8", "#6515E8"],
      };
    },
  },
  // 底部颜色
  bottomColorArray: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 开启底部颜色不
  openBottomColor: {
    type: Boolean,
    default: false,
  },
});
//组织颜色
let setColor = function (colorArr) {
  let color = {
    type: "linear",
    x: 0,
    x2: 1,
    y: 0,
    y2: 0,
    /* 此处决定阴暗面 若为横向柱状图则x,y轴调换
					x: 0,
					x2: 0,
					y: 0,
					y2: 1, */
    colorStops: [
      {
        offset: 0,
        color: colorArr[0],
      },
      {
        offset: 0.5,
        color: colorArr[1],
      },
      {
        offset: 1,
        color: colorArr[2],
      },
      {
        offset: 0.5,
        color: colorArr[3],
      },
    ],
  };
  return color;
};
// 设置每一项的叠加总数,方便serve的顶部渲染
const upStack = ref({
  upStackArr1: [],
  upStackArr2: [],
  upStackArr3: [],
  upStackArr4: [],
  upStackArr5: [],
});
const serveStack = () => {
  const stackLength = props.dataJson.length;
  for (let i = 0; i < stackLength; i++) {
    const currentStackArr = props.dataJson[i];
    let sumArr = [];
    if (i === 0) {
      sumArr = currentStackArr;
    } else {
      const prevStackArr = upStack.value[`upStackArr${i}`];
      sumArr = currentStackArr.map(
        (value, index) => value + prevStackArr[index]
      );
    }
    upStack.value[`upStackArr${i + 1}`] = sumArr;
  }
};
const series = ref([]);
const bf_series = ref([]);
const actionSeries = () => {
  series.value = [];
  props.yAxisJson?.forEach((el, index) => {
    //   stack: 'total', 堆叠字段
    series.value.push(
      // 柱体
      {
        z: 1,
        type: "bar",
        name: el,
        barGap: "15%", //相邻柱子间距
        itemStyle: {
          borderRadius: [0, 0, 0, 0], //柱子四周圆角
          color: setColor(props.barColorArray[`colorArr${index + 1}`]), //柱子左右颜色(深,浅)
        },
        data: props.dataJson[index], //Y轴上的高度
        barWidth: props.barWidth,
        stack: "total",
      },
      //   每一个柱体的顶部
      {
        z: 3,
        name: el,
        type: "pictorialBar",
        symbolPosition: "end",
        data: upStack.value[`upStackArr${index + 1}`], //此数据对应顶部组件
        symbol: "diamond",
        symbolOffset: ["0%", "-50%"],
        symbolSize: [
          props.barWidth - 4,
          (10 * (props.barWidth - 10)) / props.barWidth,
        ],
        itemStyle: {
          normal: {
            borderColor: props.upColorArray[`colorArr${index + 1}`][2],
            borderWidth: 1, //加上棱角分明
            color: setColor(props.upColorArray[`colorArr${index + 1}`]), //柱子左右颜色(深,浅)
          },
        },
        tooltip: {
          show: false,
        },
        stack: "total",
      }
    );
  });
  // 底部 暂时不需要
  if (props.openBottomColor) {
    series.value.push({
      z: 2,
      name: "柱子1",
      type: "pictorialBar",
      data: [0, 0, 0, 0, 0], //此数据对应底部组件
      symbol: "diamond", //底部组件形状,不写默认为椭圆
      symbolOffset: ["0%", "50%"], //与柱子的偏移角度
      symbolSize: [25, 10], //底面[宽,高]
      itemStyle: {
        normal: {
          color: etColor(props.bottomColorArray), //底面左右颜色(深,浅)
        },
      },
      tooltip: {
        show: false,
      },
      stack: "total",
    });
  }
  bf_series.value = series.value;
};
var option = {
  tooltip: {
    trigger: "axis",
    axisPointer: {
      type: "shadow",
    },
    formatter: function (params) {
      var tooltipContent = ""; // 初始化 tooltip 内容字符串
      let all = 0;
      params.forEach((item) => {
        all += item.value;
      });
      tooltipContent += `<div class='tooltipContent'>总数:<span style='color:#FF3A3A'>${all}</span></div>`;
      params.forEach((item) => {
        if (item.seriesName == "隐患事件") {
          tooltipContent += `<div class='tooltipContent'>${item.seriesName}:<span style='color:#455AFF'>${item.value}</span></div>`;
        } else if (item.seriesName == "不安全事件") {
          tooltipContent += `<div class='tooltipContent'>${item.seriesName}:<span style='color:#FC7A00'>${item.value}</span></div>`;
        } else if (item.seriesName == "风险") {
          tooltipContent += `<div class='tooltipContent'>${item.seriesName}:<span style='color:#8AFFAD'>${item.value}</span></div>`;
        } else if (item.seriesName == "重大作业") {
          tooltipContent += `<div class='tooltipContent'>${item.seriesName}:<span style='color:#3BCCCD'>${item.value}</span></div>`;
        } else if (item.seriesName == "其他") {
          tooltipContent += `<div class='tooltipContent'>${item.seriesName}:<span style='color:#AF24E8'>${item.value}</span></div>`;
        }
      });
      return "<div class='tooltipBox'>" + tooltipContent + "</div>"; // 返回自定义的 tooltip 内容
    },
    // 自定义 tooltip 的样式
    extraCssText:
      "width: 120px;height: 140px;padding:0;margin:0 ;background: #0A1A34;border: 1px solid #59AFF9B4;box-shadow: 0px 1px 12px 0px #03FBFFA6 inset;",
  },
  legend: {
    show: true,
    data: props.yAxisJson,
    selectedMode: true,
    textStyle: {
      color: "#fff",
      fontSize: "14",
    },
    top: props.legendDirection.top,
    bottom: props.legendDirection.bottom,
    left: props.legendDirection.left,
    right: props.legendDirection.right,
  },
  grid: {
    right: props.gridDirection.right,
    top: props.gridDirection.top,
    bottom: props.gridDirection.bottom,
    left: props.gridDirection.left,
  },
  xAxis: {
    type: "category",
    axisLabel: {
      color: "#FFFFFF",
    },
    axisLine: {
      show: true,
      lineStyle: {
        color: "#1B3F66",
      },
    },
    axisTick: {
      show: false,
    },
    data: props.xAxisJson,
  },
  yAxis: {
    type: "value",
    axisLabel: {
      show: true,
      // 字体样式
      color: "#fff", //更改坐标轴文字颜色
      fontSize: 12, //更改坐标轴文字大小
    },
    axisLine: {
      show: true,
      lineStyle: {
        color: "#1B3F66",
      },
    },
    splitLine: {
      show: true,
      lineStyle: {
        type: "dashed", // 将轴线设置为虚线
        color: "#35414C",
      },
    },
    name: props.yAxisJsonName,
    nameTextStyle: props.nameTextStyle,
  },
  series: [],
};
// legend 监听处理的事
const legendselectAction = (selected_false_name) => {
  let indexArray = [];
  let bf_upStack = JSON.parse(JSON.stringify(upStack.value));
  //   找到名字下标
  selected_false_name.forEach((el) => {
    indexArray.push(props.yAxisJson.indexOf(el));
  });
  //   找到下标一致的数据,对其他的数据进行相减得到新的up数据
  indexArray.forEach((el) => {
    // 找到对应需要减的下标
    for (let index = el + 1; index < 5; index++) {
      const currentStackArr = props.dataJson[el];
      // bf_upStack[`upStackArr${index}`] = [];
      var sy = [];
      // 遍历数组,对应下标进行相减
      for (var i = 0; i < bf_upStack[`upStackArr${index + 1}`].length; i++) {
        sy.push(bf_upStack[`upStackArr${index + 1}`][i] - currentStackArr[i]);
      }
      bf_upStack[`upStackArr${index + 1}`] = sy;
    }
  });
  //   重新赋值server
  props.yAxisJson.forEach((el, index) => {
    series.value.forEach((item) => {
      if (el == item.name && item.type != "bar") {
        item.data = bf_upStack[`upStackArr${index + 1}`];
      }
    });
  });
};
const initData = () => {
  // 设置每一项的叠加总数,
  serveStack();
  // 对series进行处理
  actionSeries();
  option.series = series.value;
  chart.setOption(option, true);
};
let chart = "";
onMounted(() => {
  const chartDom = document.getElementById(`${props.echartsId}`);
  chart = echarts.init(chartDom);
  initData();
  // 监听 legend 的点击事件
  chart.on("legendselectchanged", function (params) {
    let selected_false_name = [];
    for (const key in params.selected) {
      const element = params.selected[key];
      // 找到为false的name
      if (!element) {
        selected_false_name.push(key);
      }
    }
    legendselectAction(selected_false_name);
    option.series = series.value;
    chart.setOption(option, false);
  });
});
watch(
  () => props.echartsBool,
  (newValue, oldValue) => {
    // 清除之前的视图
    chart.clear();
    initData();
  },
  { deep: true }
);
</script>
<style>
.tooltipContent {
  color: #99afcc;
  text-align: left;
  font-size: 14px;
  span {
    font-size: 14px;
    margin-left: 10px;
  }
}
.tooltipBox {
  width: 155px;
  height: 178px;
  background: url("../../../../assets/digitalSafetySupervisionBigData/echartsColumnarbody_tooltip_bg.png")
    center/155px 178px;
  margin: -10px;
  padding: 20px;
}
</style>

展示效果:
问题点:当某项数据为0的时候,顶部颜色不匹配,希望大佬看见能帮忙解决

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您好!对于堆叠的3D柱状图,您可以使用ECharts来实现。下面是一个简单的示例代码: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts 堆叠3D柱状图示例</title> <!-- 引入 ECharts.js --> <script src="https://cdn.jsdelivr.net/npm/echarts@5.1.2/dist/echarts.min.js"></script> </head> <body> <!-- 创建一个具有指定宽度和高度的 div 容器 --> <div id="chart" style="width: 600px;height: 400px;"></div> <script> // 初始化 ECharts 实例 var myChart = echarts.init(document.getElementById('chart')); // 配置项 var option = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, legend: { data: ['系列1', '系列2', '系列3'] }, grid3D: {}, xAxis3D: { type: 'category', data: ['柱1', '柱2', '柱3', '柱4', '柱5'] }, yAxis3D: {}, zAxis3D: {}, dataset: { dimensions: ['x', 'y', 'z'], source: [ [0, 0, 0, 2], [0, 1, 0, 4], [0, 2, 0, 6], [0, 3, 0, 8], [0, 4, 0, 10], [1, 0, 0, 3], [1, 1, 0, 6], [1, 2, 0, 9], [1, 3, 0, 12], [1, 4, 0, 15], [2, 0, 0, 4], [2, 1, 0, 8], [2, 2, 0, 12], [2, 3, 0, 16], [2, 4, 0, 20] ] }, series: [ { type: 'bar3D', stack: 'stack', encode: { x: 'x', y: 'y', z: 'z' } } ] }; // 使用刚指定的配置项和数据显示图表 myChart.setOption(option); </script> </body> </html> ``` 在上面的代码中,我们使用了ECharts提供的`bar3D`系列来绘制3D堆叠柱状图。您可以根据自己的需求修改数据源和配置项来适应您的实际情况。希望对您有所帮助!如果您有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值