需求是展示11个指标数据的折线图,也就是11条折线,但是其实这是3组数据,值域的分布差别有点大,一组数据值域是0到0.1,一组数据的值域达到了10万,如果强行在同一个坐标系,导致数据趋势不能在图表上展示,于是,就有了显示的要求,要求三组数据分组显示,但是要在同一个X轴,也就是Y轴分组。我选择了EChart来实现。
最终实现的思路是 xAxis、yAxis和grid生成三组,xAxis和yAxis引用gridIndex,其中X轴的数据是相同的,grid设置到不同的区域,纵向排布,series设置时把相应的yAxisIndex、xAxisIndex分别设置到对应的区域,还有一个关键的交互,要求在鼠标移动时三个坐标系要同步显示标线并且tooltip展示所有的数据,代码如下

 // 过滤掉 fma he sma 为 0 的数据
    data = data.filter((item: any) => item['fma'] !== 0 && item['sma'] !== 0)

    // 获取日期数组
    const dates = data.map((item: any) => dayjs(item.timestamp).utc().format('MM-DD HH:mm:ss'));

    // 获取三组数据
    const group1 = ['market_price_ask', 'market_price_bid', 'market_price_mid', 'sma', 'fma'];
    const group2 = ['most_of_vol', 'realtime_vol'];
    const group3 = ['rs', 'rsa', 'rsd', 'rsm'];

    const series = [
      ...group1.map(symbol => ({
        name: symbol,
        type: 'line',
        showSymbol: false,
        color: getColor(symbol),
        data: data.map((item: any) => item[symbol]),
        yAxisIndex: 0,
        xAxisIndex: 0,
        lineStyle: {
          width: 1
        },
      })),
      ...group2.map(symbol => ({
        name: symbol,
        type: 'line',
        showSymbol: false,
        color: getColor(symbol),
        data: data.map((item: any) => item[symbol]),
        yAxisIndex: 1,
        xAxisIndex: 1,
        lineStyle: {
          width: 1
        },
      })),
      ...group3.map(symbol => ({
        name: symbol,
        type: 'line',
        showSymbol: false,
        color: getColor(symbol),
        data: data.map((item: any) => item[symbol]),
        yAxisIndex: 2,
        xAxisIndex: 2,
        lineStyle: {
          width: 1
        },
      })),
    ];

    if (data.length > 0) {
      chartRef.current?.setOption({
        title: {
          text: 'Price Analysis',
        },
        // 核心配置:强制所有坐标系联动
        axisPointer: {
          type: 'line', // 显示纵向指示线
          link: [{ xAxisIndex: [0, 1, 2] }], // 联动所有 x 轴
          label: { show: false } // 隐藏默认标签
        },
        tooltip: {
          trigger: 'axis',
          // 自定义 Tooltip 内容
          formatter: (params: any) => {
            const date = params[0].axisValue; // 获取当前时间点
            const allValues = data.find((d: any) => dayjs(d.timestamp).utc().format('MM-DD HH:mm:ss') === date); // 找到完整数据

            // 按分组组织内容
            return `
              <div style="padding: 8px 12px;">
                <div style="margin-bottom: 8px;font-weight: 500;">${date}</div>
                
                <div style="margin: 8px 0; color: #666;">Market Data:</div>
                ${['market_price_ask', 'market_price_bid', 'market_price_mid', 'sma', 'fma']
                .map(symbol => `
                    <div style="display: flex; align-items: center; margin: 4px 0;">
                      <span style="display: inline-block; width: 8px; height: 8px; 
                        background: ${getColor(symbol)}; margin-right: 8px;"></span>
                      ${symbol}: ${allValues[symbol].toFixed(4)}
                    </div>
                  `).join('')}

                <div style="margin: 8px 0; color: #666;">Volatility:</div>
                ${['most_of_vol', 'realtime_vol']
                .map(symbol => `
                    <div style="display: flex; align-items: center; margin: 4px 0;">
                      <span style="display: inline-block; width: 8px; height: 8px; 
                        background: ${getColor(symbol)}; margin-right: 8px;"></span>
                      ${symbol}: ${allValues[symbol].toFixed(4)}
                    </div>
                  `).join('')}

                <div style="margin: 8px 0; color: #666;">PDS:</div>
                ${['rs', 'rsa', 'rsd', 'rsm']
                .map(symbol => `
                    <div style="display: flex; align-items: center; margin: 4px 0;">
                      <span style="display: inline-block; width: 8px; height: 8px; 
                        background: ${getColor(symbol)}; margin-right: 8px;"></span>
                      ${symbol}: ${allValues[symbol].toFixed(4)}
                    </div>
                  `).join('')}
              </div>
            `;
          }
        },
        grid: [
          { // 第一组坐标系
            top: '5%',
            height: '30%',
            left: '10%',
            right: '10%'
          },
          { // 第二组坐标系
            top: '40%',
            height: '25%',
            left: '10%',
            right: '10%'
          },
          { // 第三组坐标系
            top: '70%',
            height: '20%',
            left: '10%',
            right: '10%'
          }
        ],
        legend: {
          data: [...group1, ...group2, ...group3],
        },
        xAxis: [
          { // 主 X 轴(共享)
            type: 'category',
            data: dates,
            gridIndex: 0, // 关联第一个 grid
            show: false,
          },
          { // 隐藏的副 X 轴(用于对齐)
            type: 'category',
            gridIndex: 1,
            show: false,
            data: dates,
            axisPointer: { show: true }
          },
          { // 隐藏的副 X 轴(用于对齐)
            type: 'category',
            gridIndex: 2,
            axisLabel: { show: true },
            data: dates,
            axisPointer: { show: true }
          }
        ],
        yAxis: [
          {
            type: 'value',
            name: 'Market Data',
            position: 'left',
            scale: true,
            gridIndex: 0,
          },
          {
            type: 'value',
            name: 'Volatility',
            position: 'left',
            scale: true,
            gridIndex: 1,
          },
          {
            type: 'value',
            name: 'PDS',
            position: 'left',
            scale: true,
            gridIndex: 2,
          }
        ],
        series: series,
      }, true)
    }

superMin
9 声望2 粉丝

在自己的行业内深耕