Skip to content

Commit

Permalink
Add support for local plugins and plugin options
Browse files Browse the repository at this point in the history
Plugins can now be declared in the chart `config.plugins` array and will only be applied to the associated chart(s), after the globally registered plugins. Plugin specific options are now scoped under the `config.options.plugins` options. Hooks now receive the chart instance as first argument and the plugin options as last argument.
  • Loading branch information
simonbrunel committed Dec 18, 2016
1 parent e249de7 commit ff57293
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/chart.js
Expand Up @@ -5,13 +5,13 @@ var Chart = require('./core/core.js')();

require('./core/core.helpers')(Chart);
require('./core/core.canvasHelpers')(Chart);
require('./core/core.plugin.js')(Chart);
require('./core/core.element')(Chart);
require('./core/core.animation')(Chart);
require('./core/core.controller')(Chart);
require('./core/core.datasetController')(Chart);
require('./core/core.layoutService')(Chart);
require('./core/core.scaleService')(Chart);
require('./core/core.plugin.js')(Chart);
require('./core/core.ticks.js')(Chart);
require('./core/core.scale')(Chart);
require('./core/core.title')(Chart);
Expand Down
28 changes: 14 additions & 14 deletions src/core/core.controller.js
Expand Up @@ -258,7 +258,7 @@ module.exports = function(Chart) {
var me = this;

// Before init plugin notification
Chart.plugins.notify('beforeInit', [me]);
Chart.plugins.notify(me, 'beforeInit');

me.bindEvents();

Expand All @@ -273,7 +273,7 @@ module.exports = function(Chart) {
me.update();

// After init plugin notification
Chart.plugins.notify('afterInit', [me]);
Chart.plugins.notify(me, 'afterInit');

return me;
},
Expand Down Expand Up @@ -315,7 +315,7 @@ module.exports = function(Chart) {
if (!silent) {
// Notify any plugins about the resize
var newSize = {width: newWidth, height: newHeight};
Chart.plugins.notify('resize', [me, newSize]);
Chart.plugins.notify(me, 'resize', [newSize]);

// Notify of resize
if (me.options.onResize) {
Expand Down Expand Up @@ -460,7 +460,7 @@ module.exports = function(Chart) {
var me = this;

updateConfig(me);
Chart.plugins.notify('beforeUpdate', [me]);
Chart.plugins.notify(me, 'beforeUpdate');

// In case the entire data object changed
me.tooltip._data = me.data;
Expand All @@ -476,7 +476,7 @@ module.exports = function(Chart) {
Chart.layoutService.update(me, me.chart.width, me.chart.height);

// Apply changes to the datasets that require the scales to have been calculated i.e BorderColor changes
Chart.plugins.notify('afterScaleUpdate', [me]);
Chart.plugins.notify(me, 'afterScaleUpdate');

// Can only reset the new controllers after the scales have been updated
helpers.each(newControllers, function(controller) {
Expand All @@ -486,7 +486,7 @@ module.exports = function(Chart) {
me.updateDatasets();

// Do this before render so that any plugins that need final scale updates can use it
Chart.plugins.notify('afterUpdate', [me]);
Chart.plugins.notify(me, 'afterUpdate');

if (me._bufferedRender) {
me._bufferedRequest = {
Expand Down Expand Up @@ -530,18 +530,18 @@ module.exports = function(Chart) {
var me = this;
var i, ilen;

if (Chart.plugins.notify('beforeDatasetsUpdate', [me])) {
if (Chart.plugins.notify(me, 'beforeDatasetsUpdate')) {
for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
me.getDatasetMeta(i).controller.update();
}

Chart.plugins.notify('afterDatasetsUpdate', [me]);
Chart.plugins.notify(me, 'afterDatasetsUpdate');
}
},

render: function(duration, lazy) {
var me = this;
Chart.plugins.notify('beforeRender', [me]);
Chart.plugins.notify(me, 'beforeRender');

var animationOptions = me.options.animation;
if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
Expand Down Expand Up @@ -577,7 +577,7 @@ module.exports = function(Chart) {
var easingDecimal = ease || 1;
me.clear();

Chart.plugins.notify('beforeDraw', [me, easingDecimal]);
Chart.plugins.notify(me, 'beforeDraw', [easingDecimal]);

// Draw all the scales
helpers.each(me.boxes, function(box) {
Expand All @@ -587,7 +587,7 @@ module.exports = function(Chart) {
me.scale.draw();
}

Chart.plugins.notify('beforeDatasetsDraw', [me, easingDecimal]);
Chart.plugins.notify(me, 'beforeDatasetsDraw', [easingDecimal]);

// Draw each dataset via its respective controller (reversed to support proper line stacking)
helpers.each(me.data.datasets, function(dataset, datasetIndex) {
Expand All @@ -596,12 +596,12 @@ module.exports = function(Chart) {
}
}, me, true);

Chart.plugins.notify('afterDatasetsDraw', [me, easingDecimal]);
Chart.plugins.notify(me, 'afterDatasetsDraw', [easingDecimal]);

// Finally draw the tooltip
me.tooltip.transition(easingDecimal).draw();

Chart.plugins.notify('afterDraw', [me, easingDecimal]);
Chart.plugins.notify(me, 'afterDraw', [easingDecimal]);
},

// Get the single element that was clicked on
Expand Down Expand Up @@ -701,7 +701,7 @@ module.exports = function(Chart) {
me.chart.ctx = null;
}

Chart.plugins.notify('destroy', [me]);
Chart.plugins.notify(me, 'destroy');

delete Chart.instances[me.id];
},
Expand Down
94 changes: 82 additions & 12 deletions src/core/core.plugin.js
Expand Up @@ -2,16 +2,31 @@

module.exports = function(Chart) {

var noop = Chart.helpers.noop;
var helpers = Chart.helpers;
var noop = helpers.noop;

Chart.defaults.global.plugins = {};

/**
* The plugin service singleton
* @namespace Chart.plugins
* @since 2.1.0
*/
Chart.plugins = {
/**
* Globally registered plugins.
* @private
*/
_plugins: [],

/**
* This identifier is used to invalidate the descriptors cache attached to each chart
* when a global plugin is registered or unregistered. In this case, the cache ID is
* incremented and descriptors are regenerated during following API calls.
* @private
*/
_cacheId: 0,

/**
* Registers the given plugin(s) if not already registered.
* @param {Array|Object} plugins plugin instance(s).
Expand All @@ -23,6 +38,8 @@ module.exports = function(Chart) {
p.push(plugin);
}
});

this._cacheId++;
},

/**
Expand All @@ -37,6 +54,8 @@ module.exports = function(Chart) {
p.splice(idx, 1);
}
});

this._cacheId++;
},

/**
Expand All @@ -45,6 +64,7 @@ module.exports = function(Chart) {
*/
clear: function() {
this._plugins = [];
this._cacheId++;
},

/**
Expand All @@ -66,28 +86,78 @@ module.exports = function(Chart) {
},

/**
* Calls registered plugins on the specified extension, with the given args. This
* method immediately returns as soon as a plugin explicitly returns false. The
* Calls enabled plugins for chart, on the specified extension and with the given args.
* This method immediately returns as soon as a plugin explicitly returns false. The
* returned value can be used, for instance, to interrupt the current action.
* @param {Object} chart chart instance for which plugins should be called.
* @param {String} extension the name of the plugin method to call (e.g. 'beforeUpdate').
* @param {Array} [args] extra arguments to apply to the extension call.
* @returns {Boolean} false if any of the plugins return false, else returns true.
*/
notify: function(extension, args) {
var plugins = this._plugins;
var ilen = plugins.length;
var i, plugin;
notify: function(chart, extension, args) {
var descriptors = this.descriptors(chart);
var ilen = descriptors.length;
var i, descriptor, plugin, params, method;

for (i=0; i<ilen; ++i) {
plugin = plugins[i];
if (typeof plugin[extension] === 'function') {
if (plugin[extension].apply(plugin, args || []) === false) {
descriptor = descriptors[i];
plugin = descriptor.plugin;
method = plugin[extension];
if (typeof method === 'function') {
params = [chart].concat(args || []);
params.push(descriptor.options);
if (method.apply(plugin, params) === false) {
return false;
}
}
}

return true;
},

/**
* Returns descriptors of enabled plugins for the given chart.
* @returns {Array} [{ plugin, options }]
* @private
*/
descriptors: function(chart) {
var cache = chart._plugins || (chart._plugins = {});
if (cache.id === this._cacheId) {
return cache.descriptors;
}

var plugins = [];
var descriptors = [];
var config = (chart && chart.config) || {};
var defaults = Chart.defaults.global.plugins;
var options = (config.options && config.options.plugins) || {};

this._plugins.concat(config.plugins || []).forEach(function(plugin) {
var idx = plugins.indexOf(plugin);
if (idx !== -1) {
return;
}

var id = plugin.id;
var opts = options[id];
if (opts === false) {
return;
}

if (opts === true) {
opts = helpers.clone(defaults[id]);
}

plugins.push(plugin);
descriptors.push({
plugin: plugin,
options: opts || {}
});
});

cache.descriptors = descriptors;
cache.id = this._cacheId;
return descriptors;
}
};

Expand All @@ -96,7 +166,7 @@ module.exports = function(Chart) {
* @interface Chart.PluginBase
* @since 2.1.0
*/
Chart.PluginBase = Chart.Element.extend({
Chart.PluginBase = helpers.inherits({
// Called at start of chart init
beforeInit: noop,

Expand All @@ -123,7 +193,7 @@ module.exports = function(Chart) {
* Provided for backward compatibility, use Chart.plugins instead
* @namespace Chart.pluginService
* @deprecated since version 2.1.5
* @todo remove me at version 3
* TODO remove me at version 3
*/
Chart.pluginService = Chart.plugins;
};

0 comments on commit ff57293

Please sign in to comment.