You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue集成BillboardJS实现跨图表悬停提示与垂直线同步效果

实现Vue + BillboardJS多图表同步悬停效果

我之前在项目里也遇到过一模一样的需求,折腾了一阵终于搞定了。核心思路就是共享悬停状态 + 手动控制所有图表的tooltip和垂直线显示,下面给你详细讲实现步骤和代码示例:

核心思路

  1. 在Vue组件中统一管理所有BillboardJS实例,以及共享的悬停状态(当前悬停的X轴值、是否处于悬停状态)
  2. 给每个图表绑定onover/onout事件,触发时更新共享状态
  3. 监听共享状态的变化,同步调用所有图表的API来显示/隐藏tooltip和垂直悬停线

具体实现代码

Vue组件示例

<template>
  <div class="chart-container">
    <div ref="chart1" class="chart-item"></div>
    <div ref="chart2" class="chart-item"></div>
    <div ref="chart3" class="chart-item"></div>
  </div>
</template>

<script>
import bb from 'billboard.js'
import 'billboard.js/dist/billboard.min.css'

export default {
  name: 'SyncHoverCharts',
  data() {
    return {
      // 存储所有图表实例
      chartInstances: [],
      // 当前悬停的X轴值
      hoveredX: null,
      // 是否处于悬停状态
      isHovering: false
    }
  },
  mounted() {
    // 初始化3个示例图表,你可以根据自己的需求修改数据和配置
    this.initChart(this.$refs.chart1, [['sales', 100, 200, 150, 300, 250, 400]])
    this.initChart(this.$refs.chart2, [['traffic', 50, 150, 100, 250, 200, 350]])
    this.initChart(this.$refs.chart3, [['conversion', 10, 25, 15, 30, 20, 40]])
  },
  watch: {
    // 监听悬停的X轴值变化,同步所有图表
    hoveredX(newX) {
      if (this.isHovering) {
        this.syncChartHoverStates(newX)
      }
    },
    // 监听悬停状态结束,清除所有图表的悬停效果
    isHovering(isActive) {
      if (!isActive) {
        this.clearAllHoverEffects()
      }
    }
  },
  methods: {
    /**
     * 初始化单个图表
     * @param {HTMLElement} el 图表绑定的DOM元素
     * @param {Array} data 图表数据
     */
    initChart(el, data) {
      const chart = bb.generate({
        bindto: el,
        data: {
          columns: data,
          type: 'line'
        },
        axis: {
          x: {
            type: 'category',
            categories: ['周一', '周二', '周三', '周四', '周五', '周六']
          }
        },
        tooltip: {
          // 禁用默认tooltip自动显示,我们手动控制
          show: false
        },
        point: {
          // 启用点的悬停高亮
          focus: { expand: true }
        },
        // 鼠标悬停到图表上时触发
        onover: (event) => {
          // 获取当前悬停点的X轴值(如果是数值型X轴,直接取event.x即可)
          const targetX = event.x
          this.hoveredX = targetX
          this.isHovering = true
        },
        // 鼠标移出图表时触发
        onout: () => {
          this.isHovering = false
        }
      })

      // 将图表实例存入数组,方便后续统一控制
      this.chartInstances.push(chart)
    },

    /**
     * 同步所有图表的悬停效果
     * @param {String|Number} xVal 当前悬停的X轴值
     */
    syncChartHoverStates(xVal) {
      this.chartInstances.forEach(chart => {
        // 1. 显示对应X轴值的tooltip
        // 找到当前X轴值对应的数据点索引
        const dataPoints = chart.data.targets.flatMap(target => target.values)
        const targetPoint = dataPoints.find(point => point.x === xVal)
        
        if (targetPoint) {
          chart.showTooltip({
            x: xVal,
            index: targetPoint.index
          })
        }

        // 2. 显示垂直悬停线(使用官方公开API,兼容性更好)
        chart.axis.x.focus.set(xVal)
      })
    },

    /**
     * 清除所有图表的悬停效果
     */
    clearAllHoverEffects() {
      this.chartInstances.forEach(chart => {
        chart.hideTooltip()
        chart.axis.x.focus.clear()
      })
      this.hoveredX = null
    }
  }
}
</script>

<style scoped>
.chart-container {
  padding: 20px;
}
.chart-item {
  height: 300px;
  margin-bottom: 20px;
}
</style>

关键细节说明

  1. 禁用默认Tooltip:因为我们要统一控制所有图表的tooltip显示,所以关闭每个图表的自动tooltip,避免重复触发
  2. 使用官方API控制垂直线:优先用chart.axis.x.focus.set(xVal)和chart.axis.x.focus.clear()来控制垂直悬停线,比调用内部方法更稳定,避免版本更新导致失效
  3. X轴数据对齐:确保所有图表的X轴数据是完全对齐的(比如都是相同的分类或数值区间),这样同步悬停才有意义
  4. 数值型X轴适配:如果你的X轴是数值类型,直接在onover事件中取event.x即可,不需要额外处理

可能的优化点

  • 如果图表数量很多,可以考虑用防抖函数优化syncChartHoverStates方法,避免频繁触发
  • 可以给tooltip添加自定义样式,让同步显示的tooltip更统一
  • 如果需要支持鼠标在图表间移动时平滑过渡,可以调整watch的触发时机,或者使用Vue的nextTick优化

内容的提问来源于stack exchange,提问作者Rushikesh Mhetre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 09:42:37