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運營管控團(tuán)隊", value: 1000, itemStyle: { color: "#dd4b3d", }, }, { name: "業(yè)務(wù)支撐團(tuán)隊", value: 600, itemStyle: { color: "#dd9c3c", }, }, { name: "計費結(jié)算團(tuán)隊", value: 900, itemStyle: { color: "#f6bb50", }, }, { name: "數(shù)據(jù)應(yīng)用運營團(tuán)隊", value: 800, itemStyle: { color: "#5ec7f8", }, }, { name: "Paas組件運營團(tuán)隊", value: 400, itemStyle: { color: "#31dda1", }, }, { name: "云數(shù)安全團(tuán)隊", 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; // 如果只有一個扇形,則不實現(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 餅圖的配置項 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ū)是否是順時針排布。上述這兩項配置主要是為了對齊3d的樣式 radius: ["50%", "60%"], center: ["62%", "50%"], data: optionsData, itemStyle: { opacity: 0, }, }); // 準(zhǔn)備待返回的配置項,把準(zhǔn)備好的 legendData、series 傳入。 const option = { legend: { show: true, // 顯示圖例 tooltip: { show: true, // 顯示圖例的提示信息 }, orient: "vertical", // 圖例的排列方向 data: ["IT運營管控團(tuán)隊", "業(yè)務(wù)支撐團(tuán)隊", "計費結(jié)算團(tuán)隊", "數(shù)據(jù)應(yīng)用運營團(tuán)隊", "Paas組件運營團(tuán)隊", '云數(shù)安全團(tuán)隊'], // 圖例的內(nèi)容 top: 20, // 圖例距離頂部的距離 itemGap: 10, // 圖例項之間的間距 itemHeight: 20, // 圖例項的高度 itemWidth: 24, // 圖例項的寬度 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) { // 格式化圖例項的顯示內(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ù)值(未賦值需補充) "{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}\nvvxyksv9kd%", // 標(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)隊概況 </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ù)器的壓力和帶寬費用等)。2010-04-04js數(shù)字轉(zhuǎn)中文兩種實現(xiàn)方法
在前端開發(fā)中有時候會需要到將阿拉伯?dāng)?shù)字轉(zhuǎn)化為中文,當(dāng)前做個記錄,提供自己之后翻閱,這篇文章主要給大家介紹了關(guān)于js數(shù)字轉(zhuǎn)中文兩種實現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2023-10-10JavaScript 數(shù)組去重并統(tǒng)計重復(fù)元素出現(xiàn)的次數(shù)實例
下面小編就為大家分享一篇JavaScript 數(shù)組去重并統(tǒng)計重復(fù)元素出現(xiàn)的次數(shù)實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12javascript 最常用的10個自定義函數(shù)[推薦]
如果不使用類庫或者沒有自己的類庫,儲備一些常用函數(shù)總是有好處的。2009-12-12offsetHeight在OnLoad中獲取為0的現(xiàn)象
需要獲取div的高度時,往往需要用到offsetHeight,有時會碰到offsetHeight獲取到為0的現(xiàn)象,感興趣的朋友可以參考下面的代碼片段2013-07-07深入理解基于vue-cli的webpack打包優(yōu)化實踐及探索
這篇文章主要介紹了基于vue-cli的webpack打包優(yōu)化實踐及探索,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10