React中如何使用echarts寫出3d旋轉(zhuǎn)扇形圖
效果

技術(shù)
React + TypeScript + Less + Echarts
代碼塊
import * as echarts from "echarts";
import React, { useEffect, useRef } from "react";
import "echarts-gl";
import "./index.less";
const LeftEcharts = () => {
const chartDom = useRef(null);
useEffect(() => {
const myChart = echarts.init(chartDom.current);
// 數(shù)據(jù)源
const optionsData: any = [
{
name: "IT運(yùn)營管控團(tuán)隊(duì)",
value: 1000,
itemStyle: {
color: "#dd4b3d",
},
},
{
name: "業(yè)務(wù)支撐團(tuán)隊(duì)",
value: 600,
itemStyle: {
color: "#dd9c3c",
},
},
{
name: "計費(fèi)結(jié)算團(tuán)隊(duì)",
value: 900,
itemStyle: {
color: "#f6bb50",
},
},
{
name: "數(shù)據(jù)應(yīng)用運(yùn)營團(tuán)隊(duì)",
value: 800,
itemStyle: {
color: "#5ec7f8",
},
},
{
name: "Paas組件運(yùn)營團(tuán)隊(duì)",
value: 400,
itemStyle: {
color: "#31dda1",
},
},
{
name: "云數(shù)安全團(tuán)隊(duì)",
value: 300,
itemStyle: {
color: "#637aff",
},
},
];
// 生成扇形的曲面參數(shù)方程,用于 series-surface.parametricEquation
function 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;
// 如果只有一個扇形,則不實(shí)現(xiàn)選中效果。
// if (startRatio === 0 && endRatio === 1) {
// isSelected = false;
// }
isSelected = false;
// 通過扇形內(nèi)徑/外徑的值,換算出輔助參數(shù) k(默認(rèn)值 1/3)
k = typeof k !== "undefined" ? k : 1 / 3;
// 計算選中效果分別在 x 軸、y 軸方向上的位移(未選中,則位移均為 0)
let offsetX = isSelected ? Math.sin(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.cos(midRadian) * 0.1 : 0;
// 計算高亮效果的放大比例(未高亮,則比例為 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 * 0.1;
}
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
},
};
}
// 生成模擬 3D 餅圖的配置項(xiàng)
function getPie3D(pieData: any, internalDiameterRatio) {
let series: any = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData: any = [];
let k =
typeof internalDiameterRatio !== "undefined"
? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
: 1 / 3;
// 為每一個餅圖數(shù)據(jù),生成一個 series-surface 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem: any = {
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: 1 / 10,
},
};
if (typeof pieData[i].itemStyle != "undefined") {
let itemStyle: any = {};
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);
}
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 = getParametricEquation(
series[i].pieData.startRatio,
series[i].pieData.endRatio,
false,
false,
k,
series[i].pieData.value
);
startValue = endValue;
legendData.push(series[i].name);
}
return series;
}
const series: any = getPie3D(optionsData, 0.6);
series.push({
name: "pie2d",
type: "pie",
label: {
opacity: 1,
fontSize: 14,
lineHeight: 20,
textStyle: {
fontSize: 14,
color: "#fff",
},
show: false,
position: "center",
},
labelLine: {
length: 10,
length2: 10,
show: false,
},
startAngle: 2, //起始角度,支持范圍[0, 360]。
clockwise: false, //餅圖的扇區(qū)是否是順時針排布。上述這兩項(xiàng)配置主要是為了對齊3d的樣式
radius: ["50%", "60%"],
center: ["62%", "50%"],
data: optionsData,
itemStyle: {
opacity: 0,
},
});
// 準(zhǔn)備待返回的配置項(xiàng),把準(zhǔn)備好的 legendData、series 傳入。
const option = {
legend: {
show: true, // 顯示圖例
tooltip: {
show: true, // 顯示圖例的提示信息
},
orient: "vertical", // 圖例的排列方向
data: ["IT運(yùn)營管控團(tuán)隊(duì)", "業(yè)務(wù)支撐團(tuán)隊(duì)", "計費(fèi)結(jié)算團(tuán)隊(duì)", "數(shù)據(jù)應(yīng)用運(yùn)營團(tuán)隊(duì)", "Paas組件運(yùn)營團(tuán)隊(duì)", '云數(shù)安全團(tuán)隊(duì)'], // 圖例的內(nèi)容
top: 20, // 圖例距離頂部的距離
itemGap: 10, // 圖例項(xiàng)之間的間距
itemHeight: 20, // 圖例項(xiàng)的高度
itemWidth: 24, // 圖例項(xiàng)的寬度
right: "5%", // 圖例距離右邊的距離
textStyle: { // 圖例的文本樣式
color: "#fff", // 文本顏色
fontSize: 10, // 文本字體大小
rich: {
name: {
width: 60, // 名稱部分的寬度
fontSize: 14, // 名稱部分字體大小
color: "#B0D8DF", // 名稱部分顏色
fontFamily: "Source Han Sans CN", // 名稱部分字體
},
value: {
width: 50, // 數(shù)值部分的寬度
fontSize: 4, // 數(shù)值部分字體大小
padding: [0, 5, 0, 5], // 數(shù)值部分的內(nèi)邊距
color: "#fff", // 數(shù)值部分顏色
fontFamily: "Source Han Sans CN", // 數(shù)值部分字體
},
A: {
fontSize: 20, // A部分的字體大小
color: "#B0D8DF", // A部分顏色
fontFamily: "Source Han Sans CN", // A部分字體
},
rate: {
width: 60, // 比率部分的寬度
fontSize: 14, // 比率部分字體大小
padding: [0, 5, 0, 10], // 比率部分的內(nèi)邊距
color: "#579ed2", // 比率部分顏色
fontFamily: "Source Han Sans CN", // 比率部分字體
},
},
},
formatter: function (name) { // 格式化圖例項(xiàng)的顯示內(nèi)容
let total = 0; // 總值
let target; // 目標(biāo)值
for (let i = 0; i < optionsData.length; i++) {
total += optionsData[i].value; // 計算總值
if (optionsData[i].name === name) { // 查找目標(biāo)值
target = optionsData[i].value;
}
}
let arr = [
"{name|" + name + "}", // 名稱
"{value|" + "}", // 數(shù)值(未賦值需補(bǔ)充)
"{rate|" + ((target / total) * 100).toFixed(1) + "%}", // 比率
];
return arr.join(""); // 返回格式化后的字符串
},
},
animation: true, // 開啟動畫效果
tooltip: {
backgroundColor: "rgba(64, 180, 176, 0.6)", // 提示框的背景顏色
borderColor: "rgba(64, 180, 176, 0.6)", // 提示框的邊框顏色
textStyle: {
color: "#fff", // 提示文本顏色
fontSize: 24, // 提示文本字體大小
},
formatter: (params) => { // 格式化提示框內(nèi)容
if (
params.seriesName !== "mouseoutSeries" &&
params.seriesName !== "pie2d" // 排除特定系列
) {
return `${params.seriesName
}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color
};"></span>${option.series[params.seriesIndex].pieData.value + "萬人"
}`; // 返回系列名稱和數(shù)值
}
},
},
labelLine: {
show: true, // 顯示標(biāo)簽連接線
lineStyle: {
color: "#7BC0CB", // 標(biāo)簽連接線顏色
},
normal: {
show: true, // 正常狀態(tài)顯示
length: 10, // 連接線長度
length2: 10, // 連接線第二段長度
},
},
label: {
show: true, // 顯示標(biāo)簽
position: "outside", // 標(biāo)簽位置
formatter: " \n{c}\nywm4kq6%", // 標(biāo)簽格式
textStyle: {
color: "rgba(176, 216, 223, 1)", // 標(biāo)簽文本顏色
fontSize: 24, // 標(biāo)簽字體大小
},
},
xAxis3D: {
min: -1, // x軸最小值
max: 1, // x軸最大值
},
yAxis3D: {
min: -1, // y軸最小值
max: 1, // y軸最大值
},
zAxis3D: {
min: -1, // z軸最小值
max: 1, // z軸最大值
},
grid3D: {
show: false, // 是否顯示3D網(wǎng)格
boxHeight: 1, // 3D盒子的高度
left: -40, // 3D圖形左邊距
top: -10, // 3D圖形頂部邊距
width: "50%", // 3D圖形寬度
viewControl: {
distance: 280, // 視距
alpha: 20, // 視角的俯仰角
beta: 15, // 視角的旋轉(zhuǎn)角
autoRotate: true, // 是否自動旋轉(zhuǎn)
rotateSensitivity: 1, // 旋轉(zhuǎn)靈敏度
zoomSensitivity: 0, // 縮放靈敏度
panSensitivity: 0, // 平移靈敏度
},
},
series: series, // 數(shù)據(jù)系列
};
myChart.setOption(option);
}, []);
return (
<div className='left-echarts'>
<div className='left-top-nav'>
團(tuán)隊(duì)概況
</div>
<div style={{ width: "496px", height: "270px", position: "relative" }}>
<div ref={chartDom} style={{ width: "100%", height: "100%", zIndex: "5" }}></div>
<div className="bg"></div>
</div>
</div>
);
};
export default LeftEcharts;總結(jié)
到此這篇關(guān)于React中如何使用echarts寫出3d旋轉(zhuǎn)扇形圖的文章就介紹到這了,更多相關(guān)React echarts寫3d旋轉(zhuǎn)扇形圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的區(qū)別和應(yīng)用場景簡述
隨著web2.0的彪悍發(fā)展,以及瀏覽器端所承載的工作越來越大(在不是很影響性能的情況下,開發(fā)者都習(xí)慣把能用瀏覽器做的事兒都讓瀏覽器做,以減輕服務(wù)器的壓力和帶寬費(fèi)用等)。2010-04-04
js數(shù)字轉(zhuǎn)中文兩種實(shí)現(xiàn)方法
在前端開發(fā)中有時候會需要到將阿拉伯?dāng)?shù)字轉(zhuǎn)化為中文,當(dāng)前做個記錄,提供自己之后翻閱,這篇文章主要給大家介紹了關(guān)于js數(shù)字轉(zhuǎn)中文兩種實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2023-10-10
JS實(shí)現(xiàn)可視化音頻效果的實(shí)例代碼
這篇文章主要介紹了JS實(shí)現(xiàn)可視化音頻效果的實(shí)例代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01
JavaScript 數(shù)組去重并統(tǒng)計重復(fù)元素出現(xiàn)的次數(shù)實(shí)例
下面小編就為大家分享一篇JavaScript 數(shù)組去重并統(tǒng)計重復(fù)元素出現(xiàn)的次數(shù)實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
javascript 最常用的10個自定義函數(shù)[推薦]
如果不使用類庫或者沒有自己的類庫,儲備一些常用函數(shù)總是有好處的。2009-12-12
offsetHeight在OnLoad中獲取為0的現(xiàn)象
需要獲取div的高度時,往往需要用到offsetHeight,有時會碰到offsetHeight獲取到為0的現(xiàn)象,感興趣的朋友可以參考下面的代碼片段2013-07-07
深入理解基于vue-cli的webpack打包優(yōu)化實(shí)踐及探索
這篇文章主要介紹了基于vue-cli的webpack打包優(yōu)化實(shí)踐及探索,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10

