Extending Highcharts

Since version 2.3, Highcharts is built in a modular way with extensions in mind.

Major chart concepts correspond to JavaScript prototypes or "classes" which are exposed on the Highcharts namespace and can easily be modified. Examples are Highcharts.Series, Highcharts.Tooltip, Highcharts.Chart, Highcharts.Axis, Highcharts.Legend etc.

Constructor logic is consequently kept in a method, init, to allow overriding the initiation.

Events can be added to the instance through framework event binding. If your framework is jQuery, you can for example run$(chart).bind('load', someFunction);

Some, but not all, prototypes and properties are listed at api.highcharts.com under Methods and Properties. Some prototypes and properties are not listed, which means they may change in future versions as we optimize and adapt the library. We do not discourage using these members, but warn that your plugin should be tested with future versions of Highcharts. These members can be identified by inspecting the Highcharts namespace as well as generated chart objects in developer tools, and by studying the source code of highcharts.src.js.

Wrapping up a plugin

Like jQuery plugins, Highcharts plugins should be wrapped in an anonymous self-executing function in order to prevent variable pollution to the global scope. A good practice is to wrap plugins like this:

Hooking up to Chart.init

In order to add event listeners to existing parts of a chart, a general callback function can be registered to run after the chart is first rendered. This can be done by pushing the function to the Chart.prototype.callbacks array:

Wrapping prototype functions

JavaScript with its dynamic nature is extremely powerful when it comes to altering the behaviour of scripts on the fly. In Highcharts we created a utility called wrap, which wraps an existing prototype function ("method") and allows you to add your own code before or after it.

The wrap function accepts the parent object as the first argument, the name of the function to wrap as the second, and a callback replacement function as the third. The original function is passed as the first argument to the replacement function, and original arguments follow after that.

It's best explained by a code sample:

H.wrap(H.Series.prototype, 'drawGraph', function (proceed) {
// Before the original function
console.log("We are about to draw the graph: ", this.graph);
// Now apply the original function with the original arguments,
// which are sliced off this function's arguments
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
// Add some code after the original function
console.log("We just finished drawing the graph: ", this.graph);
});

Example extension

In this example the client wanted to use markers ("trackballs") on column type series in Highstock. Markers is currently only supported in line type series. To get this functionality, a small plugin can be written.

This plugin will add a trackball to each series in the chart, that does not already support and contain a marker.

To gain this we start with the following code, creating a self-executing function to contain the plugin:

(function (H) {
// This is a self executing function
// The global variable Highcharts is passed along with a reference H
}(Highcharts));

Afterwards, we need to add extra functionality to the methods Tooltip.prototype.refresh and Tooltip.prototype.hide. For this, we wrap the methods:

Now the trackball will be displayed, but we also need to hide it when the tooltip is removed. Therefore som extra functionality is also needed in the hide method. A new wrap is added inside the function containing the plugin: