vue中如何使用echarts和echarts-gl實(shí)現(xiàn)3D餅圖環(huán)形餅圖
效果圖:(移動(dòng)上去也會(huì)有效果的那種哦)


第一步:vue中安裝echarts和echarts-gl
npm install echarts npm install echarts-gl
注意:我不知道版本差異會(huì)不會(huì)有影響(可以指定版本 也可以借鑒我的)

指定版本命令 加個(gè)@后面跟版本號(hào)即可
npm install echarts-gl@2.0.9
成功之后可以在package.json中檢查是否安裝成功(如上圖)
第二步:在vue文件中引入
引入位置:我沒有在main.js中全局引用,而是哪個(gè)頁面用到就引入哪里

代碼:
import * as echarts from 'echarts' import 'echarts-gl';
第三步:實(shí)現(xiàn)具體代碼(完整的)
注意:我沒有封裝起來(你也可以先直接在頁面中實(shí)現(xiàn),然后在考慮封裝需求)
1、有一個(gè)裝餅圖的容器(可以都復(fù)制走 為了成功實(shí)現(xiàn)效果)
<!-- 餅圖 -->
<div class="container">
<div class="chartsGl" id="charts"></div>
<!-- 餅圖下面的底座 -->
<div class="buttomCharts"></div>
</div>
2、對(duì)應(yīng)樣式
//餅圖(外面的容器)
.container {
width: 100%;
height: 100%;
}
//餅圖的大小
.chartsGl {
height: 200px;
width: 400px;
}
//餅圖底座(我也想給你們底座圖片 可是我不知道咋給)
.buttomCharts{
background: center top url(/src/assets/images/bg/buttom-charts.png) no-repeat;
background-size: cover;
height: 78px;
width: 180px;
margin-top: -155px;
margin-left: 18%;
}
3、餅圖數(shù)據(jù)
data() {
return {
//餅圖數(shù)據(jù)+顏色
optionData: [
{
name: '休閑室',//名稱
value: 19,//值
itemStyle: {//顏色 紫色
color: 'rgba(123, 167, 212,1)'
}
}, {
name: '羽毛球室',//藍(lán)色
value: 13,
itemStyle: {
color: 'rgba(98, 195, 250,1)',
}
}, {
name: '瑜伽室',//綠色
value: 15,
itemStyle: {
color: 'rgba(140, 189, 107,1)'
}},
{
name: '動(dòng)感單車室',//橙色
value: 16,
itemStyle: {
color: 'rgba(245, 182, 94,1)'
}}
,
{
name: '兵乓球室',//黃色
value: 5,
itemStyle: {
color: 'rgba(237, 222, 111,1)'
}}
],
}
},
4、鉤子中調(diào)用mouted
mounted() {
this.$nextTick(function() {
this.init();
});
},
5、具體方法methods(為了你也方便修改樣式 我注釋盡量給到)
//初始化構(gòu)建
init() {
//構(gòu)建3d餅狀圖
let myChart = echarts.init(document.getElementById('charts'));
// 傳入數(shù)據(jù)生成 option ; getPie3D(數(shù)據(jù),透明的空心占比(調(diào)節(jié)中間空心范圍的0就是普通餅1就很鏤空))
this.option = this.getPie3D(this.optionData, 0.85);
//將配置項(xiàng)設(shè)置進(jìn)去
myChart.setOption(this.option);
//鼠標(biāo)移動(dòng)上去特效效果
this.bindListen(myChart);
},
//配置構(gòu)建 pieData 餅圖數(shù)據(jù) internalDiameterRatio:透明的空心占比
getPie3D(pieData, internalDiameterRatio) {
let that = this;
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let legendBfb = [];
let k = 1 - internalDiameterRatio;
pieData.sort((a, b) => {
return (b.value - a.value);
});
// 為每一個(gè)餅圖數(shù)據(jù),生成一個(gè) series-surface(參數(shù)曲面) 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
//系統(tǒng)名稱
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
//是否為參數(shù)曲面(是)
parametric: true,
//曲面圖網(wǎng)格線(否)上面一根一根的
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
},
//設(shè)置餅圖在容器中的位置(目前沒發(fā)現(xiàn)啥用)
// center: ['50%', '100%']
};
//曲面的顏色、不透明度等樣式。
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);
}
// 使用上一次遍歷時(shí),計(jì)算出的數(shù)據(jù)和 sumValue,調(diào)用 getParametricEquation 函數(shù),
// 向每個(gè) series-surface 傳入不同的參數(shù)方程 series-surface.parametricEquation,也就是實(shí)現(xiàn)每一個(gè)扇形。
legendData = [];
legendBfb = [];
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 = this.getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
false, false, k, series[i].pieData.value);
startValue = endValue;
let bfb = that.fomatFloat(series[i].pieData.value / sumValue, 4);
legendData.push({
name: series[i].name,
value: bfb
});
legendBfb.push({
name: series[i].name,
value: bfb
});
}
//(第二個(gè)參數(shù)可以設(shè)置你這個(gè)環(huán)形的高低程度)
let boxHeight = this.getHeight3D(series, 13);//通過傳參設(shè)定3d餅/環(huán)的高度
// 準(zhǔn)備待返回的配置項(xiàng),把準(zhǔn)備好的 legendData、series 傳入。
let option = {
//圖例組件
legend: {
data: legendData,
//圖例列表的布局朝向。
orient: 'horizontal',
left: 10,
top: 140,
//圖例文字每項(xiàng)之間的間隔
itemGap: 15,
textStyle: {
color: '#A1E2FF',
},
show: true,
icon: "circle",
//格式化圖例文本(我是數(shù)值什么顯示什么)
formatter: function (name) {
var target;
for (var i = 0, l =pieData.length; i < l; i++) {
if (pieData[i].name == name) {
target = pieData[i].value;
}
}
return `${name}: ${target}`;
}
// 這個(gè)可以顯示百分比那種(可以根據(jù)你想要的來配置)
// formatter: function(param) {
// let item = legendBfb.filter(item => item.name == param)[0];
// let bfs = that.fomatFloat(item.value * 100, 2) + "%";
// console.log(item.name)
// return `${item.name} :${bfs}`;
// }
},
//移動(dòng)上去提示的文本內(nèi)容(我沒來得及改 你們可以根據(jù)需求改)
tooltip: {
formatter: params => {
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
100).toFixed(2);
return `${params.seriesName}<br/>` +
`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
`${ bfb }`;
}
}
},
//這個(gè)可以變形
xAxis3D: {
min: -1,
max: 1
},
yAxis3D: {
min: -1,
max: 1
},
zAxis3D: {
min: -1,
max: 1
},
//此處是修改樣式的重點(diǎn)
grid3D: {
show: false,
boxHeight: boxHeight, //圓環(huán)的高度
//這是餅圖的位置
top: '-20.5%',
left:'-15%',
viewControl: { //3d效果可以放大、旋轉(zhuǎn)等,請(qǐng)自己去查看官方配置
alpha: 30, //角度(這個(gè)很重要 調(diào)節(jié)角度的)
distance: 200,//調(diào)整視角到主體的距離,類似調(diào)整zoom(這是整體大小)
rotateSensitivity: 0, //設(shè)置為0無法旋轉(zhuǎn)
zoomSensitivity: 0, //設(shè)置為0無法縮放
panSensitivity: 0, //設(shè)置為0無法平移
autoRotate: false //自動(dòng)旋轉(zhuǎn)
}
},
series: series
};
return option;
},
//獲取3d丙圖的最高扇區(qū)的高度
getHeight3D(series, height) {
series.sort((a, b) => {
return (b.pieData.value - a.pieData.value);
})
return height * 25 / series[0].pieData.value;
},
// 生成扇形的曲面參數(shù)方程,用于 series-surface.parametricEquation
getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
// 計(jì)算
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
// 如果只有一個(gè)扇形,則不實(shí)現(xiàn)選中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
// 通過扇形內(nèi)徑/外徑的值,換算出輔助參數(shù) k(默認(rèn)值 1/3)
k = typeof k !== 'undefined' ? k : 1 / 3;
// 計(jì)算選中效果分別在 x 軸、y 軸方向上的位移(未選中,則位移均為 0)
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 計(jì)算高亮效果的放大比例(未高亮,則比例為 1)
let 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: 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 * .1;
}
return Math.sin(v) > 0 ? 1 * h * .1 : -1;
}
};
},
//這是一個(gè)自定義計(jì)算的方法
fomatFloat(num, n) {
var f = parseFloat(num);
if (isNaN(f)) {
return false;
}
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 冪
var s = f.toString();
var rs = s.indexOf('.');
//判定如果是整數(shù),增加小數(shù)點(diǎn)再補(bǔ)0
if (rs < 0) {
rs = s.length;
s += '.';
}
while (s.length <= rs + n) {
s += '0';
}
return s;
},
// 監(jiān)聽鼠標(biāo)事件,實(shí)現(xiàn)餅圖選中效果(單選),近似實(shí)現(xiàn)高亮(放大)效果。
bindListen(myChart) {
let that = this;
let selectedIndex = '';
let hoveredIndex = '';
// 監(jiān)聽點(diǎn)擊事件,實(shí)現(xiàn)選中效果(單選)
myChart.on('click', function(params) {
// 從 option.series 中讀取重新渲染扇形所需的參數(shù),將是否選中取反。
let isSelected = !that.option.series[params.seriesIndex].pieStatus.selected;
let isHovered = that.option.series[params.seriesIndex].pieStatus.hovered;
let k = that.option.series[params.seriesIndex].pieStatus.k;
let startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
let endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
// 如果之前選中過其他扇形,將其取消選中(對(duì) option 更新)
if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
that.option.series[selectedIndex].parametricEquation = that.getParametricEquation(that.option.series[
selectedIndex].pieData
.startRatio, that.option.series[selectedIndex].pieData.endRatio, false, false, k, that.option.series[
selectedIndex].pieData
.value);
that.option.series[selectedIndex].pieStatus.selected = false;
}
// 對(duì)當(dāng)前點(diǎn)擊的扇形,執(zhí)行選中/取消選中操作(對(duì) option 更新)
that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[params.seriesIndex].pieData.value);
that.option.series[params.seriesIndex].pieStatus.selected = isSelected;
// 如果本次是選中操作,記錄上次選中的扇形對(duì)應(yīng)的系列號(hào) seriesIndex
isSelected ? selectedIndex = params.seriesIndex : null;
// 使用更新后的 option,渲染圖表
myChart.setOption(that.option);
});
// 監(jiān)聽 mouseover,近似實(shí)現(xiàn)高亮(放大)效果
myChart.on('mouseover', function(params) {
// 準(zhǔn)備重新渲染扇形所需的參數(shù)
let isSelected;
let isHovered;
let startRatio;
let endRatio;
let k;
// 如果觸發(fā) mouseover 的扇形當(dāng)前已高亮,則不做操作
if (hoveredIndex === params.seriesIndex) {
return;
// 否則進(jìn)行高亮及必要的取消高亮操作
} else {
// 如果當(dāng)前有高亮的扇形,取消其高亮狀態(tài)(對(duì) option 更新)
if (hoveredIndex !== '') {
// 從 option.series 中讀取重新渲染扇形所需的參數(shù),將是否高亮設(shè)置為 false。
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
isHovered = false;
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
k = that.option.series[hoveredIndex].pieStatus.k;
// 對(duì)當(dāng)前點(diǎn)擊的扇形,執(zhí)行取消高亮操作(對(duì) option 更新)
that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[hoveredIndex].pieData.value);
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
// 將此前記錄的上次選中的扇形對(duì)應(yīng)的系列號(hào) seriesIndex 清空
hoveredIndex = '';
}
// 如果觸發(fā) mouseover 的扇形不是透明圓環(huán),將其高亮(對(duì) option 更新)
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
// 從 option.series 中讀取重新渲染扇形所需的參數(shù),將是否高亮設(shè)置為 true。
isSelected = that.option.series[params.seriesIndex].pieStatus.selected;
isHovered = true;
startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
k = that.option.series[params.seriesIndex].pieStatus.k;
// 對(duì)當(dāng)前點(diǎn)擊的扇形,執(zhí)行高亮操作(對(duì) option 更新)
that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected, isHovered, k, that.option.series[params.seriesIndex].pieData.value + 5);
that.option.series[params.seriesIndex].pieStatus.hovered = isHovered;
// 記錄上次高亮的扇形對(duì)應(yīng)的系列號(hào) seriesIndex
hoveredIndex = params.seriesIndex;
}
// 使用更新后的 option,渲染圖表
myChart.setOption(that.option);
}
});
// 修正取消高亮失敗的 bug
myChart.on('globalout', function() {
// 準(zhǔn)備重新渲染扇形所需的參數(shù)
let isSelected;
let isHovered;
let startRatio;
let endRatio;
let k;
if (hoveredIndex !== '') {
// 從 option.series 中讀取重新渲染扇形所需的參數(shù),將是否高亮設(shè)置為 true。
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
isHovered = false;
k = that.option.series[hoveredIndex].pieStatus.k;
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
// 對(duì)當(dāng)前點(diǎn)擊的扇形,執(zhí)行取消高亮操作(對(duì) option 更新)
that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[hoveredIndex].pieData.value);
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
// 將此前記錄的上次選中的扇形對(duì)應(yīng)的系列號(hào) seriesIndex 清空
hoveredIndex = '';
}
// 使用更新后的 option,渲染圖表
myChart.setOption(that.option);
});
}
}
第四:我想說一下注意事項(xiàng)哈
1、因?yàn)檫@些代碼比較復(fù)雜(我看不懂 只是盡量把配置樣式相關(guān)給了一下注解 希望有幫助)
2、一開始只想實(shí)現(xiàn)效果的(不要先封裝成組件 很可能會(huì)失敗 先在要實(shí)現(xiàn)的頁面寫)
3、gl 3d相關(guān)的配置可以在官方文檔上查看理解 (下面附贈(zèng)鏈接)
https://echarts.apache.org/zh/option-gl.html#globe

4、在提供給你們一個(gè)echarts圖集表(挺全的很多案例參考)https://www.isqqw.com/

總結(jié)
到此這篇關(guān)于vue中如何使用echarts和echarts-gl實(shí)現(xiàn)3D餅圖環(huán)形餅圖的文章就介紹到這了,更多相關(guān)vue實(shí)現(xiàn)3D餅圖環(huán)形餅圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決vue 格式化銀行卡(信用卡)每4位一個(gè)符號(hào)隔斷的問題
這篇文章主要介紹了vue 格式化銀行卡(信用卡)每4位一個(gè)符號(hào)隔斷的問題,本文給大家分享了解決方法,需要的朋友可以參考下2018-09-09
Vue-cli項(xiàng)目部署到Nginx服務(wù)器的方法
這篇文章主要介紹了Vue-cli項(xiàng)目部署到Nginx服務(wù)器的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
Vue-cli Eslint在vscode里代碼自動(dòng)格式化的方法
本篇文章主要介紹了Vue-cli Eslint在vscode里代碼自動(dòng)格式化的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02
Vue+Microapp實(shí)現(xiàn)微前端的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何實(shí)現(xiàn)以vite+vue3+Microapp為主應(yīng)用,以vue2+element為子應(yīng)用的微前端,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2023-06-06
vue 路由守衛(wèi)(導(dǎo)航守衛(wèi))及其具體使用
這篇文章主要介紹了vue 路由守衛(wèi)(導(dǎo)航守衛(wèi))及其具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Vuejs如何通過Axios請(qǐng)求數(shù)據(jù)
這篇文章主要介紹了Vuejs如何通過Axios請(qǐng)求數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04

