可以动的饼图

描述:当前是关于Echarts图表中的 饼图 示例。
 
            let angle = 0
// 复制代码
const chartData = [
  {
    value: 38,
    name: "刑满释放人员",
  },
  {
    value: 145,
    name: "社区矫正人员",
  },
  // {
  //   value: 45,
  //   name: "吸毒人员",
  // },
  // {
  //   value: 21,
  //   name: "邪教人员",
  // },
  // {
  //   value: 51,
  //   name: "艾滋病",
  // },
  // {
  //   value: 9,
  //   name: "重点青少年",
  // },
];
const colorList = ['#88D9FF', '#0092FF', '#81EDD2', '#B0FA93', '#63F2FF', '#9999FE'];
const sum = chartData.reduce((per, cur) => per + cur.value, 0);
const gap = (1 * sum) / 100;
const pieData1 = [];
const pieData2 = [];
const gapData = {
  name: "",
  value: gap,
  itemStyle: {
    color: "transparent",
  },
};

//图标位置显示
let lefts = ["4%", "4%", "4%", "80%", "80%", "80%"];
let tops = ["24%", "37%", "55%", "24%", "37%", "55%"];
// let legendData = [];
let total = 0;
chartData.forEach((item) => {
  total += item.value;
});

for (let i = 0; i < chartData.length; i++) {
  // 第一圈数据
  pieData1.push({
    ...chartData[i],
    itemStyle: {
      borderRadius: 10,
    },
  });
  pieData1.push(gapData);
}

option = {
  backgroundColor: '#ccc',
  title: {
    text: "重点人员",
    subtext: "353",
    x: "49.5%",
    y: "43%",
    itemGap: 15,
    textStyle: {
      color: "#999",
      fontSize: 30,
      fontWeight: "bold",
    },
    subtextStyle: {

      color: "#333",
      fontSize: 24,
      fontWeight: "bold",
    },
    textAlign: 'center'
  },

  // backgroundColor: "#0F141B",
  tooltip: {
    show: true,
    backgroundColor: "rgba(0, 0, 0,.8)",
    textStyle: {
      color: "#fff",
    },
  },
  // legend: legendData,
  grid: {
    top: 30,
    right: 20,
    bottom: 10,
    left: 10,
  },
  color: colorList,
  series: [
    // 外圈
    {
      type: 'custom',
      coordinateSystem: 'none',
      silent: true,
      data: [0],
      renderItem(params, api) {
        //环形图半径
        const r = Math.min(api.getWidth(), api.getHeight()) / 2
        //圆心
        const center = {
          x: api.getWidth() / 2,
          y: api.getHeight() / 2
        }
        //小圆半径
        const rSmall = r * 0.62
        //大圆上的扇形
        const circleOnCircle = [] //小圆上携带的小圆圈
        for (let i = 0; i < 4; i++) {
          circleOnCircle.push({
            type: 'circle',
            shape: {
              cx: getCirclePoint(center.x, center.y, rSmall, 270 + i * 90 + angle).x,
              cy: getCirclePoint(center.x, center.y, rSmall, 270 + i * 90 + angle).y,
              r: 6
            },
            style: {
              fill: '#19ECFF',
              stroke: '#19ECFF',
              lineWidth: 2
            }
          })
        }
        return {
          type: 'group',
          children: [
            {
              //内圆环
              type: 'group',
              children: [
                ...circleOnCircle,
                {
                  //内圆
                  type: 'arc',
                  shape: {
                    cx: center.x,
                    cy: center.y,
                    r: rSmall
                  },
                  style: {
                    fill: 'transparent',
                    stroke: '#55EAF1',
                    lineWidth: 2,
                  }
                }
              ]
            }
          ]
        }
      }
    },
    // 数据圈
    {
      name: '',
      type: 'pie',
      roundCap: true,
      radius: ['52%', '56%'],
      center: ['50%', '50%'],
      label: {
        show: false
      },
      labelLine: {
        show: false
      },
      data: pieData1
    },
    // 内圈
    {
      type: 'pie',
      center: ['50%', '50%'],
      radius: [0, '45.6%'],
      label: {
        show: false
      },
      labelLine: {
        show: false
      },
      itemStyle: {
        color: '#ffffff'
      },
      silent: true,
      data: [
        {
          value: 100,
          name: ''
        }
      ]
    }
  ],
};

//获取圆上某点的坐标(x0、y0表示坐标,r半径,angle角度)
function getCirclePoint(x0, y0, r, angle) {
  let x1 = x0 + r * Math.cos((angle * Math.PI) / 180)
  let y1 = y0 + r * Math.sin((angle * Math.PI) / 180)
  return {
    x: x1,
    y: y1
  }
}

let timer
function play() {
  angle += 3
  option && myChart.setOption(option)
  if (timer) return
  timer = setTimeout(() => {
    requestAnimationFrame(play)
    timer = null
  }, 28)
}

//过渡完成后开始动画
myChart.on('finished', () => {
  play()
})