Plugins
Plugins are the most efficient way to customize or change the default behavior of a chart. Leveraging on Chart.JS implementation, Charba provides the features to set a plugin both at global and at chart level (inline plugin).
There 2 ways to add plugins to Charba:
- implementing Plugin interface.
- using SmartPlugin class.
Using Plugin interface
A plugin could be implemented by the Plugin interface.
// creates my plugin
Plugin myPlugin = new Plugin(){
@Override
public String getId(){
return "myplugin";
}
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// my logic
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
An easy way to implement a plugin is also to extends the AbstractPlugin class as following:
// creates my plugin
AbstractPlugin myPlugin = new AbstractPlugin("myplugin"){
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// my logic
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
Even if the interface implementation is a standard JAVA way to have plugins, this implementation forces CHART.JS to invoke all plugins hooks, even if not used. This could affect the performance of chart drawing.
Using SmartPlugin
A SmartPlugin works as a configuration object where the user can add the hooks needed implementations.
// creates my plugin
SmartPlugin myPlugin = new SmartPlugin("myplugin");
// adds needed hooks
myPlugin.setBeforeUpdateHook(new BeforeUpdateHook() {
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// my logic
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
In this case, CHART.JS will invoke ONLY the defined hook, ignoring all the others, improving the performance of chart drawing.
All plugin hooks could be implemented by a specific interface in org.pepstock.charba.client.plugins.hooks or by a native hook where you use JavaScript code.
Registering
Every plugin must be registered to the chart or the the default before the charts will start using it.
Globally
A plugin can be registered/unregistered at global level, which means that the plugin instance will be triggered by all charts instances.
The global registration is performed as following:
// --------------------------------
// REGISTER plugin for all charts
// --------------------------------
Defaults.get().getPlugins().register(new ChartBackgroundColor());
// --------------------------------
// UNREGISTER the "pluginid" plugin
// --------------------------------
Defaults.get().getPlugins().unregister("pluginid");
At chart level
A plugin can be registered/unregistered at chart level, which means that the plugin instance will be triggered only by that chart instance.
The chart registration is performed as following:
// --------------------------------
// Using Plugin interface
// --------------------------------
// creates my plugin
AbstractPlugin myPlugin = new AbstractPlugin("myplugin"){
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// my logic
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
// --------------------------------
// Using SmartPlugin
// --------------------------------
// creates my plugin
// creates my plugin
SmartPlugin myPlugin = new SmartPlugin("myplugin");
// adds needed hooks
myPlugin.setBeforeUpdateHook(new BeforeUpdateHook() {
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// my logic
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
Plugin ID
Plugins must define a unique id in order to be configurable.
This id should follow the name convention (otherwise an illegal argument exception will be thrown):
- can not start with a dot or an underscore
- can not contain any non-URL-safe characters
// --------------------------------
// Using Plugin interface
// --------------------------------
// creates my plugin
AbstractPlugin myPlugin = new AbstractPlugin("_myPlugin"){
...
}; // <-- throws IllegalArgumentException
// because there is '_'
// --------------------------------
// Using SmartPlugin
// --------------------------------
// creates my plugin
SmartPlugin myPlugin = new SmartPlugin("_myPlugin"); // <-- throws IllegalArgumentException
// because there is '_'
Options
A plugin could need to be configured. Apart the public methods that every plugin can expose to set specific values and to be aligned with Chart.JS way to pass configuration to plugins, the chart options can host the configuration of the plugin which could be read at runtime.
The plugins configuration is nested in the configuration using
// get plugins options container from chart configuration
Plugins plugins = chart.getOptions().getPlugins();
The plugin options must extend AbstractPluginOptions and leverage on available methods to store the plugin configuration.
Furthermore, every plugin needs to have a factory which must be an implementation of AbstractPluginOptionsFactory) interface necessary to enable Charba to create your options, passing the javascript object which maintain the configuration.
A plugin can consume configuration by options from:
- Global options
- Global chart options, based on chart type
- Chart options
- Datasets
Global options
A plugin can have a default configuration that can be used from all plugin instances on all charts.
Here are some examples how to get and store the options in the defaults:
// creates the options
ChartBackgroundColorOptions option = new ChartBackgroundColorOptions();
option.setBackgroundColor(HtmlColor.GREEN);
// --------------------------------------
// STORING plugin options
// --------------------------------------
// stores the plugin options by plugin ID
Defaults.get().getGlobal().getPlugin().setOptions(ChartBackgroundColor.ID, options);
// stores the plugin options without plugin ID
Defaults.get().getGlobal().getPlugin().setOptions(options);
// stores the plugin options directly by the options
options.store();
// --------------------------------------
// GETTING plugin options
// --------------------------------------
if (Defaults.get().getGlobal().getPlugin().hasOptions(ChartBackgroundColor.ID)){
// retrieves the plugin options by plugin ID
options = Defaults.get().getGlobal().getPlugin().getOptions(ChartBackgroundColor.ID, ChartBackgroundColor.FACTORY);
// retrieves the plugin options without plugin ID
options = Defaults.get().getGlobal().getPlugin().getOptions(ChartBackgroundColor.FACTORY);
}
Global chart type options
You can set a default plugin configuration for a specific type of chart that can be used from all plugin instances on all charts of that type.
Here are some examples how to get and store the options in the chart type defaults options:
// creates the options
ChartBackgroundColorOptions option = new ChartBackgroundColorOptions();
option.setBackgroundColor(HtmlColor.GREEN);
// --------------------------------------
// STORING plugin options
// --------------------------------------
// stores the plugin options by plugin ID
Defaults.get().getOptions(ChartType.BAR).getPlugin().setOptions(ChartBackgroundColor.ID, options);
// stores the plugin options without plugin ID
Defaults.get().getOptions(ChartType.BAR).getPlugin().setOptions(options);
// stores the plugin options directly by the options
options.store(ChartType.BAR);
// --------------------------------------
// GETTING plugin options
// --------------------------------------
if (Defaults.get().getOptions(ChartType.BAR).getPlugin().hasOptions(ChartBackgroundColor.ID)){
// retrieves the plugin options by plugin ID
options = Defaults.get().getOptions(ChartType.BAR).getPlugin().getOptions(ChartBackgroundColor.ID, ChartBackgroundColor.FACTORY);
// retrieves the plugin options without plugin ID
options = Defaults.get().getOptions(ChartType.BAR).getPlugin().getOptions(ChartBackgroundColor.FACTORY);
}
Chart configuration
You can set a plugin configuration for a chart that can be used only on that chart instance.
Here are some examples how to get and store the options in the chart configuration:
// creates the chart
BarChart chart = new BarChart();
// creates the options
ChartBackgroundColorOptions option = new ChartBackgroundColorOptions();
option.setBackgroundColor(HtmlColor.GREEN);
// --------------------------------------
// STORING plugin options
// --------------------------------------
// stores the plugin options by plugin ID
chart.getOptions().getPlugin().setOptions(ChartBackgroundColor.ID, options);
// stores the plugin options without plugin ID
chart.getOptions().getPlugin().setOptions(options);
// stores the plugin options directly by the options
options.store(chart);
// --------------------------------------
// GETTING plugin options
// --------------------------------------
if (chart.getOptions().getPlugin().hasOptions(ChartBackgroundColor.ID)){
// retrieves the plugin options by plugin ID
chart.getOptions().getPlugin().getOptions(ChartBackgroundColor.ID, ChartBackgroundColor.FACTORY);
//retrieves the plugin options without plugin ID
chart.getOptions().getPlugin().getOptions(ChartBackgroundColor.FACTORY);
}
Dataset configuration
A plugin can also act at dataset level and you can set a plugin configuration for a dataset that can be used only on that dataset instance.
Here are some examples how to get and store the options in the dataset configuration:
// creates the chart
BarChart chart = new BarChart();
// creates the dataset
BarDataset dataset = chart.newDataset();
// creates the options
DataLabelsOptions option = new DataLabelsOptions();
option.setDisplay(true);
// --------------------------------------
// STORING plugin options
// --------------------------------------
// stores the plugin options by plugin ID
dataset.setOptions(DataLabelsPlugin.ID, options);
// stores the plugin options without plugin ID
dataset.getPlugin().setOptions(options);
// stores the plugin options directly by the options
options.store(dataset);
// --------------------------------------
// GETTING plugin options
// --------------------------------------
if (dataset.hasOptions(DataLabelsPlugin.ID)){
// --------------------------------------
// retrieve the plugin options by plugin ID
// --------------------------------------
options = dataset.getOptions(DataLabelsPlugin.ID, DataLabelsPlugin.FACTORY);
// --------------------------------------
// or retrieve the plugin options without plugin ID
// --------------------------------------
options = dataset.getOptions(DataLabelsPlugin.FACTORY);
}
Accessing to the options from plugins
The implementation of plugin usually needs to access to the plugin configuration to enable the right behaviors based on the user configuration.
Inside the plugin, the chart instance can provide a method to get the whole configuration of the chart where also the defaults at different levels are applied.
// creates my plugin
AbstractPlugin myPlugin = new AbstractPlugin("myplugin"){
@Override
public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument){
// get options reference
MyPluginOptions myOptions = null;
// loads chart options for the chart
IsDefaultScaledOptions options = chart.getWholeOptions();
// retrieves the plugin options
if (options.getPlugins().hasOptions("myplugin")){
myOptions = options.getPlugins().getOptions("myplugin", myFactory);
}
return true;
}
};
// registers my plugin to the chart
chart.getPlugins().add(myPlugin);
Disabling plugins
You can also enable or disable them at chart level, as following:
// disables the tooltip to the chart
chart.getOptions().getPlugins().setEnabled(DefaultPluginId.TOOLTIP, false);
// disables the "pluginid" plugin
chart.getOptions().getPlugins().setEnabled("pluginid", true);
Chart.JS provides a set of plugins out-of-the-box. All their ids are mapped to DefaultPluginId enumeration.
Hooks
Plugin interface and SmartPlugin hooks provide all possible hooks or methods which will invoked during the life cycle of the chart or when an event or conditions is occurring.
All hooks are defined with a default therefore you can implement only what you need. The hooks have got different purposes:
- Initialization
- Registering and activating
- Updating or reconfiguring
- Rendering
- Building scales
- Tooltip drawing
- Events
- Resizing, resetting and destroying
Initializating
Plugins are notified during the initialization process.
The process is triggered when draw method of the chart is invoked.
The following hooks can be used to setup data needed for the plugin to operate:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onConfigure | ConfigureHook | Called before initializing configuration of 'chart' |
onBeforeInit | BeforeInitHook | Called before initializing 'chart' |
onAfterInit | AfterInitHook | Called after 'chart' has been initialized and before the first update. |
onResize | ResizeHook | Called after the chart as been resized. |
The initialization process is documented in the flowchart below.
Registering and activating
Plugins are notified during throughout the plugin installation and activation process.
The following hooks can be used to interact during the plugin registering or activating:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onInstall | InstallHook | Called when plugin is installed for this chart instance; this hook is also invoked for disabled plugins (options equals to false) |
onStart | StartHook | Called when a plugin is starting; this happens when chart is created or plugin is enabled |
onStop | StopHook | Called when a plugin stopping; this happens when chart is destroyed or plugin is disabled |
onUninstall | UninstallHook | Called after chart is destroyed on all plugins that were installed for that chart; this hook is also invoked for disabled plugins (options equals to false) |
Updating or reconfiguring
Plugins are notified during throughout the update process.
The process is triggered when
- draw method of the chart is invoked.
- update method of the chart is invoked.
- reconfigure method of the chart is invoked.
- resize method of the chart is invoked.
- a resize event from the browser has been caught by Chart.JS.
The same notification are provided even if the chart is reconfigured. The following hooks can be used to interact during the chart updating or reconfiguring:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onBeginDrawing | - | Called before every drawing cycle, coming from initialization, updating or rendering of chart |
onBeforeUpdate | BeforeUpdateHook | Called before updating 'chart'. If any plugin returns false, the update is cancelled (and thus subsequent render(s)) until another 'update' is triggered. |
onAfterUpdate | AfterUpdateHook | Called after 'chart' has been updated and before rendering. Note that this hook will not be called if the chart update has been previously cancelled. |
onBeforeElementsUpdate | BeforeElementsUpdateHook | Called during the update process, before any chart elements have been created. |
onBeforeLayout | BeforeLayoutHook | Called before laying out 'chart'. If any plugin returns false, the layout update is cancelled until another 'update' is triggered. |
onAfterLayout | AfterLayoutHook | Called after the 'chart' has been layed out. Note that this hook will not be called if the layout update has been previously cancelled. |
onBeforeDatasetsUpdate | BeforeDatasetsUpdateHook | Called before updating the 'chart' datasets. If any plugin returns false, the datasets update is cancelled until another 'update' is triggered. |
onAfterDatasetsUpdate | AfterDatasetsUpdateHook | Called after the 'chart' datasets have been updated. Note that this hook will not be called if the datasets update has been previously cancelled. |
onBeforeDatasetUpdate | BeforeDatasetUpdateHook | Called before updating the 'chart' dataset at the given 'args.index'. If any plugin returns false, the datasets update is cancelled until another 'update' is triggered. |
onAfterDatasetUpdate | AfterDatasetUpdateHook | Called after the 'chart' datasets at the given 'args.index' has been updated. Note that this hook will not be called if the datasets update has been previously cancelled. |
The updating and reconfiguring process is documented in the flowchart below.
Rendering
Plugins can interact with the chart throughout the render process.
The process is triggered when
- updating or reconfiguring process of the chart is invoked.
- render method of the chart is invoked.
The following hooks can be used to interact during the chart rendering:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onBeforeRender | BeforeRenderHook | Called before rendering 'chart'. If any plugin returns false, the rendering is cancelled until another 'render' is triggered. |
onAfterRender | AfterRenderHook | Called after the 'chart' has been fully rendered (and animation completed). Note that this hook will not be called if the rendering has been previously cancelled. |
onBeforeDraw | BeforeDrawHook | Called before drawing 'chart' at every animation frame. If any plugin returns false, the frame drawing is cancelled until another 'render' is triggered. |
onAfterDraw | AfterDrawHook | Called after the 'chart' has been drawn. Note that this hook will not be called if the drawing has been previously cancelled. |
onBeforeDatasetsDraw | BeforeDatasetsDrawHook | Called before drawing the 'chart' datasets. If any plugin returns false, the datasets drawing is cancelled until another 'render' is triggered. |
onAfterDatasetsDraw | AfterDatasetsDrawHook | Called after the 'chart' datasets have been drawn. Note that this hook will not be called if the datasets drawing has been previously cancelled. |
onBeforeDatasetDraw | BeforeDatasetDrawHook | Called before drawing the 'chart' dataset at the given 'index' (datasets are drawn in the reverse order). If any plugin returns false, the datasets drawing is cancelled until another 'render' is triggered. |
onAfterDatasetDraw | AfterDatasetDrawHook | Called after the 'chart' datasets at the given 'args.index' have been drawn (datasets are drawn in the reverse order). Note that this hook will not be called if the datasets drawing has been previously cancelled. |
onEndDrawing | - | Called after every drawing cycle, coming from initialization, updating or rendering of chart. |
The rendering process is documented in the flowchart below.
Building scales
Plugins are notified during the scales and ticks building process.
The process is triggered when updating or reconfiguring process of the chart is invoked.
The following hooks can be used to interact during the chart updating or reconfiguring:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onBeforeDataLimits | BeforeDataLimitsHook | Called before scale data limits are calculated. This hook is called separately for each scale in the chart. |
onAfterDataLimits | AfterDataLimitsHook | Called after scale data limits are calculated. This hook is called separately for each scale in the chart. |
onBeforeBuildTicks | BeforeBuildTicksHook | Called before scale builds its ticks. This hook is called separately for each scale in the chart. |
onAfterBuildTicks | AfterBuildTicksHook | Called after scale has build its ticks. This hook is called separately for each scale in the chart. |
Tooltip drawing
Plugins are notified during the tooltip drawing process.
The following hooks can be used to interact during the tooltip drawing:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onBeforeTooltipDraw | BeforeTooltipDrawHook | Called before drawing the 'tooltip'. If any plugin returns false, the tooltip drawing is cancelled until another 'render' is triggered. |
onAfterTooltipDraw | AfterTooltipDrawHook | Called after drawing the 'tooltip'. Note that this hook will not be called if the tooltip drawing has been previously cancelled. |
Events
Plugins are notified during the chart canvas event process.
The process is triggered when a resize event from the browser has been caught by Chart.JS.
The following hooks can be used to interact during the canvas event process:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onBeforeEvent | BeforeEventHook | Called before processing the specified 'event'. If any plugin returns false, the event will be discarded. |
onAfterEvent | AfterEventHook | Called after the 'event' has been consumed. Note that this hook will not be called if the 'event' has been previously discarded. |
Resizing, resetting and destroying
Plugins are notified during the resize, reset and destroy processes.
The process is triggered when
- reset method of the chart is invoked.
- destroy method of the chart is invoked.
- resize method of the chart is invoked.
- a resize event from the browser has been caught by Chart.JS.
The following hooks can be used to interact during the resize, reset and destroy processes:
Plugin method | SmartPlugin hook | Description |
---|---|---|
onResize | ResizeHook | Called after the chart as been resized. |
onReset | ResetHook | Called during chart reset. |
onBeforeDestroy | BeforeDestroyHook | Called before the chart is being destroyed. |
onAfterDestroy | AfterDestroyHook | Called after the chart has been destroyed. |