Vue 中 Highcharts 饼图获取选中块集合失准问题

728 阅读1分钟

前言

Highcharts 通过 getSelectedPoints API 获取图表选中的点。在 Vue 项目中使用时发现,基于 Highcharts 封装的饼图组件,直接调用 getSelectedPoints 无法准确地获取到当前选中的饼图块的点的集合。

基于 Highcharts 封装的饼图组件

<template>
  <div class="pie-chart"></div>
</template>

<script>
import { chartMixin } from '@/mixin/chart_mixin'
var Highcharts = require('highcharts')

export default {
  name: 'PieChart',
  mixins: [chartMixin],
  props: {
    series: {
      type: Array,
      required: true
    }
  },
  data: function () {
    return {
      pieChartRef: undefined,
      seriesData: []
    }
  },
  methods: {
    initChart () {
      const self = this
      this.pieChartRef = Highcharts.chart(this.$el, {
        chart: {
          plotBackgroundColor: null,
          plotBorderWidth: null,
          plotShadow: false,
          type: 'pie'
        },
        title: {
          text: null
        },
        credits: {
          enabled: false
        },
        tooltip: {
          pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
        },
        accessibility: {
          point: {
            valueSuffix: '%'
          }
        },
        plotOptions: {
          pie: {
            allowPointSelect: true,
            cursor: 'pointer',
            dataLabels: {
              enabled: true,
              format: '<b>{point.name}</b>: {point.percentage:.1f} %'
            }
          },
          series: {
            events: {
              click: function (event) {
                // 通过 setTimeout 创建宏任务,在宏任务中通过 getSelectedPoints 获取饼图块 id
                setTimeout(() => {
                  self.$emit('sclick', self.pieChartRef.getSelectedPoints())
                }, 0)
              }
            }
          }
        },
        series: [{
          name: '占比',
          colorByPoint: true,
          data: [
            {
              name: 'text',
              y: 10.84
            }
          ]
        }]
      })

      this.initChartRef(this.pieChartRef)
    },
    updateChartData (data) {
      this.pieChartRef.series[0].update({
        data: data
      })
    },
    getSelectedSliced () {
      return this.pieChartRef && this.pieChartRef.getSelectedPoints()
    }
  },
  watch: {
    series: {
      immediate: true,
      deep: true,
      handler (newVal) {
        this.seriesData = newVal

        setTimeout(() => {
          this.updateChartData(this.seriesData)
          this.pieChartRef.reflow()
        }, 5)
      }
    }
  },
  mounted: function () {
    this.initChart()

    setTimeout(() => {
      this.pieChartRef.reflow()
    }, 5)
  }
}

</script>

在上述代码中,在 series 的点击事件中,通过 setTimeout 创建一个宏任务,并在宏任务中通过 getSelectedPoints 来获取对应的饼图选中块,并向父组件 emit 当前的选中块,这样就可以解决获取饼图选中块失准的问题。

父组件中使用

在父组件中,引入 PieChart 组件,并监听 sclick 事件,通过方法 onPieChartClick 进行处理。

<PieChart
  ref="piechart"
  @sclick="index => onPieChartClick(index)"
  :series="getPieChartData(tab.key)"/>

事件监听处理

onPieChartClick (sliceList) {
  this.sliceList = sliceList
  setTimeout(() => {
    const sliceIdList = this.getPieSliceIdList(sliceList)

    if (sliceIdList.length > 0) {
      this.$set(this.btnDisabledList, this.tabIndex, false)
    } else {
      this.$set(this.btnDisabledList, this.tabIndex, true)
    }
  }, 150)
}

在事件处理中,需要筛选饼图块的 id 值集合。饼图块中原始的选中集合,格式类似如下:

[
  {
    id: 1
    name: '饼图块1',
    y: 50
  }
  ...
]

饼图块 id 筛选

getPieSliceIdList (sliceList) {
  const sliceIdList = sliceList.map(function (item) {
    return item.id
  })

  return sliceIdList
}

参考