Skip to content

Commit

Permalink
Add support for Chart.js v4 (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
typpo committed Dec 15, 2022
1 parent 8b0fb9a commit a341079
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 22 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -42,9 +42,9 @@ The chart configuration object is based on the popular Chart.js API. Check out

QuickChart includes many Chart.js plugins that allow you to add chart annotations, data labels, and more: `chartjs-plugin-datalabels`, `chartjs-plugin-annotation`, `chartjs-plugin-piechart-outlabels`, `chartjs-chart-radial-gauge`, `chartjs-chart-box-and-violin-plot `, `chartjs-plugin-doughnutlabel`, and `chartjs-plugin-colorschemes`.

### Chart.js v3
### Chart.js versions

Chart.js v3 is supported via the `version` parameter ([documentation](https://quickchart.io/documentation/) to read more about parameters). Custom chart plugins such as annotations and outlabels are disabled for >= 3.0.0 due to lack of support.
Chart.js v3 and v4 are supported via the `version` parameter ([documentation](https://quickchart.io/documentation/) to read more about parameters). Custom chart plugins such as annotations and outlabels currently not available for >= 3.0.0.

Each QuickChart instance should use 1 specific version of the Chart.js library. Mixing and matching versions (e.g., rendering a v2 chart followed by a v3 chart) is not well supported.

Expand Down
41 changes: 22 additions & 19 deletions lib/charts.js
Expand Up @@ -27,7 +27,17 @@ const MAX_WIDTH = process.env.CHART_MAX_WIDTH || 3000;

const rendererCache = {};

function getRenderer(width, height, version, format) {
async function getChartJsForVersion(version) {
if (version && version.startsWith('4')) {
return (await import('chart.js-v4/auto')).Chart;
}
if (version && version.startsWith('3')) {
return require('chart.js-v3');
}
return require('chart.js');
}

async function getRenderer(width, height, version, format) {
if (width > MAX_WIDTH) {
throw `Requested width exceeds maximum of ${MAX_WIDTH}`;
}
Expand All @@ -37,9 +47,8 @@ function getRenderer(width, height, version, format) {

const key = `${width}__${height}__${version}__${format}`;
if (!rendererCache[key]) {
rendererCache[key] = new CanvasRenderService(width, height, undefined, format, () => {
return version.startsWith('3') ? require('chart.js-v3') : require('chart.js');
});
const Chart = await getChartJsForVersion(version);
rendererCache[key] = new CanvasRenderService(width, height, undefined, format, () => Chart);
}
return rendererCache[key];
}
Expand Down Expand Up @@ -111,7 +120,7 @@ function patternDraw(shapeType, backgroundColor, patternColor, requestedSize) {
return pattern.draw(shapeType, backgroundColor, patternColor, size);
}

function renderChartJs(
async function renderChartJs(
width,
height,
backgroundColor,
Expand All @@ -135,7 +144,7 @@ function renderChartJs(
pattern: {
draw: patternDraw,
},
Chart: version.startsWith('3') ? require('chart.js-v3') : require('chart.js'),
Chart: getChartJsForVersion(version),
},
});
chart = vm.run(`module.exports = ${untrustedChart}`);
Expand Down Expand Up @@ -368,11 +377,11 @@ function renderChartJs(
}
logger.debug('Chart:', JSON.stringify(chart));

if (version.startsWith('3')) {
if (version.startsWith('3') || version.startsWith('4')) {
require('chartjs-adapter-moment');
}
if (!chart.plugins) {
if (version.startsWith('3')) {
if (version.startsWith('3') || version.startsWith('4')) {
chart.plugins = [];
} else {
const chartAnnotations = require('chartjs-plugin-annotation');
Expand Down Expand Up @@ -415,19 +424,13 @@ function renderChartJs(
});
}

const canvasRenderService = getRenderer(width, height, version, format);
const canvasRenderService = await getRenderer(width, height, version, format);

try {
if (format === 'svg') {
// SVG rendering doesn't work asychronously.
return Promise.resolve(canvasRenderService.renderToBufferSync(chart, 'image/svg+xml'));
}
return canvasRenderService.renderToBuffer(chart);
} catch (err) {
// canvasRenderService doesn't seem to be throwing errors correctly for
// certain chart errors.
return Promise.reject(err.message || err);
if (format === 'svg') {
// SVG rendering doesn't work asychronously.
return canvasRenderService.renderToBufferSync(chart, 'image/svg+xml');
}
return canvasRenderService.renderToBuffer(chart);
}

module.exports = {
Expand Down
3 changes: 2 additions & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "quickchart",
"version": "1.7.1",
"version": "1.8.0",
"main": "index.js",
"license": "AGPL-3.0",
"homepage": "https://quickchart.io/",
Expand All @@ -26,6 +26,7 @@
"canvas-5-polyfill": "^0.1.5",
"chart.js": "^2.9.4",
"chart.js-v3": "npm:chart.js@3.9.1",
"chart.js-v4": "npm:chart.js@4.0.1",
"chartjs-adapter-moment": "https://github.com/typpo/chartjs-adapter-moment.git#e9bc92ab6e0e500c91c4a9871db7b14d15b5c2e7",
"chartjs-chart-box-and-violin-plot": "^2.4.0",
"chartjs-chart-radial-gauge": "^1.0.3",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Expand Up @@ -993,6 +993,11 @@ charenc@0.0.2:
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.9.1.tgz#3abf2c775169c4c71217a107163ac708515924b8"
integrity sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==

"chart.js-v4@npm:chart.js@4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.0.1.tgz#93d5d50ac222a5b3b6ac7488e82e1553ac031592"
integrity sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==

chart.js@^2.4.0, chart.js@^2.8.0, chart.js@^2.9.4:
version "2.9.4"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
Expand Down

0 comments on commit a341079

Please sign in to comment.