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

Kim*_*Kim 7 javascript echarts

我有一个显示多个时间序列的图表。不同时间序列不会同时采样。有没有办法在工具提示中显示所有系列?在示例中,您可以看到所有系列都包含在前 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);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

A m*_*dev 8

解决方案说明

正如 echarts github 上的此功能请求中所述,他们计划在将来添加您正在寻找的内容。但目前来看,仍然不支持。

因此,我找到了一种解决方法,让工具提示显示所有系列,即使它们在axisPointer 所在的确切x处没有值。为此,我使用了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: ${myChart.getVisual({ seriesIndex: index }, 'color')}"></span>`
     // Add the serie's name and its value
     tooltip += `${serie.name} &emsp;&emsp; <b>${value}</b></p>`;
   });
   return tooltip;
}
Run Code Online (Sandbox Code Playgroud)

完整代码

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

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"
  }
]

option = {
  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: ${myChart.getVisual({ seriesIndex: index }, 'color')}"></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)
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

进一步的想法

  • 线性插值

我们还可以通过简单的线性插值来计算该值,而不是显示最接近的实际点的值。

线性插值
这是带有线性插值的格式化函数(不是最有效的,但有效)

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: ${myChart.getVisual({ seriesIndex: index }, 'color')}"></span> ${serie.name} &emsp;&emsp; <b>${value}</b></p>`;
   });
   return tooltip;
}
Run Code Online (Sandbox Code Playgroud)
  • 将系列显示为步骤

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

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

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

  • 表现

这些reduce()方法在处理整个系列时在大型数据集上速度很慢。例如,将其替换为二分搜索(二分搜索)将大大提高性能。

如果有人有使其性能更高的想法,我会很感兴趣。