1、需要安装
import * as echarts from 'echarts'
import 'echarts-gl'
2、使用方法
/**
* 需要引入扩展资源 https://cdn.jsdelivr.net/npm/echarts-gl@2/dist/echarts-gl.min.js
* 实际项目中需要安装【echarts-gl】插件
* (vue)使用中引入 import "echarts-gl";
*/
/**
* getParametricEquation 生成扇形的曲面参数方程 生成 3D 扇形环曲面
* @param{} startRatio(浮点数): 当前扇形起始比例,取值区间 [0, endRatio)
* @param{} endRatio(浮点数): 当前扇形结束比例,取值区间 (startRatio, 1]
* @param{} isSelected(布尔值):是否选中,效果参照二维饼图选中效果(单选)
* @param{} isHovered(布尔值): 是否放大,效果接近二维饼图高亮(放大)效果(未能实现阴影)
* @param{} k(0~1之间的浮点数):用于参数方程的一个参数,取值 0~1 之间,通过「内径/外径」的值换算而来。
* @param{} h :饼图的初始高度
*/
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: 60 },
{ name: "冻品", value: 44 },
{ name: "粮食", value: 24 },
{ name: "日化1", value: 60 },
{ name: "冻品1", value: 44 },
{ name: "粮食1", value: 24 },
{ name: "日化2", value: 60 },
{ name: "冻品2", value: 44 },
{ name: "粮食2", value: 24 }
];
// 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
function getPie3D(pieData, internalDiameterRatio) {
const series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
const legendData = [];
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,
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.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,
false,
k,
10 // 在此处传入饼图初始高度h
);
startValue = endValue;
legendData.push(series[i].name);
}
// 准备待返回的配置项,把准备好的series 传入。
const option = {
backgroundColor: "#123756",
title: {
text: "立体旋转饼图/环图",
top: "1%",
textAlign: "left",
left: "1%",
textStyle: {
color: "#38adb9",
fontSize: 32,
fontWeight: "600"
}
},
legend: {
show: true,
type: "scroll",
right: 10,
top: 10,
orient: "vertical", // 纵向
icon: "circle", // icon 类型
itemHeight: 12, // icon高度
itemWidth: 12, // icon 宽度
itemGap: 5, // 图例间隔
textStyle: {
color: "#709DD9",
fontSize: 12,
fontWeight: "400"
},
formatter: name => {
if (pieData.length) {
const item = pieData.filter(item => item.name === name)[0];
return ` ${name}:${item.value}`;
}
}
},
color: ["#159AFF", "#66E1DF", "#66E193", "#E3F170", "#FFAD6A", "#ffe0ab", "#6bc5f4", "#c08ef2", "#ffda49"],
tooltip: {
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: 15, // 修改立体饼图的高度
top: "-10%",
left: "0%",
viewControl: {
// 3d效果可以放大、旋转等,
alpha: 20, // 饼图翻转的程度
beta: 30,
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotate: true, // 是否自动旋转
distance: 300 // 距离越小看到的饼图越大
}
},
series
};
return option;
}
option = getPie3D(optionData, 0)
3、案例
<template>
<!-- 病种分类 -->
<div class="age_distribution">
<div class="title">{{ title }}</div>
<div id="age"></div>
<div class="bg"></div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import 'echarts-gl'
export default {
props: ['title'],
data() {
return {}
},
mounted() {
this.getPeople()
},
methods: {
// 折线图
getPeople() {
var myChart = echarts.init(document.getElementById('age'))
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: '18岁以下', value: 7140 },
{ name: '19-30岁', value: 8991 },
{ name: '31-40岁', value: 37455 },
{ name: '41-50岁', value: 25490 },
{ name: '51-60岁', value: 7161 }
]
function getPie3D(pieData, internalDiameterRatio) {
const series = []
let sumValue = 0
let startValue = 0
let endValue = 0
const legendData = []
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,
false,
k,
10 // 在此处传入饼图初始高度h
)
startValue = endValue
legendData.push(series[i].name)
}
// 准备待返回的配置项,把准备好的series 传入。
const option = {
// backgroundColor: '#123756',
title: {
show: false
// text: '',
// top: '1%',
// textAlign: 'left',
// left: '1%',
// textStyle: {
// color: '#38adb9',
// fontSize: 32,
// fontWeight: '600'
// }
},
// 右边提示文本
legend: {
show: true,
type: 'scroll',
right: 50,
top: 60,
orient: 'vertical', // 纵向
icon: 'rect', // icon 类型 标记类型包括 'circle'圆, 'rect'方, 'roundRect'圆角, 'triangle'三角形, 'diamond'lin, 'arrow'箭头, 'pin', 'arrow', 'none'
itemHeight: 12, // icon高度
itemWidth: 12, // icon 宽度
itemGap: 10, // 图例间隔 --每个title之间的间隔
data: legendData,
textStyle: {
color: '#709DD9',
fontSize: 12,
fontWeight: '400'
},
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}人}`]
return arr
// return `${name}:${item.value}`
}
},
textStyle: {
rich: {
//改样式 和下面formatter一起
a: {
color: '#fff',
fontSize: 12 // 字体大小被覆盖了,这里重新定义
},
b: {
color: '#59e6ed',
fontSize: 12
}
}
}
},
// 每一块区域的颜色
color: ['#9f76f2', '#2a9dff', '#fac924', '#5ce5ff', '#6573f3'],
tooltip: {
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: 25, // 修改立体饼图的高度
top: '5%',
left: '-15%',
viewControl: {
// 3d效果可以放大、旋转等,
alpha: 40, // 饼图翻转的程度
beta: 30,
// projection: 'perspective',//默认为透视投影'perspective',也支持设置为正交投影'orthographic'
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotateSpeed: 50, //物体自传的速度
autoRotate: true, // 是否自动旋转
distance: 350 // 距离越小看到的饼图越大
}
},
series
}
return option
}
// 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
let option = getPie3D(optionData, 0)
myChart.setOption(option)
// 让图表自适应容器大小
window.addEventListener('resize', function () {
myChart.resize()
})
}
}
}
</script>
<style lang="less" scoped>
.age_distribution {
position: relative;
width: 100%;
height: 100%;
background-image: url('../../assets/box_card.png');
background-repeat: no-repeat;
background-size: 100% 100%;
.title {
position: absolute;
top: -7px;
left: 50%;
transform: translateX(-50%);
font-size: 17px;
font-family: PingFang SC, PingFang SC;
color: #ffffff;
letter-spacing: 2px;
}
#age {
z-index: 3;
width: 100%;
height: 100%;
}
.bg {
z-index: 2;
position: absolute;
background-image: url('../../assets/bottom_img_age.png');
top: 9%;
left: 10%;
background-size: 100% 100%;
width: 50%;
height: 84%;
}
}
</style>
效果图:
文章来源:https://www.toymoban.com/news/detail-810050.html
需要底座背景图自取
文章来源地址https://www.toymoban.com/news/detail-810050.html
到了这里,关于echarts的3D饼图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!