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

Upgrade to Chart.js version 4 #121

Open
almeidx opened this issue Dec 2, 2022 · 10 comments
Open

Upgrade to Chart.js version 4 #121

almeidx opened this issue Dec 2, 2022 · 10 comments

Comments

@almeidx
Copy link

almeidx commented Dec 2, 2022

Just upgrading the dependency doesn't seem to be working (in ESM environments, at least)

@ajimix
Copy link

ajimix commented Dec 5, 2022

Same issue here

@Whobeu
Copy link

Whobeu commented Jan 20, 2023

I am still using CommonJS and was able to upgrade to Chart.js 4.2.0 successfully. I do not have an overly complicated project and the only breaking change I ran into (proving the upgrade did work since it was a break in my code) was:

scales[id].grid.drawBorder has been renamed to scales[id].border.display.

The release notes note that dist/chart.js is now an ESM only module and the dist/chart.min.js is now dist/chart.umd.js.

Update: I was doing testing with Node.js 18 and did a a fresh install of node_modules in a test project root. At that point, I was no longer able to run Chart.js 4.2.0. Had me very puzzled. Then I realized I had been working with a modified copy of dist/index.js where I had modified the require statement at line 149 to read require("chart.js/auto"), which was a fix I noted in issue #118 . Forgot I had left it in. Putting that back in and the Chart.js 4.2.0 install now works. I have no plans to migrate to 4.x.x any time soon but I was able to catalog the breaking changes in it for future refefence.

@Whobeu
Copy link

Whobeu commented May 2, 2023 via email

@ajimix
Copy link

ajimix commented Jul 21, 2023

The code has to be changed from

const chartJs = require('chart.js');

to

const chartJs = require('chart.js/auto');

Unfortunately looks like the project is dead

@cwtuan
Copy link

cwtuan commented Nov 4, 2023

chartjs-node-canvas doesn't support chart.js@4. However, you can simply use the canvas library instead. Here is an example for your reference.

Filename: make-image.js

const { createCanvas, registerFont } = require('canvas');
const Chart = require('chart.js/auto');

// Create a canvas and chart
const width = 800;
const height = 400;

const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');

const chartConfig = {
  type: 'bar', 
  data: {
    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
    datasets: [
      {
        label: 'My First Dataset',
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: ['red', 'blue', 'yellow', 'green', 'purple', 'orange'],
      },
    ],
  },
  options: {
    responsive: false,
    maintainAspectRatio: false,
  },
};

new Chart(ctx, chartConfig);

// Save the chart image as a file
const fs = require('fs');
const out = fs.createWriteStream('chart.png');
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on('finish', () => console.log('The chart image was saved.'));

Then, run the script via node. A image named chart.png will be generated.

➜  node make-image.js
The chart image was saved.

➜  ls -l chart.png                
-rw-r--r--  1 user1 admin    13K Nov  4 20:02 chart.png

The code is tested with [email protected] and [email protected] in [email protected].

@Whobeu
Copy link

Whobeu commented Nov 7, 2023

chartjs-node-canvas doesn't support chart.js@4. However, you can simply use the canvas library instead. Here is an example for your reference.

Filename: make-image.js

const { createCanvas, registerFont } = require('canvas');
const Chart = require('chart.js/auto');

// Create a canvas and chart
const width = 800;
const height = 400;

const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');

const chartConfig = {
  type: 'bar', 
  data: {
    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
    datasets: [
      {
        label: 'My First Dataset',
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: ['red', 'blue', 'yellow', 'green', 'purple', 'orange'],
      },
    ],
  },
  options: {
    responsive: false,
    maintainAspectRatio: false,
  },
};

new Chart(ctx, chartConfig);

// Save the chart image as a file
const fs = require('fs');
const out = fs.createWriteStream('chart.png');
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on('finish', () => console.log('The chart image was saved.'));

Then, run the script via node. A image named chart.png will be generated.

➜  node make-image.js
The chart image was saved.

➜  ls -l chart.png                
-rw-r--r--  1 user1 admin    13K Nov  4 20:02 chart.png

