立体旋转饼图

描述:当前是关于Echarts图表中的 饼图 示例。
 
            
/**
 * 需要引入扩展资源 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)