echarts tooltip 轮播

91 阅读2分钟

🔥 手撸一个 ECharts 图表自动轮播组件,让数据"动"起来

本文将带你封装一个开箱即用的 ECharts 图表轮播控制器,支持自动高亮、智能暂停、多系列管理,让你的数据可视化瞬间提升一个档次。

AEqBALEI_converted.gif

一、背景

想象一下这样的场景:

  • 📊 大屏展示时,数据自动轮播高亮,无需人工干预
  • 🖱️ 用户点击查看详情时,自动暂停,看完继续轮播
  • 🎯 支持多图表统一管理,页面切换时自动销毁

核心能力一览

功能说明
⏯️ 自动轮播定时高亮不同数据点,支持自定义间隔
🛑 智能暂停点击交互时暂停,避免打断用户操作
🎮 手动控制提供 start/stop/pause/resume 完整 API
📦 多实例管理支持一个页面多个图表独立控制

二、核心实现:不到 100 行的轮播控制器

2.1 创建轮播控制器

/**
 * 创建图表轮播控制器
 * @param {Object} chartInstance - ECharts 实例
 * @param {Number} dataLen - 数据长度
 * @param {Array} seriesIndexes - 系列索引数组,支持多个系列同时高亮,默认 [0]
 * @param {Number} interval - 轮播间隔(毫秒),
 * @returns {Object} 控制器对象,包含 stop、pause、resume、start 方法
 */
export const createCarousel = (chartInstance, dataLen, seriesIndexes = [0], interval = 2000) => {
  if (!chartInstance || dataLen === 0) return null;
  
  let timer = null;
  let currentIndex = -1;
  let isPaused = false;
  
  const stop = () => {
    if (timer) {
      clearInterval(timer);
      timer = null;
    }
  };
  
  const pause = () => {
    isPaused = true;
  };
  
  const resume = () => {
    isPaused = false;
  };
  
  const start = () => {
    stop();
    currentIndex = -1;
    
    timer = setInterval(() => {
      if (isPaused) return;
      
      currentIndex = (currentIndex + 1) % dataLen;

      // 显示 tooltip(使用第一个系列索引)
      chartInstance.dispatchAction({
        type: 'showTip',
        seriesIndex: seriesIndexes[0],
        dataIndex: currentIndex
      });
    }, interval);
  };
  
  // 立即启动
  start();
  
  return {
    stop,
    pause,
    resume,
    start
  };
};

💡 设计亮点

  1. 模块化:纯函数封装,不依赖 Vue/React,任何项目都能用
  2. 防御性:参数校验 + 自动清理,避免内存泄漏
  3. 状态管理isPaused 标记实现真正的暂停(而非停止)

2.2 绑定交互事件

/**
 * 设置图表交互监听
 * @param {Object} chartInstance - ECharts 实例
 * @param {Object} controller - 轮播控制器对象
 * @param {Number} pauseDuration - 点击后暂停时长(毫秒),默认3000
 */
export const setupChartInteraction = (chartInstance, controller, pauseDuration = 10000) => {
  if (!chartInstance || !controller) return;
  
  const zr = chartInstance.getZr();
  
  // 点击时暂停一段时间
  zr.on('click', () => {
    controller.pause();
    setTimeout(() => {
      controller.resume();
    }, pauseDuration);
  });
};

三、实战用法:三种典型场景

场景 1:单图表快速接入

import { createCarousel, setupChartInteraction } from './chartCarousel.js';


const controller = createCarousel(chartInstance, dataLen, [0], 3000);
setupChartInteraction(chartInstance, controller);


onBeforeUnmount(() => {
  controller.stop();
});

场景 2:多图表统一管理(推荐

import { ref, onBeforeUnmount } from 'vue';
import { createCarousel, setupChartInteraction } from './chartCarousel.js';

// 统一管理所有轮播控制器
const carouselControllers = ref([]);

// 初始化多个图表
const initCharts = () => {
  // 图表 1:销售额趋势
  const chart1 = echarts.init(document.getElementById('chart1'));
  const ctrl1 = createCarousel(chart1, 12, [0], 2000);
  setupChartInteraction(chart1, ctrl1);
  carouselControllers.value.push(ctrl1);
  
  // 图表 2:用户分布
  const chart2 = echarts.init(document.getElementById('chart2'));
  const ctrl2 = createCarousel(chart2, 5, [0, 1], 3000); // 同时高亮两个系列
  setupChartInteraction(chart2, ctrl2);
  carouselControllers.value.push(ctrl2);
};

// 页面离开时一键清理
onBeforeUnmount(() => {
  carouselControllers.value.forEach(ctrl => ctrl.stop());
  carouselControllers.value = [];
});