<!-- 准备图表容器 -->
<template>
<div id="cubeLeft3dBar" ref="echartsRef" :style="'width:calc(100% - 380px)'"
style="height: 298px;background:#001F39; opacity:0.6;"></div>
</template>
<script setup>
import { areaStatsApi, latestMsgApi } from '/@/api/overview/index';
import * as echarts from 'echarts';
const props = defineProps({
nds: {
type: Array,
default: []
}
})
const xData = ref([]);
const echartsRef = ref();
const initChart = (arr) => {
// 4. 初始化 ECharts 实例并配置选项
let myChart = echarts.init(echartsRef.value);
myChart.clear();
let option = {
tooltip: {
trigger: 'axis',
},
grid: {
top: '18%',
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
legend: {
show: true,
top: 10,
left: 'center',
icon: 'rect',
textStyle: {
color: '#fff', // 文字颜色(#333/rgba均可)
// color: 'rgba(51,51,51,0.8)', // 半透明效果
fontSize: 12, // 文字大小
fontWeight: '500' // 文字粗细
},
itemWidth: 10,
itemHeight: 10,
itemGap: 20,
},
xAxis: [{
type: 'category',
axisTick: {
color: '#fff',
alignWithLabel: true,
},
axisLine: {
lineStyle: {
color: '#6A7C82', // 轴线颜色(支持十六进制/rgba/颜色名)
width: 1, // 轴线宽度(默认1px)
type: 'solid' // 轴线类型:solid(实线)/dashed(虚线)/dotted(点线)
}
},
axisLabel: {
color: '#fff', // 核心:设置X轴标签文字颜色(支持十六进制/rgba/颜色名)
fontSize: 12, // 可选:字体大小
// rotate: 30, // 可选:标签旋转角度(避免文字重叠)
fontWeight: '500' // 可选:字体粗细
},
data: xData.value,
}],
yAxis: [{
type: 'value',
min: 0,
splitLine: {
lineStyle: {
color: '#fff'
}
},
// splitNumber: 5,
// axisLine: {
// show: false
// },
// axisTick: {
// show: false
// },
splitLine: {
show: true, // 控制是否显示分割线(默认true)
lineStyle: {
color: '#075858', // 分割线颜色(可自定义,比如你之前用的#075858)
type: 'dashed', // 样式:可选 solid(实线)、dashed(虚线)、dotted(点线)
width: 1 // 分割线宽度
}
},
axisLabel: {
fontSize: 14,
color: '#fff',
fontWeight: '500' // 可选:字体粗细
},
}],
series:
arr
}
console.log('7777777777', arr, option.series)
// 5. 渲染图表并适配窗口变化
myChart.setOption(option);
window.addEventListener('resize', () => {
myChart.resize();
});
}
let colorStart = ['#00AFED', '#FCBC28', '#00D1C4', '#99D1C9']
let colorEnd = ['#0BCBF9', '#FEC65A', '#00D4CE', '#99D1C0']
// 定义立方体核心配置参数(统一控制宽、高,可按需修改)
const cubeConfig = {
// 立方体主体宽度(水平方向尺寸)
cubeWidth: 16,
// 立方体立体高度(垂直/纵深方向尺寸,控制立体效果明显程度)
cubeHeight: 8,
// 辅助偏移量(可选,微调立体面的对齐效果,基于宽高自动计算更优)
offsetX: function() { return this.cubeWidth / 2.8; },
offsetY: function() { return this.cubeHeight / 1.2; }
};
// 2. 处理数据:提取X轴类目、年度、生成系列数据
// 绘制左侧面
const CubeLeft = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath: function (ctx, shape) {
// 从全局配置提取宽高参数,避免硬编码
const { cubeWidth, cubeHeight } = cubeConfig;
const halfWidth = cubeWidth / 2; // 宽度均分,优化左侧面对齐
const xAxisPoint = shape.xAxisPoint;
// 基于配置参数计算顶点坐标(不再写死 7、10)
const c0 = [shape.x + halfWidth, shape.y];
const c1 = [shape.x - halfWidth, shape.y];
const c2 = [xAxisPoint[0] - halfWidth, xAxisPoint[1]];
const c3 = [xAxisPoint[0] + halfWidth, 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 { cubeWidth, cubeHeight } = cubeConfig;
const halfWidth = cubeWidth / 2;
const fullHeight = cubeHeight; // 立体高度(纵深方向)
const xAxisPoint = shape.xAxisPoint;
// 基于配置参数计算顶点坐标(不再写死 7、15、10)
const c1 = [shape.x + halfWidth, shape.y];
const c2 = [xAxisPoint[0] + halfWidth, xAxisPoint[1]];
const c3 = [xAxisPoint[0] + cubeWidth, xAxisPoint[1] - fullHeight];
const c4 = [shape.x + cubeWidth, shape.y - fullHeight];
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 { cubeWidth, cubeHeight } = cubeConfig;
const halfWidth = cubeWidth / 2;
const fullHeight = cubeHeight;
// 基于配置参数计算顶点坐标(不再写死 7、15、10、2)
const c1 = [shape.x + halfWidth, shape.y];
const c2 = [shape.x + cubeWidth, shape.y - fullHeight]; // 右点(对应右侧面高度)
const c3 = [shape.x - (cubeWidth / 5), shape.y - fullHeight]; // 左后点,基于宽度比例计算
const c4 = [shape.x - halfWidth, shape.y];
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 cubeBaseOffset = -30; // 基础左偏移(调整整体位置)
const cubeGap = 40; // 不同年度立方体之间的间距(可根据需要调整,越大间距越宽)
const cubeWidth = 25; // 单个立方体的宽度(匹配3D形状大小)
// 4. 初始化ECharts
onMounted(() => {
areaStatsApi({ nds: props.nds }).then((res) => {
let rawData = res.data;
// 1. 提取X轴类目(所有name)
xData.value = rawData.map(item => item.name);
// 2. 提取所有年度(去重)
const allYears = [...new Set(rawData.flatMap(item => item.vos.map(v => v.nd)))];
// 3. 生成系列数据:每个年度对应一条折线
let arr = [];
console.log('allYears==', allYears);
allYears.forEach((year, ind) => {
let d = rawData.map(item => {
// 找到当前item对应年度的num,无则填0
const vosItem = item.vos.find(v => v.nd === year);
return vosItem ? vosItem.num : 0;
})
let item = {
type: 'custom',
name: year,
renderItem: (params, api) => {
let cubeLeftStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: colorStart[ind],
},
{
offset: 1,
color: colorEnd[ind],
},
]);
let cubeRightStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: colorStart[ind],
},
{
offset: 1,
color: colorEnd[ind],
},
]);
let cubeTopStyle = {
color: colorStart[ind],
};
// var location = api.coord([api.value(0), api.value(1)]);
// location = [location[0] - 20, location[1]];
// var location1 = api.coord([api.value(0), 0]);
// location1 = [location1[0] - 20, location1[1]];
// 核心修改:计算差异化横向偏移,根据年度索引ind错开
var location = api.coord([api.value(0), api.value(1)]);
// 新增:ind * (cubeWidth + cubeGap) 让不同年度立方体横向排列
location = [ location[0] + cubeBaseOffset + ind * (cubeWidth + cubeGap),
location[1]
];
var location1 = api.coord([api.value(0), 0]);
// 同步修改X轴底部位置的偏移,保证3D立方体垂直对齐
location1 = [ location1[0] + cubeBaseOffset + ind * (cubeWidth + cubeGap),
location1[1]
];
return {
type: 'group',
children: [
{
type: 'CubeLeft',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: location1,
},
style: {
fill: cubeLeftStyle,
},
},
{
type: 'CubeRight',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: location1,
},
style: {
fill: cubeRightStyle,
},
},
{
type: 'CubeTop',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: location1,
},
style: {
fill: cubeTopStyle,
},
},
],
};
},
data: d,
}
arr.push(item);
})
// arr = getSeriesData(rawData, allYears);
console.log('serises === ', arr)
initChart(arr);
})
})
</script>