Chart.js でリアルタイムストリーミングデータをグラフ化

# はじめに

リアルタイムストリーミングデータを可視化したくてグラフライブラリを探していたら、結構たくさん出てきた[^1]

[^1]: まだまだある。この[まとめ](https://medium.com/@alberto.park/a-simple-guide-how-to-select-a-chart-library-to-use-6f17878248f0)がよい

* [APEXCHARTS.JS](https://apexcharts.com/javascript-chart-demos/line-charts/realtime/)
* [Epoch](https://epochjs.github.io/epoch/real-time/)
* [HIGHCHARTS](https://www.highcharts.com/demo/?example=dynamic-update&theme=default)
* [amCharts](https://www.amcharts.com/demos/live-data/)
* [Rickshaw](https://tech.shutterstock.com/rickshaw/)
* [Chart.js](https://www.chartjs.org/)
* [billboard.js](https://naver.github.io/billboard.js/)

# Chart.js

今回は、`Chart.js` でいくことに。理由は[このプラグイン](https://nagix.github.io/chartjs-plugin-streaming/ja/)がよさげだったから。サイトの説明もわかりやすい

![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32540/a988cf62-f687-40a5-6419-f9c428e49296.gif)

## とりあえず動かす

コピペで動くはず

```html:real-time-chart.html
<!DOCTYPE html>
<html lang="en">
<head>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@latest/dist/chartjs-plugin-streaming.min.js"></script>
</head>

<body>

<canvas id="myChart"></canvas>

<script>
// CHART
var chartColors = {
  red: 'rgb(255, 99, 132)',
  orange: 'rgb(255, 159, 64)',
  yellow: 'rgb(255, 205, 86)',
  green: 'rgb(75, 192, 192)',
  blue: 'rgb(54, 162, 235)',
  purple: 'rgb(153, 102, 255)',
  grey: 'rgb(201, 203, 207)'
};

var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
  type: 'line',
  data: {
    datasets: [{
      label: 'Power',
      borderColor: chartColors.red,
      fill: false,
      data: []
    },
    {
       label: 'Temperature',
       borderColor: chartColors.blue,
       fill: false,
       cubicInterpolationMode: 'monotone',
       data: []
    },
    {
      label: 'Humidity',
      borderColor: chartColors.yellow,
      fill: false,
      cubicInterpolationMode: 'monotone',
      data: []
    }]
  },
  options: {
    legend: {
      position: 'bottom'
    },
    scales: {
      xAxes: [{
        type: 'realtime',
        realtime: {
          delay: 2000,
          onRefresh: function(chart) {
            chart.data.datasets.forEach(function(dataset) {
              dataset.data.push({
                x: Date.now(),
                y: Math.random()
              });
            });
          }
        }
      }]
    }
  }
});
</script>
</body>
</html>

```

# 実際の使い方

今回は、実際のデータがこんな感じだったので

```json
{psn: 1, time: "1588382630511", name: "sensor1", amp: 4.97, tem: 6.72, hum: 8.22}
```

`forEach` じゃなくて、以下のようにした。`dequeue()` で配列から上記 JSON データを `onRefresh` の度に、一つもってくる感じ

```javascript

        realtime: {
          delay: 3000,
          onRefresh: function(chart) {
            let sensorData = dequeue(); // {psn: 1, time: "1588382630511", name: "sensor1", amp: 4.97, tem: 6.72, hum: 8.22}
            let timeFromSensor = new Date(parseInt(sensorData.time));
            // Power
            chart.data.datasets[0].data.push({
              x: timeFromSensor,
              y: sensorData.amp
            });
            // Temperature
            chart.data.datasets[1].data.push({
              x: timeFromSensor,
              y: sensorData.tem
            });
            // Humidity
            chart.data.datasets[2].data.push({
              x: timeFromSensor,
              y: sensorData.hum
            });
          }
        }
```