1.新建chart.js文件
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
// 计算
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
isSelected = false;
k = typeof k !== "undefined" ? k : 1 / 3;
let offsetX = isSelected ? Math.sin(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let hoverRate = isHovered ? 1.05 : 1;
return {
u: { min: -Math.PI, max: Math.PI * 3, step: Math.PI / 32, },
v: { min: 0, max: Math.PI * 2, step: Math.PI / 20, },
x: function (u, v) {
if (u < startRadian) {
return (offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate);
}
if (u > endRadian) {
return (offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate);
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function (u, v) {
if (u < startRadian) {
return (offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate);
}
if (u > endRadian) {
return (offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate);
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function (u, v) {
if (u < -Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u) * h * 0.1;
}
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
},
};
}
export function getPie3D(pieData, internalDiameterRatio) {
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let k = typeof internalDiameterRatio !== "undefined" ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
name: typeof pieData[i].name === "undefined" ? `series${i}` : pieData[i].name,
type: "surface",
parametric: true,
wireframe: { show: false, },
pieData: pieData[i],
pieStatus: { selected: false, hovered: false, k: 1 / 10, },
};
if (typeof pieData[i].itemStyle != "undefined") {
let itemStyle = {};
typeof pieData[i].itemStyle.color != "undefined" ? (itemStyle.color = pieData[i].itemStyle.color) : null;
typeof pieData[i].itemStyle.opacity != "undefined" ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;
seriesItem.itemStyle = itemStyle;
}
series.push(seriesItem);
}
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value;
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = getParametricEquation(
series[i].pieData.startRatio,
series[i].pieData.endRatio,
false,
false,
k,
series[i].pieData.value
);
startValue = endValue;
legendData.push(series[i].name);
}
let option = {
color: ["rgba(26, 255, 167, 1)", "rgba(42, 184, 255, 1)", "rgba(210, 0, 255, 1)"],
title: {
text: `46.2% \n{num|回收物料状态}`,
right: 'center',
top: '35%',
textStyle: { color: "#fff", fontWeight: 400, fontSize: 24, rich: { num: { fontSize: 14 } }, },
},
legend: { bottom: "20", itemWidth: 10, itemHeight: 10, icon: "rund", textStyle: { color: "#fff" }, },
xAxis3D: {},
yAxis3D: {},
zAxis3D: {},
grid3D: {
// distance缩小、alpha放大、beta调整角度
viewControl: { autoRotate: false, distance: 120, alpha: 26, beta: 60, },
left: "center",
top: -20,
show: false,
boxHeight: 20,
},
series: series,
};
return option;
}
2.vue文件引入并使用
<script setup>
import * as echarts from "echarts";
import "echarts-gl"; // 3d图表库
import { getPie3D } from "./chart";
// 中 -> 3d饼图 --> 回收物料状态
const pieRef = ref(null);
const pieOption = async () => {
echarts.init(pieRef.value).setOption(getPie3D([
{ name: "完好状态", value: 30, itemStyle: { opacity: 0.7 } },
{ name: "待修状态", value: 50, itemStyle: { opacity: 0.7 } },
{ name: "报废状态", value: 20, itemStyle: { opacity: 0.7 } }
], 0.7));
}
</script>
<template>
<div class="bai pie-ec" ref="pieRef"></div>
</template>
显示效果