1

I'm using chart.js to plot data in real time. Currently, as new data points come in and are drawn, the old ones remain which increases the amount of points chart.js has to plot every iteration. I'd like to have a maximum number of visible points, say 20 and after 20 points are on the graph, to pan every iteration. I'm using the zoom and pan plugin. Here's my code right now

if (ticks > 20) {
    flukeChart.pan({x: 1, y: 0}, 'active');
    flukeChart.update();
}

ticks is an integer that get's incremented every time new data comes in. Another thing to note, the X axis is timestamps. I'm using the timestamp from the incoming data source and not calculating the current time in JS. I have a feeling the delta in the .pan method shouldn't be 1 because the x axis isn't integers but timestamps.

Paul Côté
  • 75
  • 1
  • 10

1 Answers1

1

You can get the pixel for the values of the timestamps. If you then subtract the first and second visable ones you can pan the chart with that amount of pixels.

const options = {
  type: 'line',
  data: {
    datasets: [{
      label: '# of Votes',
      data: [],
      borderColor: 'pink'
    }]
  },
  options: {
    scales: {
      x: {
        type: 'time'
      }
    },
  }
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
let dataPointsCounter = -1;

const interVal = setInterval(() => {
  chart.data.datasets[0].data.push({
    x: new Date(),
    y: Math.random()
  });
  dataPointsCounter++;

  if (dataPointsCounter > 20) {
    const diff = chart.scales.x.getPixelForValue(chart.data.datasets[0].data[dataPointsCounter - 21].x) - chart.scales.x.getPixelForValue(chart.data.datasets[0].data[dataPointsCounter - 20].x)
    chart.pan({
      x: diff
    }, undefined, 'default');
  }
  chart.update();
}, 500)
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
</body>

Edit:

It is not exactly what you want but you can also use the streaming plugin that handles scolling and updating for you:

const options = {
  type: 'line',
  data: {
    datasets: [{
      label: '# of Votes',
      data: [],
      borderColor: 'pink'
    }]
  },
  options: {
    scales: {
      x: {
        type: 'realtime',
        realtime: {
          duration: 7500,
          refresh: 1000,
          delay: 2000,
          onRefresh: (chart) => {
            chart.data.datasets[0].data.push({
              x: new Date(),
              y: Math.random()
            })
          }
        }
      }
    },
  }
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0"></script>
</body>
LeeLenalee
  • 27,463
  • 6
  • 45
  • 69
  • Hey this is great, thank you so much. Would this work if you had multiples datasets that share the same x axis values? Or would you need to pan every single dataset individually? – Paul Côté Nov 08 '21 at 22:23
  • I'm referring to the the code snippet before the edit. That's the solution I'm looking for. Also, would that mean needing to disable the zoom/pan plugin? I also need the ability to manually pan the chart as well as have it pan automatically – Paul Côté Nov 08 '21 at 22:45
  • If your data in the second dataset is in the same intervals it will work as intended, if the intervals are different the pan will look weird since it looks at the first dataset to figure out on how much it has to pan. About the ability to pan manually not sure if you will be able to do it since it keeps panning automatically so you will need to pause the interval and start it again – LeeLenalee Nov 08 '21 at 22:53