背景
Vue项目(cli3.x)中使用了Echarts(4.8.0)图表,有自动轮播高亮的需求,所以就找到了下官方文档Api中的dispatchAction和其他人的实现,做出了初步的实现,以供大家参考。
问题:
1、定时器的存储和控制
调用 autoHover 方法,传入 chart 对象 —— 由 echarts.init(dom) 实例化的对象,给 chart 对象绑定一个 _timer 属性,外部可直接通过 chart 对象访问该属性并操作,每次定时器触发时,用一个变量存储 chart._timer,保证在 chart 销毁后销毁定时器
2、鼠标事件的处理
在这儿主要针对鼠标移入(mouseover)和鼠标移出(mouseout)事件进行处理,当鼠标移入时关闭定时器,鼠标移出时恢复自动轮播,顺序接上一自动轮播之后。
鼠标移入只有移入到饼图和柱状图的数据上才有效,最后解决方案直接给整个图表增加了鼠标移入事件,通过 chart.getZr().on 注册鼠标移出事件,getZr() 是直接针对画布的。
代码
BaseChart.vue
<template>
<div ref="chart" :style="{ width, height }" @mouseover="clearTimer" />
</template>
<script>
import echarts from 'echarts'
// import { debounce } from 'lodash-es'
import { autoHover } from './auto-chart'
export default {
name: 'BaseChart',
props: {
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '100%'
}
},
data () {
return {
chart: null
}
},
mounted () {
window.addEventListener('resize', this.handleResize)
},
methods: {
/** 窗口变化事件 */
handleResize () {
this.chart && this.chart.resize()
},
/** 高亮索引切换 */
handleHoverIndexChange (index) {
this.$emit('curDataIndex', index)
},
setChart ({ options = {}, isAutoHover = false, isClear = false, seriesIndex = 0 }) {
this.$nextTick(() => {
if (!this.chart) {
this.chart = echarts.init(this.$refs.chart)
}
this.clearTimer()
if (isAutoHover) {
autoHover({
chart: this.chart,
seriesIndex,
length: options.series[seriesIndex].data.length,
cb: this.handleHoverIndexChange
})
}
isClear && this.chart.clear()
this.chart.setOption(options)
this.chart.resize()
})
},
/** 外部调用的 自动轮播方法 */
autoHover (params) {
this.$nextTick(() => {
autoHover({ chart: this.chart, ...params })
})
},
/** 清除定时器 */
clearTimer () {
if (this.chart && this.chart._timer) {
clearInterval(this.chart._timer)
// clearTimeout(this.chart._timer)
this.chart._timer = null
}
}
},
beforeDestroy () {
this.clearTimer()
/** 移除事件 */
window.removeEventListener('resize', this.handleResize)
}
}
</script>
auto-chart.js
/**
* 清除定时器
* @param {Echart} chart
*/
const clearTimer = chart => {
if (!chart && !chart._timer) return
clearInterval(chart._timer)
chart._timer = null
}
const sendChartDataIndex = (n, cb) => { cb(n) }
/**
* 设置 chart 的高亮和 tip 显示
* @param {Echart} chart
* @param {number/array} seriesIndex series索引
* @param {number} index 数据索引
*/
export const setChartLightAndTip = (chart, seriesIndex = 0, index = 0) => {
if (!chart) return false
// 取消高亮指定的数据图形
chart.dispatchAction({
type: 'downplay',
seriesIndex
})
// 高亮
chart.dispatchAction({
type: 'highlight',
seriesIndex,
dataIndex: index
})
// 显示tip
chart.dispatchAction({
type: 'showTip',
seriesIndex,
dataIndex: index
})
}
/**
* chart自动循环高亮
* @param {Echart} chart
* @param {number} length 数据长度
* @param {number} interval 切换间隔时间(毫秒)
* @param {number/array} seriesIndex series索引
* @param {number} defaultIndex 默认高亮索
* 参考:https://www.cnblogs.com/liuwei54/p/10496555.html
*/
export const autoHover = ({
chart,
length = 0,
interval = 2000,
seriesIndex = 0,
defaultIndex = 0,
cb }) => {
let _index = defaultIndex
let _timer = null
/** 如果 chart 不存在 */
if (!chart) {
return void 0
}
/** 先清除事件 */
chart.off('mouseout')
/** 定时器存在 */
if (chart._timer) {
clearTimer(chart)
}
/** 定时器回调函数 */
const timerCB = () => {
if (chart) {
_timer = chart._timer
}
// 如果 chart 不存在,则清空定时器
if (!chart) {
// clearTimer(chart)
clearInterval(_timer)
_timer = null
}
// 切换高亮
setChartLightAndTip(chart, seriesIndex, _index)
// 发送 切换高亮后 事件
sendChartDataIndex(_index, cb)
_index++
// 归零
if (_index >= length) _index = 0
}
// 设置定时器
chart._timer = setInterval(() => {
timerCB()
}, interval)
// 处理鼠标移入事件
// chart.getZr().on('mouseover', params => {
// console.log('移入')
// clearTimer(chart)
// _index = params.dataIndex
// sendChartDataIndex(_index, cb)
// setChartLightAndTip(chart, seriesIndex, _index)
// })
// 处理鼠标移出事件
chart.getZr().on('mouseout', () => {
clearTimer(chart)
chart._timer = setInterval(() => {
timerCB()
}, interval)
})
}
实现得比较潦草,希望能给大家提供一些思路,有想过项目中利用es6的Class,实现一个Chart类,统一维护Chart相关基础的属性和行为(方法),在计划中了,如果有什么建议可以评论区留言。