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

Apache ECharts如何实现支持整线水平拖拽的垂直markLine

问题
  • 需要在ECharts折线图中实现多条可水平拖拽的垂直标记线,要求整条垂直线任意位置都可触发拖拽、沿x轴移动,而非仅底部手柄可操作
  • 现有实现基于xAxis.axisPointer绘制垂直线,仅底部拖拽手柄支持触发拖动,无法满足交互要求
  • 当前核心实现代码:
import "./styles.css";
import echarts from "echarts";

const myChart = echarts.init(document.getElementById("app"));

const option = {
  xAxis: {
    type: "time",
    nameLocation: "center",
    nameGap: 20,
    interval: 420000,
    min: 1625741884000,
    max: 1625749084000,
    axisLabel: {
      rotate: 0
    },
    boundaryGap: ["0%", "0%"],
    axisPointer: {
      value: 1625742000000,
      snap: true,
      lineStyle: {
        color: "#ff0000",
        width: 4
      },
      handle: {
        show: true,
        color: "#ff0000"
      }
    }
  },
  yAxis: [
    {
      type: "value",
      nameLocation: "center",
      nameGap: 8,
      interval: 0.33,
      min: 1,
      max: 5.33,
      axisLabel: {
        margin: 24,
        rotate: 0
      }
    }
  ],
  series: [
    {
      id: "test",
      name: "Average Time",
      yAxisIndex: 0,
      data: [
        {
          value: [1625741884000, 1]
        },
        {
          value: [1625741885000, 1]
        },
        {
          value: [1625741890000, 1]
        },
         // 其余数据省略
      ],
      type: "line",
      showSymbol: false,
      symbolSize: 5,
      smooth: false,
      color: "#4da6e8"
    }
  ]
};

myChart.setOption(option);

效果示意图

解决方案

ECharts原生xAxis.axisPointer的拖拽热区仅绑定在底部手柄元素上,线身默认不挂载事件监听,无法通过配置直接实现整条线拖拽。需要替换实现方案:使用series.markLine渲染垂直标记线,配合zrender底层事件自定义拖拽逻辑。


实现步骤

1. 替换垂直线渲染方式

移除xAxis下的axisPointer配置,在对应折线系列中添加markLine配置绘制垂直标记线:

  • 关闭markLine的静默模式,允许响应事件
  • 移除markLine两端默认的箭头符号
  • 可适当加宽线宽、添加透明外描边扩大点击热区,降低细线条的选中难度

核心配置示例:

series: [
  {
    // 原有折线配置保持不变
    // ...
    markLine: {
      silent: false,
      symbol: 'none',
      data: [
        {
          xAxis: 1625742000000, // 初始垂直线对应的x轴时间值
          lineStyle: {
            color: '#ff0000',
            width: 4,
            // 可选:添加透明阴影扩大热区
            shadowColor: 'rgba(255,0,0,0)',
            shadowBlur: 6
          }
        }
        // 多条标记线直接在data数组中追加即可
      ]
    }
  }
]

2. 实现自定义拖拽逻辑

通过ECharts实例的zrender接口监听底层鼠标事件,分三个阶段处理拖拽:

  • 鼠标按下:判断点击位置是否命中markLine,命中则记录拖拽的线索引、初始鼠标位置、初始x轴值,开启拖拽状态
  • 鼠标移动:拖拽状态下计算鼠标水平偏移量,通过ECharts内置坐标转换方法将像素偏移转换为x轴实际数据值,更新markLine位置
  • 鼠标抬起/移出画布:清空拖拽状态,结束拖拽

核心逻辑代码:

let dragState = null

// 监听鼠标按下,检测是否选中标记线
myChart.getZr().on('mousedown', (e) => {
  const clickPoint = [e.offsetX, e.offsetY]
  if (!myChart.containPixel({seriesIndex: 0}, clickPoint)) return

  // 遍历查找命中的markLine元素
  const markLineModel = myChart.getModel().getSeriesByIndex(0).getModel('markLine')
  const lineItems = markLineModel.getData()._items
  for (let i = 0; i < lineItems.length; i++) {
    const lineEl = lineItems[i].getEl('line')
    if (lineEl.contain(e.offsetX, e.offsetY)) {
      dragState = {
        lineIndex: i,
        startPixelX: e.offsetX,
        startXValue: lineItems[i].get('xAxis')
      }
      // 设置拖拽时的光标样式
      myChart.getZr().dom.style.cursor = 'col-resize'
      break
    }
  }
})

// 监听鼠标移动,更新标记线位置
myChart.getZr().on('mousemove', (e) => {
  if (!dragState) return
  // 计算像素偏移,转换为x轴实际数据差值
  const pixelDelta = e.offsetX - dragState.startPixelX
  const valueDelta = myChart.convertFromPixel({xAxisIndex: 0}, [pixelDelta, 0])[0]
  const newXValue = dragState.startXValue + valueDelta

  // 更新markLine配置并重绘
  const newOption = myChart.getOption()
  newOption.series[0].markLine.data[dragState.lineIndex].xAxis = newXValue
  myChart.setOption(newOption)
})

// 监听鼠标抬起/移出,结束拖拽
const endDrag = () => {
  dragState = null
  myChart.getZr().dom.style.cursor = 'default'
}
myChart.getZr().on('mouseup', endDrag)
myChart.getZr().on('mouseout', endDrag)

可选优化

  • 如需吸附效果,可在计算出新x轴值后,匹配距离最近的折线数据点作为最终位置
  • 拖拽过程中可同步调用myChart.dispatchAction更新tooltip,实时显示当前标记线位置对应的数值
  • 多条标记线场景下,可给每个markLine数据项添加自定义id字段,拖拽时通过id匹配对应线,避免索引错位
  • 可额外监听markLine的mouseover/mouseout事件,非拖拽状态下悬停在线上时也显示col-resize光标,提升交互感知

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:57:20