3D环形图

描述:当前是关于Echarts图表中的 饼图 示例。
 
            function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k) {
   // 计算
   let midRatio = (startRatio + endRatio) / 2;

   let startRadian = startRatio * Math.PI * 2;
   let endRadian = endRatio * Math.PI * 2;
   let midRadian = midRatio * Math.PI * 2;

   // 如果只有一个扇形,则不实现选中效果。
   if (startRatio === 0 && endRatio === 1) {
      isSelected = false;
   }

   // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
   k = typeof k !== 'undefined' ? k : 1 / 3;

   // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
   let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
   let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;

   // 计算高亮效果的放大比例(未高亮,则比例为 1)
   let 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: 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);
         }
         return Math.sin(v) > 0 ? 1 : -1;
      },
   };
}

// 生成模拟 3D 饼图的配置项
function getPie3D(pieData, internalDiameterRatio) {
   let series = [];
   let sumValue = 0;
   let startValue = 0;
   let endValue = 0;
   let legendData = [];
   let k = typeof internalDiameterRatio !== 'undefined' ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 5;

   // 为每一个饼图数据,生成一个 series-surface 配置
   for (let i = 0; i < pieData.length; i++) {
      sumValue += pieData[i].value;

      let 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: k,
         },
      };

      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);
   }

   // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
   // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
   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, true, false, 0.25);

      startValue = endValue;

      legendData.push(series[i].name);
   }

   // 补充一个透明的圆环,用于支撑高亮功能的近似实现。
   series.push({
      name: 'mouseoutSeries',
      type: 'surface',
      parametric: true,
      wireframe: {
         show: false,
      },
      clockwise: false,
      itemStyle: {
         opacity: 0,
         color: 'rgba(18,236,252,.2)',
      },
      parametricEquation: {
         u: {
            min: 0,
            max: Math.PI * 2,
            step: Math.PI / 20,
         },
         v: {
            min: 0,
            max: Math.PI,
            step: Math.PI / 1.4,
         },
         x: function (u, v) {
            return Math.sin(v) * Math.sin(u) + Math.sin(u);
         },
         y: function (u, v) {
            return Math.sin(v) * Math.cos(u) + Math.cos(u);
         },
         z: function (u, v) {
            return Math.cos(v) > 0 ? 0.1 : -0.1;
         },
      },
   });

   // 准备待返回的配置项,把准备好的 legendData、series 传入。
   option = {
      //animation: false,
      legend: [
         {
            data: [
               {
                  name: '充换电',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '20%',
            left: '45%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '用户侧储能',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '20%',
            left: '70%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '数据中心',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '40%',
            left: '45%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '楼宇空调',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '40%',
            left: '70%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '分布式三联供',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '60%',
            left: '45%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '非连续生产',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '60%',
            left: '70%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
         {
            data: [
               {
                  name: '其他',
                  icon: 'rect',
               },
            ],
            itemWidth: 20,
            itemHeight: 20,
            top: '80%',
            left: '45%',
            textStyle: {
               color: '#fff',
               fontSize: 20,
            },
         },
      ],
      backgroundColor: "#111",
      xAxis3D: {
         min: -1,
         max: 1,
      },
      yAxis3D: {
         min: -1,
         max: 1,
      },
      zAxis3D: {
         min: -1,
         max: 1,
      },
      grid3D: {
         show: false,
         boxHeight: 10,
         left: "-10%",
         bottom: '50%',
         viewControl: {
            //3d效果可以放大、旋转等,请自己去查看官方配置
            alpha: 45,
            // beta: 40,
            rotateSensitivity: 0,
            zoomSensitivity: 0,
            panSensitivity: 0,
            autoRotate: false,
            //   autoRotateSpeed: 5,
            //   autoRotateAfterStill: 10
         },
      },
      series: series,
   };
   return option;
}

// 传入数据生成 option
option = getPie3D(
   [
      {
         name: '充换电',
         value: 30.16,
         itemStyle: {
            color: '#25a6ff',
         },
      },
      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '用户侧储能',
         value: 6.05,
         itemStyle: {
            color: '#70d69f',
         },
      },

      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '数据中心',
         value: 2.43,
         itemStyle: {
            color: '#ffb619',
         },
      },
      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '楼宇空调',
         value: 14.86,
         itemStyle: {
            color: '#ffe65c',
         },
      },
      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '分布式三联供',
         value: 8.17,
         itemStyle: {
            color: '#ff7552',
         },
      },

      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '非连续生产',
         value: 19.48,
         itemStyle: {
            color: '#ffb619',
         },
      },
      {
         value: 0.4,
         itemStyle: {
            color: '#00000000',
         },
      },
      {
         name: '其他',
         value: 1.21,
         itemStyle: {
            color: '#30f3ff',
         },
      },
   ],
   0.56
);