javascriptcontrollerchart.jsword-cloud

Chart.js register functions not recognizing any extensions (chartjs-chart-geo and chartjs-chart-wordcloud)


I'm working on a dashboard for a web application. The application uses Flask, and the dashboard is built with the Chart.js framework. For some charts, such as a word cloud and a Choropleth to display an interactive map, I'm using Chart.js extensions, specifically chartjs-chart-wordcloud and chartjs-chart-geo, respectively. The plotting of these charts was working fine until, without any noticeable changes on my part, I started receiving the error: "Uncaught Error: 'wordCloud' is not a registered controller." and a similar error for the Choropleth chart. I am registering both controllers from these extensions.

I’ve tried other ways of importing, but I haven’t had any success. This is my code:

import {Chart, registerables} from 'https://esm.sh/chart.js@4.4.4';
import {WordCloudController, WordElement} from 'https://esm.sh/chartjs-chart-wordcloud@4.4.4';
import {
    topojson,
    ChoroplethController,
    GeoFeature,
    ProjectionScale,
    ColorScale,
    } from 'https://esm.sh/chartjs-chart-geo@4.3.4';


Chart.register(WordCloudController, WordElement, ChoroplethController, GeoFeature, ProjectionScale, ColorScale, ...registerables)

// [...]

function insert_cloud_word_chart(element, infos) {
    const config = {
        type: WordCloudController.id,
        data: {
            labels: infos['labels'],
            datasets: [
                {
                    label: 'Frequência',
                    data: infos['data'],
                },
            ],
        },
        options: {
            responsive: false,
            maintainAspectRatio: false,
            plugins: {
                legend: {
                    display: false
                },
            },
            elements: {
                word: {
                    fontFamily: 'sans-serif',
                    color: (ctx) => {
                        // Define uma cor para cada palavra com base no índice
                        const colors = ['#003D6A', '#22CBE4', '#2662F0', '#333333'];
                        return colors[ctx.index % colors.length];
                    },

                }
            }
        },
    }

    new Chart(element, config)
}

I also used the console.log(Chart.registry.controllers) function to check if Chart.js was correctly registering the controllers. The result showed that even though I called the function and the controllers were imported correctly, they are not being registered.


Solution

  • TL;DR

    You have to make sure that you import the same version of chart.js from esm.sh that is imported by the extension modules, chartjs-chart-wordcloud and chartjs-chart-geo.

    Look into the file at https://esm.sh/chartjs-chart-wordcloud@4.4.4 and see what version of chart.js it imports. Currently, it's chart.js@4.4.6 (although the latest version of chart.js in existence right now is 4.4.7).

    Make sure that you import the exact same version in your project,

    import {Chart, registerables} from 'https://esm.sh/chart.js@4.4.6';
    

    The same with https://esm.sh/chartjs-chart-geo@4.3.4 - fortunately, it's the same chart.js@4.4.6.

    Details

    Probably someone bumped the dependencies in existing extension modules of chart.js on https://esm.sh to version 4.4.6, leaving behind those who linked to previous versions.

    As it happens, there is right now a (probably short-lived) lack of version synchronization, since https://esm.sh/chart.js, https://esm.sh/chart.js@4 and https://esm.sh/chart.js@4.4, all link to the true last version, which is 4.4.7, while all last-version links to https://esm.sh/chartjs-chart-wordcloud link to version 4.4.6, so a possible best-practice recommendation to use only major version links in your code won't work either. The truth is, chart.js version updates were uncommonly often lately.

    When the versions of imported libraries like chart.js match, everything works nicely, as there is only one copy of chart.js used (e.g., in this case referenced internally as "/v135/chart.js@4.4.6/es2022/chart.mjs";) and everything works the same as when installed locally with the likes of npm.

    When the versions don't match, in the best case you get a bloated bundle with multiple (slightly different) copies for parts of the code.

    (Tedious) explanation of the chart.js issue

    In the worst case, you get errors, and we were here with the OP code. What actually happened was that WordCloudController was registered as a plugin (by the call to Chart.register) and not as a controller as it should.

    Tracking the source code for Chart.register, (defined in core.controller.js#L131, to core.registry#L25, then to core.registry#L127, and finally to core.typedRegistry.js#L17, plus core.registry.js#L12) one gets that a class sent as argument to the call to Chart.register is recognized as a custom controller if it derived from DatasetController, as a custom scale if it derived Scale, as a custom element if it derived from Element and if all the above fail, it is taken to be a plugin.

    Now, WordCloudController is indeed derived from DatasetController, (see source code WordCloudController.ts#L35), and as such it should have been registered as a controller, but in the original setting WordCloudController was derived from DatasetController of chart.js@4.4.6, while TypedRegistry#isOfType checked that it had in its prototype chain DatasetController of chart.js@4.4.4, and it didn't, so it registered it as a plugin, hence the error 'wordCloud' is not a regitered controller ('wordCloud' is WordCloudController.id).