Creating plugins

Plugins are the most efficient way to extend Chart.js. A plugin can insert code before and after different phases of the rendering cycle of a chart. At each phase, it can access the chart object and read configurable options. This can be used to change practically any property or behavior of the chart.

Plugins are designed to be reusable. During the previous chapters, we used several popular plugins to extend Chart.js in different ways. They are great to encapsulate complexity, but simple plugins can also be very useful.

In the last example, we created a download link for a PNG version of the chart. If you tried it, you may have noticed that the image has a transparent background. This is OK if your background is white, but if it isn’t, the chart may be hard to read. A naïve approach to fixing the problem would be painting the canvas white using CSS or fill commands. But, it won’t work because Chart.js redraws the canvas during its render cycle. You also need to deal with any animations, resizing, updates, and other events that might reset the background after you changed its color. This is a case for a plugin. With a plugin, you can insert code during the render cycle, draw the background after the canvas is initialized, and before the chart is drawn.

The render life cycle of Chart.js is illustrated as follows. When the chart is loaded for the first time, it performs the init, update, and render steps. Every time the page is resized, update and render are executed, and on events, the render step is performed:

Chart.js life cycle. Each phase can be intercepted by plugin callbacks.

Depending on your plugin, you may need to intercept one or more of these steps. The following table lists the callbacks that are available for plugins. Each callback function contains at least two parameters: a reference to the chart instance and an options object (configured under a plugin ID key, in options.plugins). Some callbacks may have additional parameters:

Method

Parameters

Description

beforeInit
afterInit

(chart, options)

Called before and after new Chart() is invoked

beforeUpdate
afterUpdate

(chart, options)

Called before and after the update stage

beforeLayout
afterLayout

(chart, options)

Called before and after the layout stage

beforeDatasetsUpdate
afterDatasetsUpdate

(chart, options)

Called before and after updating all datasets

beforeDatasetUpdate
afterDatasetUpdate

(chart, dataset, options)

Called before and after updating each dataset

beforeRender
afterRender

(chart, options)

Called before and after the render stage

beforeDraw
afterDraw

(chart, easing, options)

Called before and after the draw stage

beforeDatasetsDraw
afterDatasetsDraw

(chart, easing, options)

Called before and after drawing all datasets

beforeDatasetDraw
afterDatasetDraw

(chart, dataset, options)

Called before and after drawing each dataset

beforeEvent
afterEvent

(chart, event, options)

Called before and after events

resize

(chart, dimensions, options)

Called after resizing

destroy

(chart, options)

Called after chart.destroy() is called

Life cycle callbacks that can be used in plugins

To see a demonstration of these methods, run the Extensions/ext-2-plugin-lifecycle.html file. It logs every life cycle event while a chart with three plugins is rendered and destroyed.

A plugin is a simple object. An id property is not necessary unless you plan to configure the plugin in the options object. You can include just the callback properties you need. The following code will create a simple configurable plugin that will draw a blue square in front of the chart, and a red one in front of the axes but behind the bars (Extensions/ext-3-simple-plugin.html):

const plugin = {
id: 'p1',
afterRender: function(chart, options) {
chart.ctx.fillStyle = 'blue';
chart.ctx.fillRect(60,60,100,100);
},
beforeDatasetsDraw: function(chart, percent, options) {
chart.ctx.fillStyle = 'red';
chart.ctx.fillRect(200,60,100,100);
},
};

This effect is shown here:

The blue and red squares were drawn in the chart using simple plugins. Code: Extensions/ext-3-simple-plugin.html.

If you are writing a plugin locally and have multiple charts, you can include a list of plugins to add to each chart using the plugins key in the Chart() constructor. It takes an array:

new Chart("chart", {
type: 'bar',
data: {…},
options: {…},
plugins: [plugin1]
});

Plugins should be reusable whenever possible. Reusable plugins are normally created in separate .js files and made automatically available to all charts. In this case, they should be registered globally with the following:

Chart.plugins.register(plugin);

Let’s create a plugin for the last example so that the image and the chart have an opaque background. Plugins should have configurable options. There are greater chances you will reuse this plugin if you can configure the background color for each chart. We could also add the possibility of drawing a background image. The plugin will be stored in a separate JavaScript file, JavaScript/chartback.js, which creates the plugin object and registers it globally. The id is necessary so that a chart can identify the plugin and configure its options.

Since the image needs to be redrawn every time the chart is resized or updated, the best place to draw it is in the beforeDraw callback. This code will also place the image behind the axes:

const bgPlugin = { id: 'chartback',
beforeDraw: function(chart, steps, options) {
let ctx = chart.ctx;
if(options.backgroundColor) {
ctx.fillStyle = options.backgroundColor;
ctx.fillRect(0, 0, chart.width, chart.height);
}
if(options.backgroundImage) {
let image = new Image(chart.width, chart.height);
image.src = options.backgroundImage;
ctx.drawImage(image, 0,0,chart.width, chart.height);
}
}
}
Chart.plugins.register(bgPlugin);

To use the plugin, import it into the HTML file where the chart will be created:

<script src="../JavaScript/chartback.js"></script>

This plugin's configuration options can be set in the options.plugins.chartback key (chartback is the plugin's ID). This code is in Extensions/ext-4-chartback.html:

new Chart("chart", { type: 'bar', data: {…},
options: {
animation: {…},
plugins: {
chartback: {
backgroundColor: 'white',
backgroundImage: '../Images/mars.jpg'
}
}
},
});

The chart will be drawn with an image behind. If you don’t want the image, you can just set the backgroundColor and have a chart with an opaque background. The following screenshot shows a web page with the chart and the .png file loaded by an image viewer application:

Using a plugin that places a background image behind the chart. Code: Extensions/ext-4-chartback.html.