The code is tested with [email protected] and [email protected] in [email protected].

I have been able to get some rudimentary image generation doing the above in an existing project. I have a rather complicated graphing routine that uses several features of ChartjsNodeCanvas so it is a bit involved moving over to pure Canvas and Chart.js. As an example, I set a background color on my image using the ChartjsNodeCanvas "backgroundColour" property. However, that does not exist in either Chart.js or Canvas so it requires implementing the "beforeDraw" event myself to do it. Also finding some other minor features that appear will require my own implementation. Long term this is probably the best solution to keep up with newer releases to Chart.js.

@SawkaDev
Copy link

SawkaDev commented Nov 9, 2023

The code has to be changed from

const chartJs = require('chart.js');

to

const chartJs = require('chart.js/auto');

Unfortunately looks like the project is dead

I am starting to agree. I can't find any good alternative either.

@Whobeu
Copy link

Whobeu commented Nov 9, 2023

The code has to be changed from

const chartJs = require('chart.js');

to

const chartJs = require('chart.js/auto');

Unfortunately looks like the project is dead

I am starting to agree. I can't find any good alternative either.

The best alternative is to do what @cwtuan documented above and switch to Canvas and Chart.js directly. It took a little work but I was able to replicate the functionality of ChartJsNodeCanvas that I needed using Canvas and Chart.js directly. The issues I ran into were needing to add the maintainAspectRatio option, having to create a tiny plugin to set the canvas background color and needing to wrap canvas.toBuffer() and canvas.toDataURL in Promises within my code. Otherwise implementation was very easy. I also duplicate my projects in Typescript as a sanity check and the only issue I had was passing Canvas context to Chart instantiation:

const ctx = canvas.getContext("2d");
const chart = new Chart(ctx as unknown as ChartItem, configuration);

Chart refuses to accept the context as any of the ChartItem types so I had to cast it to "unknown" and then to ChartItem. It works but Typescript has a fit with the current type definitions.

At this point I am free to upgrade to newer releases of Canvas or Chart.js as needed.

@SawkaDev
Copy link

SawkaDev commented Nov 9, 2023

The best alternative

I have tried that, but have so many issues it (using nextjs and it really does not get along with canvas). I keep getting this error

error - Error: The specified procedure could not be found.
\\?\C:\Users\......\node_modules\canvas\build\Release\canvas.node
code: 'ERR_DLOPEN_FAILED',

Have tried so many different things, which is why I am just on the hunt for something else sadly. I really do like chartjs and may give it a few more hours of trial and error to see if I can get it to work

EDIT: Fixed the issue via solution here: Automattic/node-canvas#2152

@himalayanelixir
Copy link

Thanks so much for all the discussion here it really helped me a lot. Just wanted to share what is working really well for me. It's a compilation of a lot the suggestions above.

"node": "21.7.3"
"typescript": "5.4.4"
"chart.js": "4.4.2"
"canvas": "2.11.2"
import { Chart } from "chart.js/auto";
import { createCanvas } from "canvas";
import * as fs from "node:fs";
import { ChartConfiguration } from "chart.js";

export function generateChart(): string {
  const width = 800;
  const height = 400;
  const canvas = createCanvas(width, height);
  const ctx = canvas.getContext("2d") as unknown as CanvasRenderingContext2D;

  const chartConfig: ChartConfiguration = {
    type: "bar",
    data: {
      labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
      datasets: [
        {
          label: "My First Dataset",
          data: [12, 19, 3, 5, 2, 3],
          backgroundColor: [
            "red",
            "blue",
            "yellow",
            "green",
            "purple",
            "orange",
          ],
        },
      ],
    },
    options: {
      responsive: false,
      maintainAspectRatio: false,
    },
  };

  new Chart(ctx, chartConfig);
  const buffer = canvas.toBuffer("image/png");
  fs.writeFileSync("images/test-chart.png", buffer);

  return "test-chart.png";
}

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

No branches or pull requests

6 participants