vmpowerio/chartjs-node

CanvasGradient is not defined

Closed this issue ยท 15 comments

I'm using chartjs-node to create a chart and send it in a nodejs Discord bot.

const chartNode = new ChartjsNode(300, 300);
chartNode.drawChart({
	type: 'line',
	data: {
		datasets: [{
			label: 'Ping',
			data: message.client.pings
		}]
	},
	options: {}
})
.then(() => {
	return chartNode.getImageBuffer('image/png');
}).then(stream => {
	message.channel.send({ files: [{ attachment: stream }] }).then(() => {
		chartNode.destroy();
	});
});

message.client.pings is an array of 3 numbers. The graph works fine with 1 and 2 numbers but once it gets 3 it errors with Unhandled rejection ReferenceError: CanvasGradient is not defined

Here is the whole error

1|martin   | Unhandled rejection ReferenceError: CanvasGradient is not defined
1|martin   |     at helpers.color (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.helpers.js:927:25)
1|martin   |     at ChartElement.draw (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/elements/element.point.js:93:23)
1|martin   |     at ChartElement.draw (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/controllers/controller.line.js:298:15)
1|martin   |     at Chart.drawDataset (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:573:20)
1|martin   |     at Chart.drawDatasets (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:548:9)
1|martin   |     at Chart.draw (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:510:7)
1|martin   |     at Chart.render (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:477:8)
1|martin   |     at Chart.update (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:375:8)
1|martin   |     at Chart.construct (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.controller.js:121:7)
1|martin   |     at new Chart (/home/kye/apps/martin-discord-bot/node_modules/chart.js/src/core/core.js:7:8)
1|martin   |     at jsdom.envAsync.then.window (/home/kye/apps/martin-discord-bot/node_modules/chartjs-node/index.js:80:31)
1|martin   |     at tryCatcher (/home/kye/apps/martin-discord-bot/node_modules/bluebird/js/release/util.js:16:23)
1|martin   |     at Promise._settlePromiseFromHandler (/home/kye/apps/martin-discord-bot/node_modules/bluebird/js/release/promise.js:512:31)
1|martin   |     at Promise._settlePromise (/home/kye/apps/martin-discord-bot/node_modules/bluebird/js/release/promise.js:569:18)
1|martin   |     at Promise._settlePromise0 (/home/kye/apps/martin-discord-bot/node_modules/bluebird/js/release/promise.js:614:10)
1|martin   |     at Promise._settlePromises (/home/kye/apps/martin-discord-bot/node_modules/bluebird/js/release/promise.js:693:18)```

Have you tried the demo site? Does it produce a chart?

+1
I get the same issue
On line 81 of chart.js/src/elements/element.point.js,
(chartArea.right*errMargin < model.x)
I get a trigger that this evaluates to true on some occasions (not all), in which line 93
ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
Calls chart.js/src/core/core.helpers.js where
if (value instanceof CanvasGradient) {
is undefined.

I solved the problem temporarily by commenting out line 927 and 929 of core.helpers.js to bypass this problem for now.

@SeanLMcCullough what OS is this on?

@SeanLMcCullough are you able to test the input on the demo site and see if it successfully generates a chart? That way we can tell if this is an OS specific issue. When I look up CanvasGradient stuff I'm seeing OS specific things within node-canvas on their repo.

@sedouard Just ran the source on the demo site, it ran fine and did not trigger the CanvasGradient call. My error, and @KyeNormanGill's problem is probably limited to other chart types (such as line in both of our cases). It appears to be a problem when chartjs tries to render a point outside of the chart bounds.

ChartJS has an error factor of 1.01 because (I believe) some browsers round pixels and they check to make sure they're not getting too close for comfort. I did notice once I commented out the lines for that call, that the points it rendered were right on the boundaries of the chart area. In this case it's irrelevant though, as it's not rendered in a browser, and the rendering on the server side does not have CanvasGradient defined somewhere, this is likely an issue further up the line with jsdom or node-canvas.

I agree. The fact that the demo site had no problem tells me it is an OS specific issue. (The demo site is running Ubuntu). Going to close this out.

I have the same issue on Ubuntu and I have solved it taking care of the length for the chartConfig.data.labels. It has to match at least the datasets[...].data length.

lingz commented

Fixed on my side just by declaring after my import:

if (global.CanvasGradient === undefined) {
  global.CanvasGradient = function() {};
}

Will make it pass the instanceof check.

Thanks @lingz. The global declaration solved the issue!

@lingz I encounter this issue,but the issue is just random , so can you tell me where the code "if (global.CanvasGradient === undefined) {
global.CanvasGradient = function() {};
}" should be ? Just place it after "require('chartjs-node')โ€œ๏ผŸ thanks for explanation!

@lonelywolf4git it's OK for me just after the require declaration.

If anyone still getting this I found a specific problem causing it. I had y axes values greater than options.scales.yAxes.ticks.max. I think it's trying to render outside of that range that's why it's getting the exception. Although the work arounds above does seem to work. It just hides those out of range values.

@lingz solution works, but feels hacky. Is there a cleaner solution in the source code itself?

Not complaining, just seems like something that could be resolved in the source!