<template>
  <div class="chart-container" v-echartResize>
     <div class="chart" ref="chartRef"></div>
     <!-- 底座背景 -->
     <div class="bg"></div> 
     <!-- 中间文字 -->
     <div class="center-text">
       <div class="value">{{ totalValue }}</div>
       <div class="unit">人</div>
     </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, reactive, computed } from 'vue'
import { getPie3D, getParametricEquation } from '@/composables/useEchart'
import * as echarts from 'echarts'
import 'echarts-gl' // 3d图表库
import { fitChartSize } from '@/utils/echartData'
import { vEchartResize } from '@/directives/chart-resize'

const color = ['#5AF3B8', '#93DBFF']

const props = defineProps({
  optionData: {
    type: Array,
    default: () => []
  }
})

// refs
const chartRef = ref(null)
let statusChart = ref(null)

// 计算数据总和
const totalValue = computed(() => {
  return props.optionData.reduce((sum, item) => sum + item.value, 0)
})

const option = reactive({})

// 初始化label样式
const setLabel = () => {
  props.optionData.forEach((item, index) => {
    item.itemStyle = {
      color: color[index]
    }
    item.label = {
      show: true,
      color: color[index],
      formatter: '{b} {d}%', // 简化格式化字符串，避免使用数组join和富文本
      rich: {
        b: {
          color: color[index],
          lineHeight: 25,
          align: 'left',
          fontSize: 12,
        },
        d: {
          color: color[index],
          align: 'left',
          fontSize: 12
        }
      }
    }
    item.labelLine = {
      lineStyle: {
        width: 1,
        color: color[index]
      }
    }
  })
}

// 图表初始化
const initChart = () => {
  statusChart.value = echarts.init(chartRef.value)
  // 传入数据生成 option, 构建3d饼状图, 参数工具文件已经备注的很详细
  Object.assign(option, getPie3D(props.optionData, 0.8, 240, 36, 13, 0.5))
  statusChart.value.setOption(option)
  // 是否需要label指引线，如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐，并再次setOption
  option.series.push({
    name: '', //自己根据场景修改
    backgroundColor: 'transparent',
    type: 'pie',
    label: {
      opacity: 1,
      fontSize: 12,
    },
    startAngle: -40, // 起始角度，支持范围[0, 360]。
    clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
    radius: ['20%', '50%'],
    center: ['50%', '50%'],
    data: props.optionData,
    itemStyle: {
      opacity: 0  //这里必须是0，不然2d的图会覆盖在表面
    }
  })
  statusChart.value.setOption(option)
  bindListen(statusChart.value)
}

// 监听鼠标事件，实现饼图选中效果（单选），近似实现高亮（放大）效果。
// optionName是防止有多个图表进行定向option传递，单个图表可以不传，默认是opiton
const bindListen = (myChart) => {
  let selectedIndex = ''
  let hoveredIndex = ''
  // 监听点击事件，实现选中效果（单选）
  myChart.on('click', (params) => {
    // 确保params.seriesIndex有效且对应的对象存在
    if (params.seriesIndex === undefined || !option.series[params.seriesIndex] || !option.series[params.seriesIndex].pieStatus) {
      return;
    }
    
    // 从 option.series 中读取重新渲染扇形所需的参数，将是否选中取反。
    const isSelected = !option.series[params.seriesIndex].pieStatus.selected
    const isHovered = option.series[params.seriesIndex].pieStatus.hovered
    const k = option.series[params.seriesIndex].pieStatus.k
    const startRatio = option.series[params.seriesIndex].pieData.startRatio
    const endRatio = option.series[params.seriesIndex].pieData.endRatio
    // 如果之前选中过其他扇形，将其取消选中（对 option 更新）
    if (selectedIndex !== '' && selectedIndex !== params.seriesIndex && 
        option.series[selectedIndex] && option.series[selectedIndex].pieStatus) {
      option.series[selectedIndex].parametricEquation = getParametricEquation(
        option.series[selectedIndex].pieData.startRatio,
        option.series[selectedIndex].pieData.endRatio,
        false,
        false,
        k,
        option.series[selectedIndex].pieData.value
      )
      option.series[selectedIndex].pieStatus.selected = false
    }
    // 对当前点击的扇形，执行选中/取消选中操作（对 option 更新）
    option.series[params.seriesIndex].parametricEquation = getParametricEquation(
      startRatio,
      endRatio,
      isSelected,
      isHovered,
      k,
      option.series[params.seriesIndex].pieData.value
    )
    option.series[params.seriesIndex].pieStatus.selected = isSelected
    // 如果本次是选中操作，记录上次选中的扇形对应的系列号 seriesIndex
    selectedIndex = isSelected ? params.seriesIndex : null
    // 使用更新后的 option，渲染图表
    myChart.setOption(option)
  })
  
  // 监听 mouseover，近似实现高亮（放大）效果
  myChart.on('mouseover', (params) => {
    // 准备重新渲染扇形所需的参数
    let isSelected
    let isHovered
    let startRatio
    let endRatio
    let k
    // 如果触发 mouseover 的扇形当前已高亮，则不做操作
    if (hoveredIndex === params.seriesIndex) {
      // 否则进行高亮及必要的取消高亮操作
    } else {
      // 如果当前有高亮的扇形，取消其高亮状态（对 option 更新）
      if (hoveredIndex !== '' && option.series[hoveredIndex] && option.series[hoveredIndex].pieStatus) {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 false。
        isSelected = option.series[hoveredIndex].pieStatus.selected
        isHovered = false
        startRatio = option.series[hoveredIndex].pieData.startRatio
        endRatio = option.series[hoveredIndex].pieData.endRatio
        k = option.series[hoveredIndex].pieStatus.k
        // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
        option.series[hoveredIndex].parametricEquation = getParametricEquation(
          startRatio,
          endRatio,
          isSelected,
          isHovered,
          k,
          option.series[hoveredIndex].pieData.value
        )
        option.series[hoveredIndex].pieStatus.hovered = isHovered
        // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
        hoveredIndex = ''
      }
      // 如果触发 mouseover 的扇形不是透明圆环，将其高亮（对 option 更新）
      if (
        params.seriesName !== 'mouseoutSeries' &&
        params.seriesName !== 'pie2d' &&
        params.seriesIndex !== undefined &&
        option.series[params.seriesIndex] &&
        option.series[params.seriesIndex].pieStatus
      ) {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
        isSelected = option.series[params.seriesIndex].pieStatus.selected
        isHovered = true
        startRatio = option.series[params.seriesIndex].pieData.startRatio
        endRatio = option.series[params.seriesIndex].pieData.endRatio
        k = option.series[params.seriesIndex].pieStatus.k
        // 对当前点击的扇形，执行高亮操作（对 option 更新）
        option.series[params.seriesIndex].parametricEquation = getParametricEquation(
          startRatio,
          endRatio,
          isSelected,
          isHovered,
          k,
          option.series[params.seriesIndex].pieData.value + 60
        )
        option.series[params.seriesIndex].pieStatus.hovered = isHovered
        // 记录上次高亮的扇形对应的系列号 seriesIndex
        hoveredIndex = params.seriesIndex
      }
      // 使用更新后的 option，渲染图表
      myChart.setOption(option)
    }
  })
  
  // 修正取消高亮失败的 bug
  myChart.on('globalout', () => {
    // 准备重新渲染扇形所需的参数
    let isSelected
    let isHovered
    let startRatio
    let endRatio
    let k
    if (hoveredIndex !== '' && option.series[hoveredIndex] && option.series[hoveredIndex].pieStatus) {
      // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
      isSelected = option.series[hoveredIndex].pieStatus.selected
      isHovered = false
      k = option.series[hoveredIndex].pieStatus.k
      startRatio = option.series[hoveredIndex].pieData.startRatio
      endRatio = option.series[hoveredIndex].pieData.endRatio
      // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
      option.series[hoveredIndex].parametricEquation = getParametricEquation(
        startRatio,
        endRatio,
        isSelected,
        isHovered,
        k,
        option.series[hoveredIndex].pieData.value
      )
      option.series[hoveredIndex].pieStatus.hovered = isHovered
      // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
      hoveredIndex = ''
    }
    // 使用更新后的 option，渲染图表
    myChart.setOption(option)
  })
}

// 自适应宽高
// const changeSize = () => {
//   statusChart.value?.resize()
// }

// 生命周期钩子
onMounted(() => {
  setLabel()
  initChart()
  
  // 根据窗口变化自动调节图表大小
  // window.addEventListener('resize', changeSize)
})

// onBeforeUnmount(() => {
//   window.removeEventListener('resize', changeSize)
// })
</script>

<style lang='scss' scoped>
.chart-container {
  position: relative;
  width: 100%;
  height: 100%;

  .chart,
  .bg {
    width: 100%;
    height: 100%;
  }

  .bg {
    position: absolute;
    bottom: 50px;
    left: 50%;
    z-index: -1;
    width: 180px;
    height: 73px;
    background: no-repeat center;
    background-image: url('/images/particles-bg.png');
    background-size: 100% 100%;
    transform: translateX(-50%);
  }
  
  .center-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 10;
    text-align: center;
    
    .value {
      display: inline-block;
      font-size: 24px;
      font-weight: 500;
      color: #8FC8FF;
    }
    
    .unit {
      display: inline-block;
      font-size: 18px;
      font-weight: 500;
      color: #FFFFFF;
    }
  }
}
</style>