chart.js v3 - data decimation not working with zoom plugin

1.3k views Asked by At

In chart.js v3 data decimation doesn't work when zooming in via the zoom plugin.

Initially at 100%, data decimation works, but if I zoom in it's no longer working (i.e. shows all points)

If I zoom out to 100% again then data decimation works again.

Any ideas on how to fix this? Do I need to call something to trigger data decimation after a zoom event?

1

There are 1 answers

1
Nico On

I suspect that it works in fact correctly.

Code sample before some possible explaination:

var ctx = document.getElementById("myChart");
var nbPoints = 1000;
var samplesPoints = 100;
var thresholdsPoints = 900;
var dataArr = []
for (let i = 0; i < nbPoints; i++) {
  dataArr.push({x: i, y: Math.floor(Math.random() * 100)})
}
var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        datasets: [{
            label: '# of Votes',
            data: dataArr
        }]
    },
    options: {
      parsing: false,
      normalized: true,
      animation: false,
      responsive: false,
      plugins: {
        decimation: {
          enabled: true,
          samples: samplesPoints,
          threshold: thresholdsPoints,
          algorithm: 'lttb'
        },
        zoom: {
          limits: {
            x: { min: 0, max: nbPoints }
          },
          pan: {
            enabled: true,
            mode: 'x'
          },
          zoom: {
            wheel: {
              enabled: true
            },
            pinch: {
              enabled: true
            },
            mode: 'x'
          }
        }
      },
      scales: {
        x: {
          type: 'linear'
        }
      }
    }
});

function resetZoom() {
  myChart.resetZoom();
}
.myChartDiv {
  max-width: 600px;
  max-height: 400px;
}
<script src="https://npmcdn.com/[email protected]/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://npmcdn.com/[email protected]/dist/chartjs-plugin-zoom.min.js"></script>
<div class="myChartDiv">
  <canvas id="myChart" width="600" height="400"></canvas>
</div>
<div class="myButton">
  <button onclick="resetZoom()">Reset Zoom</button>
</div>

It was due to a modification that was proposed a while ago: the idea was to re-perform decimation each time you zoom in order to have the "highest resolution" possible (for history: https://github.com/chartjs/Chart.js/issues/8833)

But the thing that you probably missed (I suppose) are the following properties of the decimation plugin (https://www.chartjs.org/docs/master/configuration/decimation.html#configuration-options):

  • Samples: How many points you want to have after decimation
  • Threshold: Above which number of point you want the decimation happen. Often, you might want samples = threshold, but that is not mandatory.

And the "problem" is probably the default values of each of these:

  • sample: Defaults to the canvas width to pick 1 sample per pixel.
  • threshold: Defaults to 4 times the canvas width.

Meaning that for a 800px graph, you will have 800 points, and decimation will happen only if you have more than 800*4 points on the current range.

So what I suppose is happening: you have let say 1000 points that you display on a 200px graph. At first everything is ok, but once you zoom, you have 750 points, which will be less than 200*4, so decimation won't happen and you will have in fact 750 points (while you would expect 200)

In the end, you might want to update your decimation plugin configuration with something like:

decimation: {
    enabled: true,
    algorithm: 'lttb',
    samples: 800,
    threshold: 800
}