1、需要安裝
import * as echarts from 'echarts'
import 'echarts-gl'
2、使用方法
/**
* 需要引入擴(kuò)展資源 https://cdn.jsdelivr.net/npm/echarts-gl@2/dist/echarts-gl.min.js
* 實(shí)際項(xiàng)目中需要安裝【echarts-gl】插件
* (vue)使用中引入 import "echarts-gl";
*/
/**
* getParametricEquation 生成扇形的曲面參數(shù)方程 生成 3D 扇形環(huán)曲面
* @param{} startRatio(浮點(diǎn)數(shù)): 當(dāng)前扇形起始比例,取值區(qū)間 [0, endRatio)
* @param{} endRatio(浮點(diǎn)數(shù)): 當(dāng)前扇形結(jié)束比例,取值區(qū)間 (startRatio, 1]
* @param{} isSelected(布爾值):是否選中,效果參照二維餅圖選中效果(單選)
* @param{} isHovered(布爾值): 是否放大,效果接近二維餅圖高亮(放大)效果(未能實(shí)現(xiàn)陰影)
* @param{} k(0~1之間的浮點(diǎn)數(shù)):用于參數(shù)方程的一個(gè)參數(shù),取值 0~1 之間,通過「內(nèi)徑/外徑」的值換算而來。
* @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;
// 如果只有一個(gè)扇形,則不實(shí)現(xiàn)選中效果。
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;
// 鼠標(biāo)滑過時(shí)外環(huán)放大大小
const hoverRate = isHovered ? 1.05 : 1;
// 返回曲面參數(shù)方程
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; }
// 當(dāng)前圖形的高度是Z根據(jù)h(每個(gè)value的值決定的)
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
}
};
}
// 餅圖數(shù)據(jù)
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 }
];
// 可做為調(diào)整內(nèi)環(huán)大小 0為實(shí)心圓餅圖,大于0 小于1 為圓環(huán)
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);
}
// 準(zhǔn)備待返回的配置項(xiàng),把準(zhǔn)備好的series 傳入。
const option = {
backgroundColor: "#123756",
title: {
text: "立體旋轉(zhuǎn)餅圖/環(huán)圖",
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效果可以放大、旋轉(zhuǎn)等,
alpha: 20, // 餅圖翻轉(zhuǎn)的程度
beta: 30,
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotate: true, // 是否自動(dòng)旋轉(zhuǎn)
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
// 如果只有一個(gè)扇形,則不實(shí)現(xiàn)選中效果。
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
// 鼠標(biāo)滑過時(shí)外環(huán)放大大小
const hoverRate = isHovered ? 1.05 : 1
// 返回曲面參數(shù)方程
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
}
// 當(dāng)前圖形的高度是Z根據(jù)h(每個(gè)value的值決定的)
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1
}
}
}
// 餅圖數(shù)據(jù)
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)
}
// 準(zhǔn)備待返回的配置項(xiàng),把準(zhǔn)備好的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 類型 標(biāo)記類型包括 'circle'圓, 'rect'方, 'roundRect'圓角, 'triangle'三角形, 'diamond'lin, 'arrow'箭頭, 'pin', 'arrow', 'none'
itemHeight: 12, // icon高度
itemWidth: 12, // icon 寬度
itemGap: 10, // 圖例間隔 --每個(gè)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
}
}
}
},
// 每一塊區(qū)域的顏色
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效果可以放大、旋轉(zhuǎn)等,
alpha: 40, // 餅圖翻轉(zhuǎn)的程度
beta: 30,
// projection: 'perspective',//默認(rèn)為透視投影'perspective',也支持設(shè)置為正交投影'orthographic'
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotateSpeed: 50, //物體自傳的速度
autoRotate: true, // 是否自動(dòng)旋轉(zhuǎn)
distance: 350 // 距離越小看到的餅圖越大
}
},
series
}
return option
}
// 可做為調(diào)整內(nèi)環(huán)大小 0為實(shí)心圓餅圖,大于0 小于1 為圓環(huán)
let option = getPie3D(optionData, 0)
myChart.setOption(option)
// 讓圖表自適應(yīng)容器大小
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>
效果圖:文章來源:http://www.zghlxwxcb.cn/news/detail-810050.html
需要底座背景圖自取文章來源地址http://www.zghlxwxcb.cn/news/detail-810050.html
到了這里,關(guān)于echarts的3D餅圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!