当系列没有相同的时间值时,如何在工具提示中显示所有系列

How can I show all series in tooltip when series does not have same time values

我有一个显示多个时间序列的图表。不同的时间序列不会同时采样。有没有办法在工具提示中显示所有系列?在示例中,您可以看到所有系列都包含在前 2 个点的工具提示中,因为它们是同时采样的。对于其余的点,仅包括 1 个系列。

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

var series = [{
    "name": "sensor 1",
    "data": [{
        "value": [
          "2019-02-20T11:47:44.000Z",
          22.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:03:02.000Z",
          22.1
        ]
      },
      {
        "value": [
          "2019-02-20T12:18:19.000Z",
          22.15
        ]
      },
      {
        "value": [
          "2019-02-20T12:33:36.000Z",
          22.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:48:53.000Z",
          22.15
        ]
      }
    ],
    "type": "line"
  },
  {
    "name": "sensor 2",
    "data": [{
        "value": [
          "2019-02-20T11:47:44.000Z",
          23.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:03:02.000Z",
          23.1
        ]
      },
      {
        "value": [
          "2019-02-20T12:22:19.000Z",
          24.15
        ]
      },
      {
        "value": [
          "2019-02-20T12:39:36.000Z",
          21.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:52:53.000Z",
          20.15
        ]
      }
    ],
    "type": "line"
  }
]

var option = {
  legend: {},
  tooltip: {
    trigger: 'axis',
  },
  xAxis: {
    type: 'time'
  },
  yAxis: {
    scale: true
  },
  series: series,
};

myChart.setOption(option);
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.0.4/echarts.min.js"></script>

<div id="main" style="width: 500px;height:400px;"></div>

解法说明

正如在 echarts 的 feature request github 中所述,他们计划在未来添加您正在寻找的内容。但是目前还是不支持。

所以我找到了一个解决方法,即使它们没有准确的 x 值,工具提示也会显示 all 系列axisPointer 在哪里。为此,我使用了工具提示 formatter,它可以定义为回调函数,每次必须更改工具提示时(即每次 axisPointer 移动到新值时)都会调用该回调函数,并且您可以在其中指定您的自己的工具提示格式。

在此函数中,您可以访问有关 axisPointer 数据的每条信息(在我们的例子中尤其是它的 xAxis)。给定 axisPointer 的 xAxis 值,我们可以遍历 series 并从该 xAxis 值中找到最接近的值。

formatter : (params) => {
   //The datetime where the axisPointer is
   var xTime = new Date(params[0].axisValue)
      
   //Create our custom tooltip and add to its top the dateTime where the axisPointer is
   let tooltip = `<p>${xTime.toLocaleString()}</p> `;
      
   //Go through each serie
   series.forEach((serie, index) => {
     //Find the closest value
     value = serie.data.reduce((prev, curr) => Math.abs(new Date(curr.value[0]).valueOf() - xTime.valueOf()) < Math.abs(new Date(prev.value[0]).valueOf() - xTime.valueOf()) ? curr : prev).value[1]
        
     /* Add a line in our custom tooltip */
     // Add the colored circle at the begining of the line
     tooltip += `<p><span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color: ${colors[index]}"></span>`
     // Add the serie's name and its value
     tooltip += `${serie.name} &emsp;&emsp; <b>${value}</b></p>`;
   });
   return tooltip;
}

完整代码

这是完整的代码,使用您的示例:

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

var series = [{
    "name": "sensor 1",
    //step: "end",
    "data": [{
        "value": [
          "2019-02-20T11:47:44.000Z",
          22.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:03:02.000Z",
          22.1
        ]
      },
      {
        "value": [
          "2019-02-20T12:18:19.000Z",
          22.15
        ]
      },
      {
        "value": [
          "2019-02-20T12:33:36.000Z",
          22.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:48:53.000Z",
          22.15
        ]
      }
    ],
    "type": "line"
  },
  {
    "name": "sensor 2",
    //step: 'end',
    "data": [{
        "value": [
          "2019-02-20T11:47:44.000Z",
          23.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:03:02.000Z",
          23.1
        ]
      },
      {
        "value": [
          "2019-02-20T12:22:19.000Z",
          24.15
        ]
      },
      {
        "value": [
          "2019-02-20T12:39:36.000Z",
          21.2
        ]
      },
      {
        "value": [
          "2019-02-20T12:52:53.000Z",
          20.15
        ]
      }
    ],
    "type": "line"
  }
]

