chartjs / chartjs-plugin-annotation

Annotation plugin for Chart.js
MIT License
609 stars 329 forks source link

Example "Usage" config throws uncaught error, prevents chartjs from rendering (v2.2.1) #872

Open julianna-langston opened 1 year ago

julianna-langston commented 1 year ago

Backstory I was trying to set up a codepen to try using chartjs-plugin-annotaiton. (If I just set it up wrong, I'm sorry). I created If you go look at the codepen, you'll notice that:

  1. It's the example config from the docs (docs page) (github page)
  2. there's an error message in the console.

chartjs-plugin-annotation.esm.js:940 Uncaught TypeError: Cannot set properties of undefined (setting 'backgroundColor') at ht (chartjs-plugin-annotation.esm.js:940:9) at dt (chartjs-plugin-annotation.esm.js:857:17) at Ct.resolveElementProperties (chartjs-plugin-annotation.esm.js:1249:12) at ne (chartjs-plugin-annotation.esm.js:2441:32) at Object.afterUpdate (chartjs-plugin-annotation.esm.js:2614:5) at callback (helpers.segment-1e4938ea.js:43:15) at PluginService._notify (chartjs.js:5037:11) at PluginService.notify (chartjs.js:5020:25) at Chart.notifyPlugins (chartjs.js:6266:26) at Chart.update (chartjs.js:5827:10)

So, I dug into the code. The error was thrown on this line:

function resolveLabelElementProperties(chart, properties, options) {
  const label = options.label;
  label.backgroundColor = 'transparent';

So, if options.label is considered undefined, where is options coming from?

export function resolveBoxAndLabelProperties(chart, options, centerBased) {
  const properties = resolveBoxProperties(chart, options);
  properties.initProperties = initAnimationProperties(chart, properties, options, centerBased);
  properties.elements = [{
    type: 'label',
    optionScope: 'label',
    properties: resolveLabelElementProperties(chart, properties, options),
    initProperties: properties.initProperties
  }];
  return properties;
}

which is called by

  resolveElementProperties(chart, options) {
    return resolveBoxAndLabelProperties(chart, options);
  }

...which is called from over here:

function updateElements(chart, state, options, mode) {
  const animations = resolveAnimations(chart, options.animations, mode);

  const annotations = state.annotations;
  const elements = resyncElements(state.elements, annotations);

  for (let i = 0; i < annotations.length; i++) {
    const annotationOptions = annotations[i];
    const element = getOrCreateElement(elements, i, annotationOptions.type);
    const resolver = annotationOptions.setContext(getContext(chart, element, annotationOptions));
    const properties = element.resolveElementProperties(chart, resolver);

and now we've switched from options to resolver. Maybe there's a mistake, and maybe the function is expecting an option and receiving a resolver? Maybe I'm providing the config in the wrong way? So I go look at the other pages in the docs, and I start recognizing options I saw in the code. So, I update my annotation to have these properties:

label: {
  callout: {}
}

and then I was able to move forward to another error message

Uncaught TypeError: Cannot read properties of undefined (reading 'family') at de (chartjs-plugin-annotation.esm.js:2520:19) at te (chartjs-plugin-annotation.esm.js:2397:57) at de (chartjs-plugin-annotation.esm.js:2524:22) at ae (chartjs-plugin-annotation.esm.js:2508:5) at ie (chartjs-plugin-annotation.esm.js:2486:26) at ne (chartjs-plugin-annotation.esm.js:2446:7) at Object.afterUpdate (chartjs-plugin-annotation.esm.js:2614:5) at callback (helpers.segment-1e4938ea.js:43:15) at PluginService._notify (chartjs.js:5037:11) at PluginService.notify (chartjs.js:5020:25)

which took me back to the updateElements function abov. So, another function that thought resolver would have something that it didn't. Suspicious...

What's the bug?

  1. I can't make this chart display.
  2. I found some weird console errors.

Maybe they're related?

stockiNail commented 1 year ago

@julianna-langston I think the issue is related to cdn.skypack, where we had already some issues (see #786).

If you use

import {Chart, registerables} from "https://cdn.jsdelivr.net/npm/chart.js@4.2.1/+esm";

instead of

import {Chart, registerables} from "https://cdn.skypack.dev/chart.js@4.2.1";

it works.

stockiNail commented 1 year ago

@julianna-langston let me explain better why the error is occurring. The annotation plugin is leveraging on fallback CHART.JS approach for the configuration options.

All annotation types are CHART.JS elements with their defaults. To enable it, it's mandatory to define the plugin globally because the plugin is catching the registration hook in order to register the annotation elements and then to activate the fallback.

When these kinds of errors are occurring means that the registration for whatever reason hasn't happened.

Even if we could of course check the consistency of the label object (in this case), we could have other issues (you have already seen for font) therefore the root cause is not the missing check but the missing registration of the elements.

julianna-langston commented 1 year ago

Thank you so much, and you got me unblocked with your previous comment.

Is it possible to include links in the docs to a CodePen/JSFiddle/CodeSandbox example? I always the initial setup to be the hardest with chartjs plugins (since all the working example obfuscate how imports/registrations work), so a link to a fully functioning code example would be helpful, at least to me.

stockiNail commented 1 year ago

I think it's possible, I need to check if there is already ready something as community or chartjs org. Of course I have got my codepens but I think it' better to have something at community level in order to add links to the doc. @kurkle @LeeLenaleee as far as you know, is there any community org in CodePen/JSFiddle/CodeSandbox to use to add some samples? Makes sense for you?

LeeLenaleee commented 1 year ago

I know there is a codepen account of chart.js that has some but verry outdated samples. Thats it. For the reproducible sample templates of the main repo for exaple I just used my personal account

julianna-langston commented 1 year ago

I could come up with some codepen prefills, so that it doesn't have to be hosted by any account? If you think that's a workable approach, I can file a new issue and submit a PR.