Merge pull request #2283 from nnnick/feature/plug-in-support

Adds support for plugins
This commit is contained in:
Evert Timberg
2016-04-17 12:48:05 -04:00
5 changed files with 137 additions and 5 deletions

View File

@@ -366,6 +366,32 @@ The built in controller types are:
#### Bar Controller
The bar controller has a special property that you should be aware of. To correctly calculate the width of a bar, the controller must determine the number of datasets that map to bars. To do this, the bar controller attaches a property `bar` to the dataset during initialization. If you are creating a replacement or updated bar controller, you should do the same. This will ensure that charts with regular bars and your new derived bars will work seamlessly.
### Creating Plugins
Starting with v2.1.0, you can create plugins for chart.js. To register your plugin, simply call `Chart.pluginService.register` and pass your plugin in.
Plugins will be called at the following times
* Start of initialization
* End of initialization
* Start of update
* End of update
* Start of draw
* End of draw
Plugins should derive from Chart.PluginBase and implement the following interface
```javascript
{
beforeInit: function(chartInstance) { },
afterInit: function(chartInstance) { },
beforeUpdate: function(chartInstance) { },
afterUpdate: function(chartInstance) { },
// Easing is for animation
beforeDraw: function(chartInstance, easing) { },
afterDraw: function(chartInstance, easing) { }
}
```
### Building Chart.js
Chart.js uses <a href="http://gulpjs.com/" target="_blank">gulp</a> to build the library into a single JavaScript file.

View File

@@ -18,6 +18,7 @@ require('./core/core.controller')(Chart);
require('./core/core.datasetController')(Chart);
require('./core/core.layoutService')(Chart);
require('./core/core.legend')(Chart);
require('./core/core.plugin.js')(Chart);
require('./core/core.scale')(Chart);
require('./core/core.scaleService')(Chart);
require('./core/core.title')(Chart);

View File

@@ -43,9 +43,8 @@ module.exports = function(Chart) {
helpers.extend(Chart.Controller.prototype, {
initialize: function initialize() {
// TODO
// If BeforeInit(this) doesn't return false, proceed
// Before init plugin notification
Chart.pluginService.notifyPlugins('beforeInit', [this]);
this.bindEvents();
@@ -60,8 +59,8 @@ module.exports = function(Chart) {
this.initToolTip();
this.update();
// TODO
// If AfterInit(this) doesn't return false, proceed
// After init plugin notification
Chart.pluginService.notifyPlugins('afterInit', [this]);
return this;
},
@@ -243,6 +242,8 @@ module.exports = function(Chart) {
},
update: function update(animationDuration, lazy) {
Chart.pluginService.notifyPlugins('beforeUpdate', [this]);
// In case the entire data object changed
this.tooltip._data = this.data;
@@ -266,6 +267,8 @@ module.exports = function(Chart) {
dataset.controller.update();
});
this.render(animationDuration, lazy);
Chart.pluginService.notifyPlugins('afterUpdate', [this]);
},
render: function render(duration, lazy) {
@@ -302,6 +305,8 @@ module.exports = function(Chart) {
var easingDecimal = ease || 1;
this.clear();
Chart.pluginService.notifyPlugins('beforeDraw', [this, easingDecimal]);
// Draw all the scales
helpers.each(this.boxes, function(box) {
box.draw(this.chartArea);
@@ -328,6 +333,8 @@ module.exports = function(Chart) {
// Finally draw the tooltip
this.tooltip.transition(easingDecimal).draw();
Chart.pluginService.notifyPlugins('afterDraw', [this, easingDecimal]);
},
// Get the single element that was clicked on

55
src/core/core.plugin.js Normal file
View File

@@ -0,0 +1,55 @@
"use strict";
module.exports = function(Chart) {
var helpers = Chart.helpers;
// Plugins are stored here
Chart.plugins = [];
Chart.pluginService = {
// Register a new plugin
register: function(plugin) {
if (Chart.plugins.indexOf(plugin) === -1) {
Chart.plugins.push(plugin);
}
},
// Remove a registered plugin
remove: function(plugin) {
var idx = Chart.plugins.indexOf(plugin);
if (idx !== -1) {
Chart.plugins.splice(idx, 1);
}
},
// Iterate over all plugins
notifyPlugins: function(method, args, scope) {
helpers.each(Chart.plugins, function(plugin) {
if (plugin[method] && typeof plugin[method] === 'function') {
plugin[method].apply(scope, args);
}
}, scope);
}
};
Chart.PluginBase = Chart.Element.extend({
// Plugin methods. All functions are passed the chart instance
// Called at start of chart init
beforeInit: helpers.noop,
// Called at end of chart init
afterInit: helpers.noop,
// Called at start of update
beforeUpdate: helpers.noop,
// Called at end of update
afterUpdate: helpers.noop,
// Called at start of draw
beforeDraw: helpers.noop,
// Called at end of draw
afterDraw: helpers.noop,
});
};

43
test/core.plugin.tests.js Normal file
View File

@@ -0,0 +1,43 @@
// Plugin tests
describe('Test the plugin system', function() {
beforeEach(function() {
Chart.plugins = [];
});
it ('Should register plugins', function() {
var myplugin = {};
Chart.pluginService.register(myplugin);
expect(Chart.plugins.length).toBe(1);
// Should only add plugin once
Chart.pluginService.register(myplugin);
expect(Chart.plugins.length).toBe(1);
});
it ('Should allow unregistering plugins', function() {
var myplugin = {};
Chart.pluginService.register(myplugin);
expect(Chart.plugins.length).toBe(1);
// Should only add plugin once
Chart.pluginService.remove(myplugin);
expect(Chart.plugins.length).toBe(0);
// Removing a plugin that doesn't exist should not error
Chart.pluginService.remove(myplugin);
});
it ('Should allow notifying plugins', function() {
var myplugin = {
count: 0,
trigger: function(chart) {
myplugin.count = chart.count;
}
};
Chart.pluginService.register(myplugin);
Chart.pluginService.notifyPlugins('trigger', [{ count: 10 }]);
expect(myplugin.count).toBe(10);
});
});