鼠标不移入echarts图表的情况下,tootitip实现自动轮播
先看效果
如图所示,可以实现tooltip从6月1日逐次跳到6月30日,来展示数据
之前引用别人的,封装的方法不够全面,主要出现两个问题。
问题1:点击tab按钮切换图表后,tooltip的会跳一次第一个图表的顺序,再跳一次当前这个图表的顺序(例如:物流明细的图表,tooltip展现到6月5日时,点击流向城市按钮后跳转到第二张图表,此时tooltip会先跳一下流向城市图表的第一个索引,再跳一次物流明细的6月6日对应的索引,再切换回物流明细,就会有三个索引来回跳…)初步研究,应该是方法里的seriesIndex在作祟,切换图表后就是插入一个索引。当然研究的不是很透彻,还需要echarts大神来解释,目前情况是对于菜鸟级别的功能能实现,没有明显bug就好了。
问题2:鼠标移入echarts图表再移出后,tooltip就不会自动轮播了。
前提自行参考echarts并了解关于tooltip的官方api里的方法。当然轮子自己不会造,还不会直接用嘛~
1、将自动轮播tooltip方法封装一下,放在src文件夹下新建的一个tooltip-auto-show-vue.js文件内
/**
* echarts tooltip轮播
* @param chart ECharts实例
* @param chartOption echarts的配置信息
* @param options object 选项
* {
* interval 轮播时间间隔,单位毫秒,默认为2000
* loopSeries boolean类型,默认为false。
* true表示循环所有series的tooltip,false则显示指定seriesIndex的tooltip
* seriesIndex 默认为0,指定某个系列(option中的series索引)循环显示tooltip,
* 当loopSeries为true时,从seriesIndex系列开始执行。
* updateData 自定义更新数据的函数,默认为null;
* 用于类似于分页的效果,比如总数据有20条,chart一次只显示5条,全部数据可以分4次显示。
* }
* @returns {{clearLoop: clearLoop}|undefined}
*/
export function loopShowTooltip(chart, chartOption, options) {
let defaultOptions = {
interval: 2000,
loopSeries: false,
seriesIndex: 0,
updateData: null,
};
if (!chart || !chartOption) {
return;
}
let dataIndex = 0; // 数据索引,初始化为-1,是为了判断是否是第一次执行
let seriesIndex = 0; // 系列索引
let timeTicket = 0;
let seriesLen = chartOption.series.length; // 系列个数
let dataLen = 0; // 某个系列数据个数
let chartType; // 系列类型
let first = true;
let lastShowSeriesIndex = 0;
let lastShowDataIndex = 0;
if (seriesLen === 0) {
return;
}
// 待处理列表
// 不循环series时seriesIndex指定显示tooltip的系列,不指定默认为0,指定多个则默认为第一个
// 循环series时seriesIndex指定循环的series,不指定则从0开始循环所有series,指定单个则相当于不循环,指定多个
// 要不要添加开始series索引和开始的data索引?
if (options) {
options.interval = options.interval || defaultOptions.interval;
options.loopSeries = options.loopSeries || defaultOptions.loopSeries;
options.seriesIndex = options.seriesIndex || defaultOptions.seriesIndex;
options.updateData = options.updateData || defaultOptions.updateData;
} else {
options = defaultOptions;
}
// 如果设置的seriesIndex无效,则默认为0
if (options.seriesIndex < 0 || options.seriesIndex >= seriesLen) {
seriesIndex = 0;
} else {
seriesIndex = options.seriesIndex;
}
/**
* 清除定时器
*/
function clearLoop() {
if (timeTicket) {
clearInterval(timeTicket);
timeTicket = 0;
}
chart.off('mousemove', stopAutoShow);
zRender.off('mousemove', zRenderMouseMove);
zRender.off('globalout', zRenderGlobalOut);
}
/**
* 取消高亮
*/
function cancelHighlight() {
/**
* 如果dataIndex为0表示上次系列完成显示,如果是循环系列,且系列索引为0则上次是seriesLen-1,否则为seriesIndex-1;
* 如果不是循环系列,则就是当前系列;
* 如果dataIndex>0则就是当前系列。
*/
let tempSeriesIndex =
dataIndex === 0
? options.loopSeries
? seriesIndex === 0
? seriesLen - 1
: seriesIndex - 1
: seriesIndex
: seriesIndex;
let tempType = chartOption.series[tempSeriesIndex].type;
if (tempType === 'pie' || tempType === 'radar' || tempType === 'map') {
chart.dispatchAction({
type: 'downplay',
seriesIndex: lastShowSeriesIndex,
dataIndex: lastShowDataIndex,
}); // wait 系列序号为0且循环系列,则要判断上次的系列类型是否是pie、radar
}
}
/**
* 自动轮播tooltip
*/
function autoShowTip() {
let invalidSeries = 0;
let invalidData = 0;
function showTip() {
// chart不在页面中时,销毁定时器
let dom = chart.getDom();
if (document !== dom && !document.documentElement.contains(dom)) {
clearLoop();
return;
}
// 判断是否更新数据
if (
dataIndex === 0 &&
!first &&
typeof options.updateData === 'function'
) {
options.updateData();
chart.setOption(chartOption);
}
let series = chartOption.series;
let currSeries = series[seriesIndex];
if (
!series ||
series.length === 0 ||
!currSeries ||
!currSeries.type ||
!currSeries.data ||
!currSeries.data.length
) {
return;
}
chartType = currSeries.type; // 系列类型
dataLen = currSeries.data.length; // 某个系列的数据个数
let tipParams = {
seriesIndex: seriesIndex,
};
switch (chartType) {
case 'pie':
// 处理饼图中数据为0或系列名为空的不显示tooltip
if (
!currSeries.data[dataIndex].name ||
currSeries.data[dataIndex].name === '空' ||
!currSeries.data[dataIndex].value
) {
invalidData += 1;
dataIndex = (dataIndex + 1) % dataLen;
if (options.loopSeries && dataIndex === 0) {
// 数据索引归0表示当前系列数据已经循环完
// 无效数据个数个总数据个数相等,则该系列无效
if (invalidData === dataLen) {
invalidSeries += 1;
}
// 新系列,重置无效数据个数
invalidData = 0;
// 系列循环递增1
seriesIndex = (seriesIndex + 1) % seriesLen;
// 系列数循环至起始值时重置无效系列数
if (seriesIndex === options.seriesIndex) {
if (seriesLen !== invalidSeries) {
// 下一次系列轮回,重置无效系列数
invalidSeries = 0;
showTip();
} else {
// 下一次系列轮回,重置无效系列数
invalidSeries = 0;
clearLoop();
}
} else {
showTip();
}
} else if (!options.loopSeries && dataIndex === 0) {
if (dataLen !== invalidData) {
invalidData = 0;
showTip();
} else {
invalidData = 0;
clearLoop();
}
} else {
showTip();
}
return;
}
// eslint-disable-next-line no-fallthrough
case 'map':
case 'chord':
tipParams.name = currSeries.data[dataIndex].name;
break;
case 'radar': // 雷达图
tipParams.seriesIndex = seriesIndex;
// tipParams.dataIndex = dataIndex;
break;
case 'lines': // 线图地图上的lines忽略
dataIndex = 0;
seriesIndex = (seriesIndex + 1) % seriesLen;
invalidSeries++; // 记录无效系列数,如果无效系列数和系列总数相等则取消循环显示
if (seriesLen !== invalidSeries) {
showTip();
} else {
clearLoop();
}
return;
default:
tipParams.dataIndex = dataIndex;
break;
}
if (chartType === 'pie' || chartType === 'radar' || chartType === 'map') {
if (!first) {
cancelHighlight();
}
// 高亮当前图形
chart.dispatchAction({
type: 'highlight',
seriesIndex: seriesIndex,
dataIndex: dataIndex,
});
}
// 显示 tooltip
tipParams.type = 'showTip';
chart.dispatchAction(tipParams);
lastShowSeriesIndex = seriesIndex;
lastShowDataIndex = dataIndex;
dataIndex = (dataIndex + 1) % dataLen;
if (options.loopSeries && dataIndex === 0) {
// 数据索引归0表示当前系列数据已经循环完
invalidData = 0;
seriesIndex = (seriesIndex + 1) % seriesLen;
if (seriesIndex === options.seriesIndex) {
invalidSeries = 0;
}
}
first = false;
}
showTip();
timeTicket = setInterval(showTip, options.interval);
}
// 关闭轮播
function stopAutoShow() {
if (timeTicket) {
clearInterval(timeTicket);
timeTicket = 0;
if (chartType === 'pie' || chartType === 'radar' || chartType === 'map') {
cancelHighlight();
}
}
}
let zRender = chart.getZr();
function zRenderMouseMove(param) {
if (param.event) {
// 阻止canvas上的鼠标移动事件冒泡
// param.event.cancelBubble = true;
}
stopAutoShow();
}
// 离开echarts图时恢复自动轮播
function zRenderGlobalOut() {
// console.log("移出了")
// console.log(timeTicket)
if (!timeTicket) {
autoShowTip();
}
}
// 鼠标在echarts图上时停止轮播
chart.on('mousemove', stopAutoShow);
zRender.on('mousemove', zRenderMouseMove);
zRender.on('globalout', zRenderGlobalOut);
autoShowTip();
return {
clearLoop: clearLoop
};
}
2、在需要使用该方法的文件里引入
import { loopShowTooltip } from "../../../tooltip-auto-show-vue.js";
export default {
data() {
return {
tootipTimer:""
};
},
}
3、在chart方法中,引用刚才封装的js方法
myChart.setOption(option);
this.tootipTimer && this.tootipTimer.clearLoop(); // this.tootipTimer 在data里定义
this.tootipTimer = 0;
// 调用轮播的方法
this.tootipTimer = loopShowTooltip(myChart, option, {
interval: 2000, // 轮播间隔时间
loopSeries: true, // 是否开启轮播循环
// loopSeries: boolean类型,默认为false。true表示循环所有series的tooltip;false则显示指定seriesIndex的tooltip。
// seriesIndex: 默认为0,指定某个系列(option中的series索引)循环显示tooltip,当loopSeries为true时,从seriesIndex系列开始执行。
});
注:针对刚才的问题2,我的解决方法是在main.js全局引用echarts,在基于准备好的dom,初始化echarts实例时采用this.$echarts.init()并非echart.init().
let myChart = this.$echarts.init(document.getElementById(id));
当然,这是机缘巧合发现这样可以行得通,不知道其他因素影响会不会再次出现这个bug…