最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • echarts饼图轮播(Vue 3.0 Hooks思想)

    正文概述 掘金(枯木尚未逢春)   2020-12-24   650

    场景: echarts 饼图轮播高亮各项

    效果图:

    echarts饼图轮播(Vue 3.0 Hooks思想)

    第一步:

    明确,如何获取实例的配置,如何使得echarts 图表单项高亮/取消高亮

    高亮,取消高亮对应echarts的Api

    //echarts 生成实例后, 传入实例,通过` instance.getOption()` 获取实例各项参数
    
    // 高亮
    instance.dispatchAction({
        type: 'highlight',
        dataIndex: 0 // 数据项索引
    })
    // 取消高亮
    instance.dispatchAction({
        type: 'downplay',
        dataIndex: 0 // 数据项索引
    })
    

    第二步:

    各类数据

      let timer = null // 轮播定时器
      let currentIndex = -1 // 当前高亮第几个位置(注意不是数据项的dataIndex)
      let selectedLengend = null // 当前legend切换的数据信息
      let len = 0 //  当前可轮播的数据项列表长度
      let myEchart = null // echarts 实例
      let currDataList = null 当前可轮播的数据项列表
    

    ps:

    高亮索引从0开始, 每次高亮后,currentIndex+1, 会超出data数据项的长度,所以派发高亮/取消高亮的事件时候,需要 ``currentIndex = (currentIndex+1) % len`, len 是当前legend选中展示的数据项长度而不是全部的数据长度,后面会讲到。

    第三步:

    开启各项事件的监听

    1.鼠标悬浮事件:instance.on('mouseover',e=>{.... })

    说明:鼠标悬浮到图表首先得判断, 当前鼠标悬浮图项的dataIndex 是否正是当前轮播的 currentIndex

    如果是则直接清除定时轮播,如果不是,则需要取消currentIndex的高亮效果,并且高亮当前回调中的项dataIndex,将当前currentItem 赋值为当前回调的数据项,并且调用highEvent(currentItem) (告诉外部数据变化)

    2.鼠标移出事件:instance.on('mouseout',e=>{ ....})

    说明: 承接上面移入,移出就比较简单, 直接重新开始走轮播定时器即可

    3.图表切换显示与否事件:instance.on('legendselectchanged',e=>{... })

    重点说明:如果忘了这一步,你的轮播图表就会出现明明取消展示了一些图,但是它们却还在轮播展示中,

    所以监听这个legendselectchanged事件,就是为了,改变定时器当前可轮播项。该事件触发会返回当前图项目的展示与否信息,name作为key, false/true 作为value。详细细节看下面完整代码与注释。

    4.点击事件: instance.on('click',e=>{ clickEvent(e) })

    说明: 这里的点击事件单纯作为一个扩展方法,通过外部传入clickEvent,在此执行一次,将信息传达出去共给外部自定义其他交互。 tip:

    1.timer应该在hooks 进入的时候,判断是否为空,不为空应该清除轮播定时器

    2.在hook生命周期,onUnmounted 中应该清除轮播定时器

    详细代码

    1.PieEchart.vue

    <template>
      <a-spin :spinning="loading">
        <div :ref="setRef" class="pie_echart"></div>
        <div class="markInfo">
          <div class="label">{{ current.name }}</div>
          <div class="value">{{ current.value }}</div>
        </div>
      </a-spin>
    </template>
    
    <script>
    import { ref, onMounted, reactive, defineComponent } from 'vue'
    import { pieGradient } from '/@/constant/echartsOption'
    import useWinResize from '/@/hooks/useWinResize'
    import useEchartSwipe from '/@/hooks/useEchartSwipe'
    export default {
      name: 'PieEchart',
      props: {
        data: {
          type: Array,
          required: true
        },
        colorList: {
          type: Array,
          required: false
        }
      },
      setup(props, contexts) {
        const echartRef = ref(null)
        const setRef = el => {
          echartRef.value = el
        }
        const loading = ref(true)
        const { data, colorList } = props
        const init = async () => {
          loading.value = await new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(false)
            }, 220)
          })
        }
        onMounted(() => {
          init()
        })
        const clickEvent = e => {
          console.log(e)
        }
        const dataOption = pieGradient(data, colorList)
        const current = useEchartSwipe(echartRef, dataOption, 1800, clickEvent)
        return {
          setRef,
          loading,
          current
        }
      }
    }
    </script>
    
    <style scoped lang="scss">
    .pie_echart {
      width: 100%;
      height: calc(100vh - 270px);
    }
    .markInfo {
      position: absolute;
      top: 50%;
      left: 50%;
      text-align: center;
      transform: translate(-50%, -50%);
      .label {
        font-size: 28px;
        color: black;
      }
      .value {
        font-size: 24px;
        color: aqua;
      }
      @media screen and (max-width: 414px) {
        .label {
          font-size: 16px;
          color: black;
        }
        .value {
          font-size: 14px;
          color: aqua;
        }
      }
    }
    </style>
    

    2.echartsOption

    export const pieGradient = (data, colorList) => {
      const color = colorList ? colorList : ['#58D5FF', '#73ACFF', '#FDD56A', '#FDB36A', '#FD866A', '#9E87FF']
      const option = {
        legend: {
          show: true
        },
        tooltip: {
          trigger: 'item'
        },
        series: [
          {
            type: 'pie',
            center: ['50%', '50%'],
            radius: ['25%', '40%'],
            minAngle: 10,
            avoidLabelOverlap: true,
            hoverOffset: 15,
            itemStyle: {
              color: params => {
                return color[params.dataIndex]
              }
            },
            legendHoverLink: false, // 鼠标悬浮legend 高亮图表
            label: {
              show: true,
              position: 'outer',
              alignTo: 'labelLine',
              // ·圆点
              backgroundColor: 'auto', //圆点颜色,auto:映射的系列色
              height: 0,
              width: 0,
              lineHeight: 0,
              // height,width.lineHeight必须为0
              distanceToLabelLine: 0, //圆点到labelline距离
              borderRadius: 2.5,
              padding: [2.5, -2.5, 2.5, -2.5],
    
              /**
               * radius和padding为圆点大小,圆点半径为几radius和padding各项数值就为几
                如:圆点半径为1
                borderRadius: 1,
                padding: [1, -1, 1, -1]
               */
              formatter: '{a|{b}:}{b|{d}%}',
              rich: {
                a: {
                  padding: [0, 0, 0, 10]
                },
                b: {
                  padding: [0, 10, 0, 0]
                }
              }
            },
            data
          }
        ]
      }
      return option
    }
    

    3.useEchartSwipe

    import { onMounted, onUnmounted, reactive } from 'vue'
    import useWinResize from '/@/hooks/useWinResize'
    import Echarts from 'echarts'
    /**
     *
     * @param {*} dom  节点
     * @param {*} option 额外配置项
     * @param {*} interval 速度ms
     * @param {*} clickEvent 点击事件做什么
     */
    export default function useEchartSwipe(dom = null, dataOption = null, interval = 2200, clickEvent = () => {}) {
      let timer = null
      let currentIndex = -1
      let selectedLengend = null
      let len = 0
      let myEchart = null
      let currDataList = null
      const currentItem = reactive({
        name: '',
        value: ''
      })
      const clearInstance = () => {
        myEchart.off('mouseover')
        myEchart.off('mouseout')
        myEchart.off('click')
        myEchart.clear()
        myEchart = null
      }
      /**
       * 初始化 echarts
       */
      const initPieEchart = () => {
        myEchart && clearInstance()
        myEchart = Echarts.init(dom.value)
        myEchart.setOption(dataOption)
      }
      /**
       *  auto swipe
       */
      const autoSwipe = () => {
        mainAction()
        timer && clearInterval(timer)
        timer = setInterval(mainAction, interval)
      }
      const highLight = index => {
        myEchart.dispatchAction({
          type: 'highlight',
          dataIndex: currDataList[index].dataIndex
        })
      }
      const downplay = index => {
        if (index === -1 || len === 0) return
        myEchart.dispatchAction({
          type: 'downplay',
          dataIndex: currDataList[index].dataIndex
        })
      }
      const mainAction = () => {
        const { series } = myEchart.getOption()
        currDataList = series[0].data.map((item, index) => {
          return {
            ...item,
            dataIndex: index
          }
        }) // 给每一项数据增加 dataIndex 后续 会用到
        if (selectedLengend) {
          // 如果存在 选中不选中图表的信息则需要重新过滤轮播
          currDataList = currDataList.filter(item => selectedLengend[item.name])
        }
        len = currDataList.length
        downplay(currentIndex % len)
        if (len > 0) {
          currentIndex = (currentIndex + 1) % len
          len === 1 ? clearInterval(timer) : highLight(currentIndex)
          currentItem.name = currDataList[currentIndex].name
          currentItem.value = currDataList[currentIndex].value
        } else {
          currentIndex = -1 // 取消所有数据展示 , 重置为-1
          currentItem.name = ''
          currentItem.value = ''
          timer && clearInterval(timer)
        }
      }
      /**
       * 挂载监听 mouseover, mousemove 事件
       */
      const initPieEvent = () => {
        myEchart.on('mouseover', e => {
          // 判断当前高亮是否是为悬浮的dataIndex
          const { dataIndex, name, value } = e
          if (currentIndex !== -1 && dataIndex !== currDataList[currentIndex].dataIndex) {
            // 取消轮播当前的高亮
            downplay(currentIndex)
          }
          // 改变当前项为 悬浮项
          currentItem.name = name
          currentItem.value = value
          // 下次轮播从当前高亮项开始downplay
          currentIndex = dataIndex
          // 直接清除定时器
          timer && clearInterval(timer)
        })
        myEchart.on('mouseout', () => {
          autoSwipe() // 鼠标离开,重新启动高亮
        })
        myEchart.on('legendselectchanged', e => {
          // 图表项,切换展示与否
          selectedLengend = e.selected
          // 重新开始轮播
          autoSwipe()
        })
        myEchart.on('click', e => {
          clickEvent(e) // 外部扩展事件
        })
      }
      const resizeEcharts = () => {
        myEchart && myEchart.resize()
      }
      useWinResize(resizeEcharts)
    
      onMounted(() => {
        setTimeout(() => {
          initPieEchart()
          initPieEvent()
          autoSwipe()
        }, 120)
      })
    
      onUnmounted(() => {
        timer && clearInterval(timer)
      })
      return currentItem
    }
    
    

    4.useWinResize

    import { onMounted, onBeforeUnmount } from 'vue'
    
    export default function useWinResize(Action = () => {}) {
      const fn = () => {
        /**
         * 延迟更新重绘等操作
         */
        setTimeout(Action, 120)
      }
      onMounted(() => {
        window.addEventListener('resize', fn, false)
      })
      onBeforeUnmount(() => {
        window.removeEventListener('resize', fn)
      })
      return null
    }
    

    起源地下载网 » echarts饼图轮播(Vue 3.0 Hooks思想)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元