<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的时候,顶部颜色不匹配,希望大佬看见能帮忙解决