chartjs / chartjs-plugin-zoom

Zoom and pan plugin for Chart.js
MIT License
598 stars 327 forks source link

Uncaught (in promise) TypeError: Cannot delete property '_stacks' of #<Chart> #820

Closed mewforest closed 2 weeks ago

mewforest commented 4 months ago

This error occurred when zooming a chart and the number of datasets is decreasing:

Uncaught (in promise) TypeError: Cannot delete property '_stacks' of #<Chart>
    at Chart._removeUnreferencedMetasets (chunk-OEI22TUD.js?v=8876c601:5894:7)
    at Chart.buildOrUpdateControllers (chunk-OEI22TUD.js?v=8876c601:5906:10)
    at Chart.update (chunk-OEI22TUD.js?v=8876c601:5962:33)
    at fetchData (ChartComponent.vue:917:9)

Here ChartComponent.vue:917:9 is just a chart.update() with updated dataset I've got from my API.

This is how chartjs-plugin-zoom is configured in my case:

plugins: {
      zoom: {
        zoom: {
          onZoomStart: () => (isZooming.value = true),
          onZoomComplete: () => emit('zoomComplete'),
          onZoom: (e) => {
            const { chart } = e;
            const { x } = chart.scales;
            const { min, max } = x;
            const minDate = moment(min).format( 'DD.MM.YYYY HH:mm');
            const maxDate = moment(max).format( 'DD.MM.YYYY HH:mm');

            // <-- Fetching data from my API with '${minDate}' to '${maxDate}'

            isZooming.value = false;
          },
          drag: {
            enabled: true,
          },
          mode: 'x',
        },
      },
kurkle commented 2 weeks ago

How are you updating the data to the chart?

mewforest commented 2 weeks ago

Here is part of the code where the datasets are updated (I am using Vue 3 btw):

import type { ChartData } from "chart.js";
import { Chart as ChartJS } from "chart.js";

// chart
let chart: ChartJS<"line"> | null = null;

// chart datasets
const chartData: ChartData<"line", any[], string> = {
  datasets: [],
};

// Initializing chart on component start
onMounted(async () => {
  const ctxElement = document.getElementById("chart-id");
  if (!ctxElement) return;
  const ctx = (ctxElement as HTMLCanvasElement).getContext("2d");
  if (!ctx) return;

  chart = Object.seal(
    new ChartJS(ctx, {
      type: "line",
      data: chartData,
      options: {
        responsive: true,
        maintainAspectRatio: false,
        aspectRatio: 2,
      },
      plugins: [
        /* my tooltip plugin goes here */
      ],
    }) as any
  );
});

// Updating datasets
async function fetchData(update = false) {
  let data = [];

  /* getting here `data` from api with fetch */

  chartData.datasets = data;
  chart.options = {
    /* my custom options, including plugins.zoom option, I've sent earlier */
  };
  chart.update();
}
mewforest commented 2 weeks ago

I've found a temporary solution: when the number of datasets decreases, just set deleted records to `data: null' instead of removing them.

kurkle commented 2 weeks ago

The error is raised from there: https://github.com/chartjs/Chart.js/blob/bb82c8f549374e552cc237593749eb6513d4d534/src/core/core.controller.js#L424

Which suggests this is undefined. Probably specific to Vue.

If the workaround is not enough, you should open an issue in Chart.js repository with a minimal reproduction.

As there is nothing to be done in this plugin, I'm closing this issue.