Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception due to chartArea being undefined #432

Closed
martinslota opened this issue Jun 9, 2021 · 10 comments
Closed

Exception due to chartArea being undefined #432

martinslota opened this issue Jun 9, 2021 · 10 comments
Labels

Comments

@martinslota
Copy link

I'm not sure whether to report this here or in the Chart.js repository. I'm getting these kinds of exceptions:

Uncaught TypeError: Cannot read property 'left' of undefined
    at clipArea (helpers.segment.js:1284)
    at draw (chartjs-plugin-annotation.esm.js:1031)
    at Object.beforeDraw (chartjs-plugin-annotation.esm.js:904)
    at callback (helpers.segment.js:89)
    at PluginService._notify (chart.esm.js:4774)
    at PluginService.notify (chart.esm.js:4761)
    at Chart.notifyPlugins (chart.esm.js:5833)
    at Chart.draw (chart.esm.js:5554)
    at Chart.render (chart.esm.js:5538)
    at Chart._resize (chart.esm.js:5295)
    at Chart.resize (chart.esm.js:5273)
    at attached (chart.esm.js:5768)
    at Chart.bindResponsiveEvents (chart.esm.js:5778)
    at Chart.bindEvents (chart.esm.js:5722)
    at Chart._initialize (chart.esm.js:5251)
    at new Chart (chart.esm.js:5216)
    at renderChart (chart.tsx:53)
    at chart.tsx:146
    at invokePassiveEffectCreate (react-dom.development.js:23487)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at HTMLUnknownElement.dispatchEvent (<anonymous>)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at flushPassiveEffectsImpl (react-dom.development.js:23574)
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at flushPassiveEffects (react-dom.development.js:23447)
    at performSyncWorkOnRoot (react-dom.development.js:22269)
    at react-dom.development.js:11327
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at flushSyncCallbackQueueImpl (react-dom.development.js:11322)
    at flushSyncCallbackQueue (react-dom.development.js:11309)
    at flushPassiveEffectsImpl (react-dom.development.js:23620)
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at flushPassiveEffects (react-dom.development.js:23447)
    at react-dom.development.js:23324
    at workLoop (scheduler.development.js:417)
    at flushWork (scheduler.development.js:390)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:157)

This seems to be somewhat related to the initial state of the canvas element because it happens only in certain parts of the user interface. Postponing the creation of the plot using setTimeout(..., 0) seems to be a valid workaround for the problem.

@martinslota
Copy link
Author

One way to resolve this could be to bail out of the draw() function in case chartArea is undefined.

@martinslota
Copy link
Author

If you think that's the right thing to do, then I'll be happy to make the PR.

@kurkle
Copy link
Member

kurkle commented Jun 9, 2021

You should be constructing the Chart in useEffect or `componentDidMount´, are you?

@martinslota
Copy link
Author

I'm using react-chartjs-2 for that piece and they do seem to be using useEffect.

@kurkle
Copy link
Member

kurkle commented Jun 27, 2021

If you remove annotation plugin, does it not fail anymore?
I'm asking because it might be considered a chart.js issue because its calling the draw hooks when there is no chartArea.

@kurkle kurkle added the bug label Jul 5, 2021
@psusmars
Copy link

psusmars commented Oct 5, 2021

I am having a similar issue and can confirm that if I remove the annotation plugin it starts working

@martinslota
Copy link
Author

martinslota commented Oct 5, 2021

I see I never replied to you, @kurkle. Yes, removing the annotation plugin eliminated these exceptions for me, but I really wanted to use the plugin. 😄

Eventually I ended up working around the problem by switching away from react-chartjs-2 and using a simplified and somewhat less error-sensitive wrapper instead. It seems to work pretty reliably. Not sure this is of much use to anyone else, but here's the wrapper I use:

import type { ChartData, ChartOptions, ChartType, Plugin } from 'chart.js';
import { Chart, registerables } from 'chart.js';
import 'chartjs-adapter-moment';
import annotationPlugin from 'chartjs-plugin-annotation';
import zoomPlugin from 'chartjs-plugin-zoom';
import React, { useEffect, useRef, useState } from 'react';

Chart.register(...registerables, annotationPlugin, zoomPlugin);

export type Props = {
  type: ChartType;
  data: ChartData;
  options: ChartOptions;
  width: string;
  height: string;
  fallbackContent?: React.ReactNode;
  plugins?: Plugin[];
};

export function ChartJsComponent(props: Props): JSX.Element {
  const { data, options, width, height, fallbackContent } = props;
  const [canvas, setCanvas] = useState<HTMLCanvasElement | null>(null);
  const chartRef = useRef<Chart | null>(null);

  // needed for re-initialization of the chart using the most recent props in
  // case the canvas changes or a chart update fails
  const latestProps = useRef(props);
  useEffect(() => {
    latestProps.current = props;
  });

  // chart updates are unstable - the workaround is to attempt to re-initialize
  // the whole thing when an update throws an error
  const [forcedReinitializationCount, setForcedReinitializationCount] = useState(0);

  React.useEffect(() => {
    if (!canvas) return;

    const { type, data, options, plugins } = latestProps.current;
    const chart = new Chart(canvas, {
      type,
      data,
      options,
      plugins,
    });

    chartRef.current = chart;

    return () => {
      chartRef.current = null;
      chart.destroy();
    };
  }, [canvas, forcedReinitializationCount]);

  React.useEffect(() => {
    if (chartRef.current == null) {
      return;
    }

    try {
      const chart = chartRef.current;
      chart.options = options;
      chart.config.data = data;
      chart.update();
    } catch (error) {
      console.error('Error while updating a chart - attempting to re-initialize instead', error);
      setForcedReinitializationCount((value) => value + 1);
    }
  }, [data, options]);

  return (
    <div style={{ width, height, position: 'relative' }}>
      <canvas ref={setCanvas} role='img'>
        {fallbackContent}
      </canvas>
    </div>
  );
}

@kurkle
Copy link
Member

kurkle commented Nov 16, 2021

Thanks @martinslota

Noticed this:

// chart updates are unstable - the workaround is to attempt to re-initialize

If available, and if not due to external code, please report the errors to Chart.js repository.

@kurkle
Copy link
Member

kurkle commented Nov 20, 2021

Closing as this seems to be related to react-chartjs-2 and / or chart.js calling plugin hooks when it should not.

I could not get current chart.js master (~3.6.1) to call the hooks with undefined chartArea. If somebody still gets this, we'd need to know the exact sequence how chart is constructed and attached to DOM.

Also I'm quite sure this was fixed by chartjs/Chart.js#9557

@kurkle kurkle closed this as completed Nov 20, 2021
@jbrunton
Copy link

jbrunton commented Dec 17, 2023

Just a note, in case helpful to anyone else, that I just saw this with recent versions of chart.js (4.4.0) and react-chartjs-2 (5.2.0). It occurred for me when I added an additional dom element below the chart. As discussed above, it appears to be unrelated to this plugin, because after disabling the annotations plugin I immediately saw the same error from the datalabels plugin too.

I was able to fix it very simply, by wrapping the chart in a <div>, but I didn't explore why that might be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants