chartjs-node-canvas
Version:
A node renderer for Chart.js using canvas.
154 lines (135 loc) • 6.45 kB
text/typescript
import { Stream } from 'stream';
import { Chart as ChartJS, ChartConfiguration } from 'chart.js';
import { createCanvas } from 'canvas';
import { freshRequire } from './freshRequire';
export type ChartCallback = (chartJS: typeof ChartJS) => void | Promise<void>;
export type CanvasType = 'pdf' | 'svg';
export type MimeType = 'image/png' | 'image/jpeg' | 'application/pdf' | 'image/svg+xml';
const defaultChartJsFactory: () => typeof ChartJS = () => freshRequire('chart.js');
export class CanvasRenderService {
private readonly _width: number;
private readonly _height: number;
private readonly _chartJs: typeof ChartJS;
//private readonly _createCanvas: typeof createCanvas;
private readonly _type?: CanvasType;
/**
* Create a new instance of CanvasRenderService.
*
* @param width The width of the charts to render, in pixels.
* @param height The height of the charts to render, in pixels.
* @param chartCallback optional callback which is called once with a new ChartJS global reference as the only parameter.
* @param type optional The canvas type ('PDF' or 'SVG'), see the [canvas pdf doc](https://github.com/Automattic/node-canvas#pdf-output-support).
* @param chartJsFactory optional provider for chart.js.
*/
constructor(width: number, height: number, chartCallback?: ChartCallback, type?: CanvasType, chartJsFactory?: () => typeof ChartJS) {
this._width = width;
this._height = height;
this._chartJs = (chartJsFactory || defaultChartJsFactory)();
//this._createCanvas = freshRequire('canvas', require).createCanvas;
this._type = type;
if (chartCallback) {
chartCallback(this._chartJs);
}
}
/**
* Render to a data url.
* @see https://github.com/Automattic/node-canvas#canvastodataurl
*
* @param configuration The Chart JS configuration for the chart to render.
* @param mimeType The image format, `image/png` or `image/jpeg`.
*/
public renderToDataURL(configuration: ChartConfiguration, mimeType: MimeType = 'image/png'): Promise<string> {
const chart = this.renderChart(configuration);
return new Promise<string>((resolve, reject) => {
const canvas = chart.canvas as any;
canvas.toDataURL(mimeType, (error: Error | null, png: string) => {
chart.destroy();
if (error) {
return reject(error);
}
return resolve(png);
});
});
}
/**
* Render to a data url synchronously.
* @see https://github.com/Automattic/node-canvas#canvastodataurl
*
* @param configuration The Chart JS configuration for the chart to render.
* @param mimeType The image format, `image/png` or `image/jpeg`.
*/
public renderToDataURLSync(configuration: ChartConfiguration, mimeType: MimeType = 'image/png'): string {
const chart = this.renderChart(configuration);
const canvas = chart.canvas as any;
chart.destroy();
const dataUrl = canvas.toDataURL(mimeType);
return dataUrl;
}
/**
* Render to a buffer.
* @see https://github.com/Automattic/node-canvas#canvastobuffer
*
* @param configuration The Chart JS configuration for the chart to render.
* @param mimeType A string indicating the image format. Valid options are `image/png`, `image/jpeg` (if node-canvas was built with JPEG support), `raw` (unencoded ARGB32 data in native-endian byte order, top-to-bottom), `application/pdf` (for PDF canvases) and image/svg+xml (for SVG canvases). Defaults to `image/png` for image canvases, or the corresponding type for PDF or SVG canvas.
*/
public renderToBuffer(configuration: ChartConfiguration, mimeType: MimeType = 'image/png'): Promise<Buffer> {
const chart = this.renderChart(configuration);
return new Promise<Buffer>((resolve, reject) => {
const canvas = chart.canvas as any;
canvas.toBuffer((error: Error | null, buffer: Buffer) => {
chart.destroy();
if (error) {
return reject(error);
}
return resolve(buffer);
}, mimeType);
});
}
/**
* Render to a buffer synchronously.
* @see https://github.com/Automattic/node-canvas#canvastobuffer
*
* @param configuration The Chart JS configuration for the chart to render.
* @param mimeType A string indicating the image format. Valid options are `image/png`, `image/jpeg` (if node-canvas was built with JPEG support), `raw` (unencoded ARGB32 data in native-endian byte order, top-to-bottom), `application/pdf` (for PDF canvases) and image/svg+xml (for SVG canvases). Defaults to `image/png` for image canvases, or the corresponding type for PDF or SVG canvas.
*/
public renderToBufferSync(configuration: ChartConfiguration, mimeType: MimeType = 'image/png'): Buffer {
const chart = this.renderChart(configuration);
const canvas = chart.canvas as any;
const buffer = canvas.toBuffer(mimeType);
chart.destroy();
return buffer;
}
/**
* Render to a stream.
* @see https://github.com/Automattic/node-canvas#canvascreatepngstream
*
* @param configuration The Chart JS configuration for the chart to render.
* @param mimeType A string indicating the image format. Valid options are `image/png`, `image/jpeg` (if node-canvas was built with JPEG support), `application/pdf` (for PDF canvases) and image/svg+xml (for SVG canvases). Defaults to `image/png` for image canvases, or the corresponding type for PDF or SVG canvas.
*/
public renderToStream(configuration: ChartConfiguration, mimeType: MimeType = 'image/png'): Stream {
const chart = this.renderChart(configuration);
const canvas = chart.canvas as any;
chart.destroy();
switch (mimeType) {
case 'image/png':
return canvas.createPNGStream();
case 'image/jpeg':
return canvas.createJPEGStream();
case 'application/pdf':
return canvas.createPDFStream();
default:
throw new Error(`Un-handled mimeType: ${mimeType}`);
}
}
private renderChart(configuration: ChartConfiguration): Chart {
//const canvas = this._createCanvas(this._width, this._height, this._type);
const canvas = createCanvas(this._width, this._height, this._type);
canvas.style = {};
// Disable animation (otherwise charts will throw exceptions)
configuration.options = configuration.options || {};
configuration.options.responsive = false;
configuration.options.animation = false as any;
const context = canvas.getContext('2d');
return new this._chartJs(context, configuration);
}
}