React基于Antv-G2带Annotation的饼图点击示例的自动循环轮播

由于最近接手一个大屏项目,加了个自动轮播循环的饼图示例功能,这个困扰了我一个礼拜,查了官方文档,也查了csdn其他文档,有一个文档是用的定时器做的,但在我这不生效,只好改成手写的了。

先上图(图片截的是静态的,但是成品是三段自动循环点击展示的):

正题来了,其实这些点击饼图之后出现的交互和点击事件都是在chart.render()之后加的

为了针对性的解决这个问题,我先上关键代码(最后会有全代码展示)

这边我是在render()下写了个setInterval函数来进行自动交互,其主要是在于更改antv官方给的选中的属性

    // 移除图例点击过滤交互
    chart.removeInteraction('legend-filter')
    // chart.interaction('element-active')
    chart.interaction('element-single-selected')
    chart.render()
    let count = 0
    let timer
    let lastItem
    updateAnnotation(data[0])

    function carousel() {
      // if (count === 0) {
      //   interval.elements[0].setState('selected', count === 1 ? true : false)
      // }
      count++

      interval.elements[0].setState('selected', count === 1 ? true : false)
      interval.elements[1].setState('selected', count === 2 ? true : false)
      interval.elements[2].setState('selected', count === 3 ? true : false)

      if (count === interval.elements.length) {
        count = 0
      }
    }

    carousel()
    timer = setInterval(carousel, 2000)

这边在写完手写的函数之后接上官方的参考文档,当然会有些改动

重点:如果没有stateStatus的话,你不需要隐藏Annotation,因为如果隐藏的话你的饼图自动走一轮是正常展示,但是从第二遍循环开始,第一条数据文字不会在饼图中间显示,一开始按照官方文档来也入了个坑,因为它会调用一个函数来清除中间的Annotation显示
如果你不需要自动循环播放只需要手动点击的话,上面的代码可以不写但是要加上clearAnnotation()函数,这边我加在最后面了,所以我会最后展示
    // 监听 element 上状态的变化来动态更新 Annotation 信息
    chart.on('element:statechange', (ev) => {
      const { state, stateStatus, element } = ev.gEvent.originalEvent
      // 本示例只需要监听 active 的状态变化
      if (state === 'selected') {
        const data = element.data
        if (stateStatus) {
          // 更新 Annotation
          updateAnnotation(data)
        } else {
          // 隐藏 Annotation
          // clearAnnotation()
        }
      }
    })
在接上面的代码进行绘制饼图中心文字显示
    // 绘制 annotation
    function updateAnnotation(data) {
      if (data.item !== lastItem) {
        innerView.annotation().clear(true)
        innerView
          .annotation()
          .text({
            position: ['50%', '50%'],
            content: data.item,
            style: {
              fontSize: 12,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetY: 20,
          })
          .text({
            position: ['50%', '50%'],
            content: data.percent * 100,
            style: {
              fontSize: 20,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetX: -10,
            offsetY: -10,
          })
          .text({
            position: ['50%', '50%'],
            content: '%',
            style: {
              fontSize: 16,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetY: -10,
            offsetX: 10,
          })
        innerView.render(true)
        lastItem = data.item
      }
    }

clearAnnotation函数:

    // 清空 annotation
    function clearAnnotation() {
      innerView.annotation().clear(true)
      innerView.render(true)
      lastItem = null
    }

整个饼图代码:

    const chart = new Chart({
      container: 'xxx',
      width: 160,
      height: 160,
      padding: [0],
      supportCSSTransform: true,
    })
    // 新建一个 view 用来单独渲染Annotation
    const innerView = chart.createView()
    chart.coordinate('theta', {
      radius: 0.75,
      innerRadius: 0.8,
    })

    chart.data(data)

    chart.scale('percent', {
      formatter: (val) => {
        val = val * 100 + '%'
        return val
      },
    })

    chart.tooltip(false)
    chart.legend(false)
    const interval = chart
      .interval()
      .adjust('stack')
      .position('percent')
      .color('item', ['#a3f6ff', '#3fb787', '#6344e9'])
      .style({
        fillOpacity: 1,
      })
      .state({
        active: {
          style: (element) => {
            const shape = element.shape
            return {
              // matrix: Util.zoom(shape, 1.1),
              lineWidth: 10,
              stroke: shape.attr('fill'),
              strokeOpacity: shape.attr('fillOpacity'),
            }
          },
        },
      })
    // 移除图例点击过滤交互
    chart.removeInteraction('legend-filter')
    // chart.interaction('element-active')
    chart.interaction('element-single-selected')
    chart.render()
    let count = 0
    let timer
    let lastItem
    updateAnnotation(data[0])

    function carousel() {
      console.log(interval.elements, count, data[0], '123')
      // if (count === 0) {
      //   interval.elements[0].setState('selected', count === 1 ? true : false)
      // }
      count++

      interval.elements[0].setState('selected', count === 1 ? true : false)
      interval.elements[1].setState('selected', count === 2 ? true : false)
      interval.elements[2].setState('selected', count === 3 ? true : false)

      if (count === interval.elements.length) {
        count = 0
      }
    }

    carousel()
    timer = setInterval(carousel, 2000)

    // 监听 element 上状态的变化来动态更新 Annotation 信息
    chart.on('element:statechange', (ev) => {
      // console.log(ev.gEvent.originalEvent.element.data, 'click')
      const { state, stateStatus, element } = ev.gEvent.originalEvent
      // 本示例只需要监听 active 的状态变化
      if (state === 'selected') {
        const data = element.data
        if (stateStatus) {
          // 更新 Annotation
          updateAnnotation(data)
        } else {
          // 隐藏 Annotation
          // clearAnnotation()
        }
      }
    })

    // 绘制 annotation
    // let lastItem
    function updateAnnotation(data) {
      if (data.item !== lastItem) {
        innerView.annotation().clear(true)
        innerView
          .annotation()
          .text({
            position: ['50%', '50%'],
            content: data.item,
            style: {
              fontSize: 12,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetY: 20,
          })
          .text({
            position: ['50%', '50%'],
            content: data.percent * 100,
            style: {
              fontSize: 20,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetX: -10,
            offsetY: -10,
          })
          .text({
            position: ['50%', '50%'],
            content: '%',
            style: {
              fontSize: 16,
              fill: '#8c8c8c',
              textAlign: 'center',
            },
            offsetY: -10,
            offsetX: 10,
          })
        innerView.render(true)
        lastItem = data.item
      }
    }

    // 清空 annotation
    function clearAnnotation() {
      innerView.annotation().clear(true)
      innerView.render(true)
      lastItem = null
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值