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

Apache ECharts多独立Y轴缩放持久化及setOption兼容问题

实现Apache ECharts多独立Y轴缩放及状态持久化方案

核心思路

要解决setOption后Y轴缩放状态丢失的问题,核心是为每个Y轴绑定独立的dataZoom组件,并实时保存/恢复缩放状态,同时通过replaceMerge确保ECharts合并而非重置组件配置。

具体实现步骤

1. 初始化独立的dataZoom组件

为每个Y轴创建两种类型的dataZoom:

  • type: 'inside':支持鼠标拖拽/滚轮缩放Y轴(无需显示滑块)
  • type: 'slider'(可选):点击Y轴时显示的可视化滑块

初始化时指定yAxisIndex绑定对应Y轴,并初始化状态保存对象:

// 全局保存每个Y轴的缩放状态,键为yAxisIndex
const yAxisZoomStates = {};

const myChart = echarts.init(document.getElementById('main'));

// 初始化配置
const initOption = {
  xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] },
  yAxis: [
    { type: 'value', name: '系列1' },
    { type: 'value', name: '系列2', position: 'right' }
  ],
  dataZoom: [
    // X轴全局缩放滑块
    { type: 'slider', xAxisIndex: 0, bottom: 10 },
    // Y轴1的inside缩放(支持拖拽)
    { type: 'inside', yAxisIndex: 0, orient: 'vertical' },
    // Y轴2的inside缩放
    { type: 'inside', yAxisIndex: 1, orient: 'vertical' }
  ],
  series: [
    { type: 'line', yAxisIndex: 0, data: [120, 200, 150, 80, 70, 110, 130] },
    { type: 'line', yAxisIndex: 1, data: [1000, 1200, 900, 1500, 1300, 1100, 1400] }
  ]
};

// 初始化缩放状态
initOption.dataZoom.forEach(dz => {
  if (dz.yAxisIndex !== undefined) {
    yAxisZoomStates[dz.yAxisIndex] = { start: dz.start || 0, end: dz.end || 100 };
  }
});

myChart.setOption(initOption);

2. 监听缩放事件,实时保存状态

通过datazoom事件捕获每次Y轴缩放/平移操作,更新全局状态对象:

myChart.on('datazoom', params => {
  const zoomInfo = params.batch[0];
  // 只处理Y轴的缩放事件
  if (zoomInfo.yAxisIndex !== undefined) {
    yAxisZoomStates[zoomInfo.yAxisIndex] = {
      start: zoomInfo.start,
      end: zoomInfo.end
    };
  }
});

3. 调用setOption时恢复缩放状态

无论是新增系列、切换Y轴还是其他更新操作,生成新配置时要从全局状态中恢复对应dataZoom的start和end值,同时用replaceMerge确保组件合并而非替换:

// 新增系列示例函数
function addNewSeries() {
  const currentOption = myChart.getOption();
  const newYAxisIndex = currentOption.yAxis.length;
  
  // 初始化新Y轴的缩放状态
  yAxisZoomStates[newYAxisIndex] = { start: 0, end: 100 };
  
  const newOption = {
    yAxis: [{
      type: 'value',
      name: `系列${newYAxisIndex + 1}`,
      position: newYAxisIndex % 2 === 0 ? 'left' : 'right'
    }],
    series: [{
      type: 'line',
      yAxisIndex: newYAxisIndex,
      data: [Math.random() * 500 + 500, Math.random() * 500 + 500, Math.random() * 500 + 500, Math.random() * 500 + 500, Math.random() * 500 + 500, Math.random() * 500 + 500, Math.random() * 500 + 500]
    }],
    dataZoom: [{
      type: 'inside',
      yAxisIndex: newYAxisIndex,
      orient: 'vertical',
      start: yAxisZoomStates[newYAxisIndex].start,
      end: yAxisZoomStates[newYAxisIndex].end
    }]
  };
  
  // 合并配置,保留已有组件状态
  myChart.setOption(newOption, {
    replaceMerge: ['yAxis', 'dataZoom', 'series'],
    notMerge: false
  });
  
  // 强制同步已有dataZoom的状态(避免合并时遗漏)
  const updatedDataZoom = currentOption.dataZoom.map(dz => {
    if (dz.yAxisIndex !== undefined && yAxisZoomStates[dz.yAxisIndex]) {
      return { ...dz, ...yAxisZoomStates[dz.yAxisIndex] };
    }
    return dz;
  });
  myChart.setOption({ dataZoom: updatedDataZoom }, { replaceMerge: ['dataZoom'] });
}

4. 实现点击Y轴显示/隐藏缩放滑块

如果需要点击Y轴显示对应滑块,可通过点击事件动态添加/移除slider类型的dataZoom,并加载保存的状态:

myChart.on('click', params => {
  if (params.componentType === 'yAxis') {
    const yAxisIndex = params.axisIndex;
    const currentDataZoom = myChart.getOption().dataZoom;
    const hasSlider = currentDataZoom.some(dz => dz.type === 'slider' && dz.yAxisIndex === yAxisIndex);
    
    if (hasSlider) {
      // 移除滑块
      const newDataZoom = currentDataZoom.filter(dz => !(dz.type === 'slider' && dz.yAxisIndex === yAxisIndex));
      myChart.setOption({ dataZoom: newDataZoom }, { replaceMerge: ['dataZoom'] });
    } else {
      // 添加滑块并加载保存的状态
      const zoomState = yAxisZoomStates[yAxisIndex];
      const newSlider = {
        type: 'slider',
        yAxisIndex: yAxisIndex,
        orient: 'vertical',
        left: yAxisIndex % 2 === 0 ? '3%' : '95%',
        start: zoomState.start,
        end: zoomState.end
      };
      myChart.setOption({ dataZoom: [newSlider] }, { replaceMerge: ['dataZoom'] });
    }
  }
});

关键注意事项

  • 每个dataZoom必须明确指定yAxisIndex,确保与对应Y轴绑定
  • 使用replaceMerge: ['dataZoom']时,ECharts会根据id或yAxisIndex自动合并组件,而非替换整个数组
  • 全局状态对象要覆盖所有Y轴,新增Y轴时必须初始化默认状态
  • 若存在多个dataZoom类型(inside+slider),需确保两者的状态同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:04:50