3d饼图

描述:当前是关于Echarts图表中的 饼图 示例。
 
            /********* *
生成模拟 3D 饼图的配置项 option
    备注:饼图数据格式示意如下
    [{
        name: '数据1',
        value: 10
    }, {
        // 数据项名称
        name: '数据2',
        value : 56,
        itemStyle:{
            // 透明度
            opacity: 0.5,
            // 扇形颜色
            color: 'green'
        }
    }]
*******/
var optionData = [
  {
    name: '并网',
    value: 40,
  },
  {
    name: '脱网',
    value: 20,
  },
 
]
 var sum = optionData.reduce((accumulator, currentValue) => {
  return accumulator + currentValue.value;
}, 0);
option = getPie3D(optionData, 0) // 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
/*************************
生成扇形的曲面参数方程 生成 3D 扇形环曲面:
  【 getParametricEquation 函数说明 】 
     startRatio(浮点数): 当前扇形起始比例,取值区间 [0, endRatio)
     endRatio(浮点数): 当前扇形结束比例,取值区间 (startRatio, 1]
     isSelected(布尔值):是否选中,效果参照二维饼图选中效果(单选)
     isHovered(布尔值): 是否放大,效果接近二维饼图高亮(放大)效果(未能实现阴影)
     k(0~1之间的浮点数):用于参数方程的一个参数,取值 0~1 之间,通过「内径/外径」的值换算而来。
     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
    },
  }
}
/********** 
生成模拟 3D 饼图的配置项
  【 getPie3D 函数说明 】 :
     pieData(object):饼图数据
     internalDiameterRatio(0~1之间的浮点数):内径/外径的值(默认值 1/2),当该值等于 0 时,为普通饼图
  // 为每一个饼图数据,生成一个 series-surface 配置
  // 使用遍历计算出的数据和 sumValue,调用 getParametricEquation 函数,实现每一个扇形。
*/
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: 'rgba(0, 0, 0, 0)',
      title: {
    text: `{primary|${sum}}\t{point|台}\n 设备总数`,
    left: 'center',
    top: '10%',
    textStyle: {
      rich: {
        primary: {
          color: '#0F7EFF',
          fontWeight: 500,
          fontSize: 48,
          lineHeight: 67.2
        },
        point: {
          fontSize: 14,
          lineHeight: 22,
          color: '#A1A6B1',
          verticalAlign: 'top',
          padding: [10, -10, 0, 0]
        }
      }
    }
  },
    legend: {
      show: true,
      left: '7%',
      bottom: '0%',
      orient: 'vertical',
      // icon: 'circle',
      itemHeight: 10,
      itemWidth: 15,
      itemGap: 10,
      textStyle: {
        color: '#ccc',
        fontSize: 12,
        fontWeight: '400',
      },
      formatter: (name) => {
        if (optionData.length) {
          const item = optionData.filter((item) => item.name === name)[0]
          return `  ${name}      ${item.value}台`
        }
      },
    },
    color: ['#159AFF', 'rgba(241, 68, 68, 1)'],
    tooltip: {
      formatter: (params) => {
        if (params.seriesName !== 'mouseoutSeries') {
          return `${params.marker}${params.seriesName}:${
            optionData[params.seriesIndex].value
          }`
        }
        return ''
      },
    },
    xAxis3D: {
      min: -1,
      max: 1,
    },
    yAxis3D: {
      min: -1,
      max: 1,
    },
    zAxis3D: {
      min: -1,
      max: 1,
    },
    grid3D: {
      show: false,
      boxHeight: 30, //修改立体饼图的高度
      top: '-10%',
      left: '0%',
      viewControl: {
        // 3d效果可以放大、旋转等,
        alpha: 20, //饼图翻转的程度
        beta: 130,
        rotateSensitivity: 1,
        zoomSensitivity: 0,
        panSensitivity: 0,
        autoRotate: false, //是否自动旋转
        distance: 350, //距离越小看到的饼图越大
      },
    },
    series,
  }
  return option
}