> 技术文档 > Echarts3D饼图的配置_echarts 3d饼图

Echarts3D饼图的配置_echarts 3d饼图

3d饼图,已封装完成,能满足大部分情况,但极值仍可能会出现问题

下载依赖
 

echarts引用3d图形首先需要引入echarts其次在引入echarts-gl import * as echarts from \"echarts\";import \"echarts-gl\";

效果如下

数据格式如下

pieData: [ { name: \"特级\", value: 10, unit: \"万户\",  itemStyle: { color: \"#DD3BF3\" }, }, { name: \"一级\", value: 20, unit: \"万户\",  itemStyle: { color: \"#31E49F\" }, }, { name: \"二级\", value: 30, unit: \"万户\",  itemStyle: { color: \"#7C4CF5\" }, }, { name: \"临时\", value: 40, unit: \"万户\",  itemStyle: { color: \"#1E47F1\" }, }, ],

使用如下

 queryUserModuleInfo(params).then((res) => { if (res.status === 200 && res.data.code === 200) { const resData = res.data.data; const pieData = deepClone(this.pieData);  const value = resData.slice(4, 5); const pieDataArr = resData.slice(0, 4); // 用户数-赋值  pieDataArr.forEach((item, index) => {// 饼图数据赋值 if (item.name === pieData[index].name) { this.$set(pieData[index], \"value\", Number(item.number || 0)); } }); // 将pieData进行排序,根据value排序 pieData.sort((a, b) => b.value - a.value); this.$refs.pie.setPie(pieData, this.chartId, this.chartName, this.chartsClick); }

封装完成的3d饼图

 
import { formatNumber } from \"@/utils/util.js\";//处理数据的,与整体无关export default { props: { mapTitle: [String, Array], // 视角到主体的距离 distance: { type: Number, default: 260, }, // 旋转角度 alpha: { type: Number, default: 16, }, beta: { type: Number, default: 60, }, pieDataFlag: { type: Boolean, default: false, }, optionData: { type: Array, default: () => [], }, chartId: { type: [String, Number], default: () => new Date().getTime(), }, unit: { type: String, default: () => \"\", }, chart: { type: String, default: () => null, }, eventName: { type: Function, default: null, }, }, data() { return { localChartId: this.chartId, localEventName: this.eventName, isUpdating: false, // 新增标志位 }; }, mounted() { remoteEvent.on(\"mapClick\", () => { this.setPie(this.optionData, this.chartId, this.chart, this.eventName); }); this.setPie(this.optionData, this.chartId, this.chart, this.eventName); }, methods: { setPie(pieData, id, myChart, eventName) { if (myChart) myChart.dispose(); var option = this.getPie3D(pieData); //是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption option.series.push({ backgroundColor: \"transparent\", name: \"pie2d\", type: \"pie\", label: { opacity: 1, overflow: \"none\" }, itemStyle: { opacity: 0.02 }, labelLine: { length: 20, length2: 10 }, startAngle: -60, // 起始角度,支持范围[0, 360]。 clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式 radius: [\"30%\", \"55%\"], center: [\"50%\", \"50%\"], data: pieData, // 与之前的series数据一致 tooltip: { show: false, }, }); myChart = this.$echarts.init(document.getElementById(id)); myChart.setOption(option); myChart.off(\"click\"); // 防止重复绑定点击事件 // 添加点击事件 myChart.on(\"click\", (params) => eventName(params, this.mapTitle)); window.addEventListener(\"resize\", () => myChart.resize()); }, getPie3D(pieData) { // internalDiameterRatio:透明的空心占比 let series = []; let sumValue = 0; let startValue = 0; let endValue = 0; let k = 1; pieData.sort((a, b) => { return b.value - a.value; }); // 为每一个饼图数据,生成一个 series-surface 配置 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: k, }, radius: \"50%\", center: [\"10%\", \"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); } // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数, // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。 for (let i = 0; i { if (params.seriesName !== \"mouseoutSeries\" && params.seriesName !== \"pie2d\") { let bfb = 0; if (this.pieDataFlag) { let findItem = pieData.find((item) => item.name === params.seriesName); bfb = findItem.value; } const unit = [\"万个\", \"万户\"]; const format = unit.includes(this.unit) ? 2 : 0; return ( \"
\" + `${params.seriesName}
` + `` + `${formatNumber(bfb, format)}${this.unit}` + \"
\" ); } }, }, xAxis3D: { min: -1, max: 1, }, yAxis3D: { min: -1, max: 1, }, zAxis3D: { min: -1, max: 1, }, grid3D: { show: false, boxHeight: boxHeight, //圆环的高度 left: 0, top: 0, //3d饼图的位置 viewControl: { //3d效果可以放大、旋转等,请自己去查看官方配置 alpha: this.alpha, //角度 // 饼块开始得角度 beta: this.beta || 60, distance: this.distance, //调整视角到主体的距离,类似调整zoom rotateSensitivity: 0, //设置为0无法旋转 zoomSensitivity: 0, //设置为0无法缩放 panSensitivity: 0, //设置为0无法平移 // autoRotate: true //自动旋转 }, }, series: series, }; return option; }, //获取3d丙图的最高扇区的高度 getHeight3D(series, height) { series.sort((a, b) => { return b.pieData.value - a.pieData.value; }); return (height * 25) / series[0].pieData.value; }, // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation 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; // 如果只有一个扇形,则不实现选中效果。 if (startRatio === 0 && endRatio === 1) { isSelected = true; } // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3) k = typeof k !== \"undefined\" ? k : 1 / 3; // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0) let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0; let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0; // 计算高亮效果的放大比例(未高亮,则比例为 1) 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 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 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 * 2.5) { return Math.sin(u) * h * 0.1; } return Math.sin(v) > 0 ? 1 * h * 0.1 : -1; }, }; }, },};.main { width: 100%; height: 100%; .pie-charts { width: 100%; height: 100%; }}