Echart实现3D饼图示例
在可视化项目中,很多地方会遇见图表;echart是最常见的;这个示例就是用Echart, echart-gl实现3D饼图效果,复制即可用
//需要安装,再引用依赖
import * as echarts from "echarts";
import 'echarts-gl';
initUserTypeEchart() {
let that = this;
let chartDom = document.getElementById("echart-id");
let myChart = echarts.init(chartDom);
function getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,h) {
const midRatio = (startRatio + endRatio) / 2;
const startRadian = startRatio * Math.PI * 2;
const endRadian = endRatio * Math.PI * 2;
const midRadian = midRatio * Math.PI * 2;
// 如果只有一个扇形,则不实现选中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
k = typeof k !== "undefined" ? k : 1 / 3;
const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 鼠标滑过时外环放大大小
const 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(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(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(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;
}
// 当前图形的高度是Z根据h(每个value的值决定的)
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
},
};
}
// 饼图数据
var optionData = [
{ name: '辣条', value: 100, percentage: 25 },
{ name: '亲嘴烧', value: 100, percentage: 25 },
{ name: '牛奶', value: 100, percentage: 25 },
{ name: '可乐', value: 100, percentage: 25 }
]
function getPie3D(pieData, internalDiameterRatio) {
const series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
const legendData = [];
let colors = ["#FFB82C", "#009EA8", "#2E9CFF", "#BB36DE"];
const k =
typeof internalDiameterRatio !== "undefined"
? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
: 1 / 3;
for (let i = 0; i < pieData.length; i += 1) {
sumValue += pieData[i].value;
const seriesItem = {
name:
typeof pieData[i].name === "undefined"
? `series${i}`
: pieData[i].name,
radius: ["40%", "60%"],
type: "surface",
parametric: true,
wireframe: { show: false },
pieData: pieData[i],
pieStatus: { selected: false, hovered: false, k },
};
if (typeof pieData[i].itemStyle !== "undefined") {
const { itemStyle } = pieData[i];
// eslint-disable-next-line no-unused-expressions
typeof pieData[i].itemStyle.color !== "undefined"
? (itemStyle.color = pieData[i].itemStyle.color)
: null;
// eslint-disable-next-line no-unused-expressions
typeof pieData[i].itemStyle.opacity !== "undefined"
? (itemStyle.opacity = pieData[i].itemStyle.opacity)
: null;
seriesItem.itemStyle = itemStyle;
}
// series = getPie3D(optionData, 0.3)
series.push(seriesItem);
}
for (let i = 0; i < series.length; i += 1) {
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,
true,
k,
10 // 在此处传入饼图初始高度h
);
startValue = endValue;
legendData.push({
name: series[i].name,
textStyle: { color: colors[i] },
});
}
// 准备待返回的配置项,把准备好的series 传入。
const option = {
title: {
show: false,
},
// 右边提示文本
legend: {
show: true,
type: "scroll",
right: 20,
top: "center",
orient: "vertical", // 纵向
icon: "circle", // icon 类型 标记类型包括 'circle'圆, 'rect'方, 'roundRect'圆角, 'triangle'三角形, 'diamond'lin, 'arrow'箭头, 'pin', 'arrow', 'none'
itemHeight: 12, // icon高度
itemWidth: 12, // icon 宽度
itemGap: 10, // 图例间隔 --每个title之间的间隔
data: legendData,
formatter: (name) => {
if (pieData.length) {
const item = pieData.filter((item) => item.name === name)[0];
// console.log(item, name)
var arr = [
`{a|${name}}{b|${item.value}户 (${item.percentage}%)}`,
];
return arr;
// return `${name}:${item.value}`
}
},
textStyle: {
color: "auto",
rich: {
//改样式 和下面formatter一起
a: {
align: "left",
color: "#000",
width: 80,
fontSize: 12, // 字体大小被覆盖了,这里重新定义
},
b: {
align: "right",
// color: '#59e6ed',
fontSize: 12,
},
},
},
},
// 每一块区域的颜色
color: ["#009EA8", "#2E9CFF", "#FFB82C", "#BB36DE"],
tooltip: {
trigger: "item",
formatter: (params) => {
if (params.seriesName !== "mouseoutSeries") {
return `${params.marker}${params.seriesName}:${
pieData[params.seriesIndex].value
}户`;
}
return "";
},
},
xAxis3D: { min: -1, max: 1 },
yAxis3D: { min: -1, max: 1 },
zAxis3D: { min: -1, max: 1 },
grid3D: {
show: false,
boxHeight: 30, // 修改三维场景高度
top: -20,
width: 200,
viewControl: {
// 3d效果可以放大、旋转等,
alpha: 20, // 上下绕X轴角度
beta: 0, //左右绕Y轴角度
// projection: 'perspective',//默认为透视投影'perspective',也支持设置为正交投影'orthographic'
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotateSpeed: 50, //物体自传的速度
autoRotate: false, // 是否自动旋转
distance: 270, // 距离越小看到的饼图越大
},
},
series,
};
return option;
}
// 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
let option = getPie3D(optionData, 0);
myChart.setOption(option);
window.addEventListener("resize", function () {
myChart.resize();
});
},