New Charts
Chart.js 2.0 introduced the concept of controllers for each dataset. Like scales, new controllers can be written as needed.
class MyType extends Chart.DatasetController {
}
Chart.register(MyType);
// Now we can create a new instance of our chart, using the Chart.js API
new Chart(ctx, {
// this is the string the constructor was registered at, ie Chart.controllers.MyType
type: 'MyType',
data: data,
options: options
});
Dataset Controller Interface
Dataset controllers must implement the following interface.
{
// Defaults for charts of this type
defaults: {
// If set to `false` or `null`, no dataset level element is created.
// If set to a string, this is the type of element to create for the dataset.
// For example, a line create needs to create a line element so this is the string 'line'
datasetElementType: string | null | false,
// If set to `false` or `null`, no elements are created for each data value.
// If set to a string, this is the type of element to create for each data value.
// For example, a line create needs to create a point element so this is the string 'point'
dataElementType: string | null | false,
}
// ID of the controller
id: string;
// Update the elements in response to new data
// @param mode : update mode, core calls this method using any of `'active'`, `'hide'`, `'reset'`, `'resize'`, `'show'` or `undefined`
update: function(mode) {}
}
The following methods may optionally be overridden by derived dataset controllers.
{
// Draw the representation of the dataset. The base implementation works in most cases, and an example of a derived version
// can be found in the line controller
draw: function() {},
// Initializes the controller
initialize: function() {},
// Ensures that the dataset represented by this controller is linked to a scale. Overridden to helpers.noop in the polar area and doughnut controllers as these
// chart types using a single scale
linkScales: function() {},
// Parse the data into the controller meta data. The default implementation will work for cartesian parsing, but an example of an overridden
// version can be found in the doughnut controller
parse: function(start, count) {},
}
Extending Existing Chart Types
Extending or replacing an existing controller type is easy. Simply replace the constructor for one of the built in types with your own.
The built in controller types are:
BarController
BubbleController
DoughnutController
LineController
PieController
PolarAreaController
RadarController
ScatterController
These controllers are also available in the UMD package, directly under Chart
. Eg: Chart.BarController
.
For example, to derive a new chart type that extends from a bubble chart, you would do the following.
import {BubbleController} from 'chart.js';
class Custom extends BubbleController {
draw() {
// Call bubble controller method to draw all the points
super.draw(arguments);
// Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
const meta = this.getMeta();
const pt0 = meta.data[0];
const {x, y} = pt0.getProps(['x', 'y']);
const {radius} = pt0.options;
const ctx = this.chart.ctx;
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
};
Custom.id = 'derivedBubble';
Custom.defaults = BubbleController.defaults;
// Stores the controller so that the chart initialization routine can look it up
Chart.register(Custom);
// Now we can create and use our new chart type
new Chart(ctx, {
type: 'derivedBubble',
data: data,
options: options
});
TypeScript Typings
If you want your new chart type to be statically typed, you must provide a .d.ts
TypeScript declaration file. Chart.js provides a way to augment built-in types with user-defined ones, by using the concept of “declaration merging”.
When adding a new chart type, ChartTypeRegistry
must contains the declarations for the new type, either by extending an existing entry in ChartTypeRegistry
or by creating a new one.
For example, to provide typings for a new chart type that extends from a bubble chart, you would add a .d.ts
containing:
import { ChartTypeRegistry } from 'chart.js'
declare module 'chart.js' {
interface ChartTypeRegistry {
derivedBubble: ChartTypeRegistry['bubble']
}
}