//Used to 'recreate' the tooltip
var colors = [
    "#5470c6",
    "#91cc75",
    "#fac858",
    "#ee6666",
    "#73c0de",
    "#3ba272",
    "#fc8452",
    "#9a60b4",
    "#ea7ccc",
  ],


option = {
  color: colors,
  legend: {},
  tooltip: {
    trigger: 'axis',
    formatter : (params) => {
      //The datetime where the axisPointer is
      var xTime = new Date(params[0].axisValue)
      
      //Create our custom tooltip and add to its top the dateTime where the axisPointer is
      let tooltip = `<p>${xTime.toLocaleString()}</p> `;
      
      //Go through each serie
      series.forEach((serie, index) => {
        //Find the closest value
        value = serie.data.reduce((prev, curr) => Math.abs(new Date(curr.value[0]).valueOf() - xTime.valueOf()) < Math.abs(new Date(prev.value[0]).valueOf() - xTime.valueOf()) ? curr : prev).value[1]
        
        /* Add a line in our custom tooltip */
        // Add the colored circle at the begining of the line
        tooltip += `<p><span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color: ${colors[index]}"></span>`
        // Add the serie's name and its value
        tooltip += `${serie.name} &emsp;&emsp; <b>${value}</b></p>`;
      });
      return tooltip;
    }
  },
  xAxis: {
    type: 'time'
  },
  yAxis: {
    scale: true
  },
  series: series,
};

myChart .setOption(option)
<html>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.2/echarts.min.js"></script>
    <div id="main" style="width: 600px; height:400px;"></div>
  </body>
</html>

进一步思考

  • 线性插值

除了显示最近的真实点的值,我们还可以使用简单的线性插值来计算该值。


这是带有线性插值的格式化程序函数(不是最重要的,但可以工作)

formatter : (params) => {
   var xTime = new Date(params[0].axisValue)
   let tooltip = `<p>${xTime.toLocaleString()}</p> `;
   series.forEach((serie, index) => {
     //Only works if series is chronologically sorted
     prev_point = serie.data.reduce((prev, curr) => new Date(curr.value[0]).valueOf() <= xTime.valueOf() ? curr : prev)
     next_point = serie.data.slice(0).reduce((prev, curr, i, arr) => {
       if(new Date(curr.value[0]).valueOf() >= xTime.valueOf()) {
         arr.splice(1);
       }
       return curr
     })
     var value = 0
     if(next_point.value[1] == prev_point.value[1]){
       value = next_point.value[1]
     }
     else {
       //Linear interpolation
       value = Math.round((prev_point.value[1] + (xTime.valueOf()/1000 - new Date(prev_point.value[0]).valueOf()/1000) * ((next_point.value[1] - prev_point.value[1]) / (new Date(next_point.value[0]).valueOf()/1000 - new Date(prev_point.value[0]).valueOf()/1000)))*10)/10
     }
     tooltip += `<p><span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color: ${colors[index]}"></span> ${serie.name} &emsp;&emsp; <b>${value}</b></p>`;
   });
   return tooltip;
}
  • 将系列显示为步骤

为了在视觉上更准确,您可以将系列显示为 step: 'end' 并获取最接近的先前值,而不仅仅是 最接近的值,使用:

value = serie.data.reduce((prev, curr) => new Date(curr.value[0]).valueOf() <= xTime.valueOf() ? curr : prev).value[1]

这样做,工具提示中显示的值将与您在图表上看到的完全相同。

  • 性能

我不知道这在非常大的数据集上会有什么表现,但它可能会有点慢,因为它必须遍历整个系列。如果有人有提高性能的想法,我会很感兴趣。