Documentation Index
Fetch the complete documentation index at: https://mintlify.com/highcharts/highcharts/llms.txt
Use this file to discover all available pages before exploring further.
Highcharts is designed with extensibility in mind. You can modify behavior, add new features, and create plugins using the exposed API and prototype system.
Architecture Overview
Highcharts is built on a modular architecture where major concepts correspond to JavaScript classes:
Highcharts.Chart - Main chart instance
Highcharts.Series - Series data and rendering
Highcharts.Axis - Axis functionality
Highcharts.Tooltip - Tooltip display
Highcharts.Legend - Legend component
Highcharts.Pointer - Mouse/touch interaction
Plugin Structure
All Highcharts plugins should follow this structure:
(function (H) {
// Get shortcuts to Highcharts classes
const { Chart, Series, Axis } = H;
// Local variables
let pluginState;
// Plugin initialization
function init() {
// Setup code
}
// Plugin logic
// ...
init();
}(Highcharts));
Use an immediately invoked function expression (IIFE) to avoid polluting the global scope.
Using addEvent
The addEvent utility allows you to listen to events on classes and instances.
Class-Level Events
Listen to events on all instances:
H.addEvent(H.Chart, 'load', function(e) {
const chart = e.target;
console.log('Chart loaded:', chart.options.title.text);
});
Instance-Level Events
Listen to events on specific instances:
const chart = Highcharts.chart('container', {
// options
});
H.addEvent(chart, 'redraw', function() {
console.log('Chart redrawn');
});
Complete Example: Click Handler
(function (H) {
H.addEvent(H.Chart, 'load', function(e) {
const chart = e.target;
// Add click handler to chart container
H.addEvent(chart.container, 'click', function(e) {
e = chart.pointer.normalize(e);
console.log(`Clicked chart at ${e.chartX}, ${e.chartY}`);
});
// Listen to axis extremes changes
H.addEvent(chart.xAxis[0], 'afterSetExtremes', function(e) {
console.log(`Set extremes to ${e.min}, ${e.max}`);
});
});
}(Highcharts));
Prefer regular functions over arrow functions when using addEvent. Highcharts binds this to the runtime object, while arrow functions maintain lexical this.
Wrapping Prototype Functions
The wrap utility allows you to modify existing functionality:
H.wrap(Parent, 'methodName', function (proceed, ...args) {
// Before original function
console.log('Before');
// Call original function
const result = proceed.apply(this, args);
// After original function
console.log('After');
return result;
});
Example: Custom Graph Drawing
(function (H) {
H.wrap(H.Series.types.line.prototype, 'drawGraph', function (proceed) {
// Before drawing
console.log('About to draw graph:', typeof this.graph);
// Call original function
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
// After drawing
console.log('Finished drawing graph:', typeof this.graph);
// Add custom styling
if (this.graph) {
this.graph.attr({
'stroke-dasharray': '5,5'
});
}
});
}(Highcharts));
(function (H) {
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed, point) {
// Add custom data before showing tooltip
if (point.custom === undefined) {
point.custom = {
timestamp: Date.now(),
source: 'custom'
};
}
// Call original refresh
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
});
}(Highcharts));
Regular functions are required for wrap because they rely on runtime this, proceed, and access to the original argument list.
Creating a Complete Plugin
Here’s a complete plugin that adds trackballs to column series:
/**
* Highcharts Trackball Plugin
*
* Adds trackball markers to series that don't have markers
*/
(function (H) {
/**
* Wrap tooltip refresh to show trackballs
*/
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed, points) {
// Ensure points is an array
points = H.splat(points);
// Call original refresh
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
// Add or update trackball for each point
H.each(points, function (point) {
const series = point.series;
const chart = series.chart;
// Only add trackball if series doesn't have markers
if (!series.options.marker || !series.options.marker.enabled) {
const pointX = point.plotX + series.xAxis.pos;
const pointY = H.pick(point.plotClose, point.plotY) + series.yAxis.pos;
if (!series.trackball) {
// Create trackball
series.trackball = chart.renderer.circle(pointX, pointY, 5)
.attr({
fill: series.color,
stroke: 'white',
'stroke-width': 1,
zIndex: 5
})
.add();
} else {
// Update position
series.trackball.attr({
x: pointX,
y: pointY
});
}
}
});
});
/**
* Wrap tooltip hide to remove trackballs
*/
H.wrap(H.Tooltip.prototype, 'hide', function (proceed) {
// Call original hide
proceed.apply(this);
// Destroy all trackballs
const series = this.chart.series;
H.each(series, function (serie) {
if (serie.trackball) {
serie.trackball = serie.trackball.destroy();
}
});
});
}(Highcharts));
Extending with ES Modules
When using ES modules, you can access and modify modules directly:
import Highcharts from 'highcharts/es-modules/masters/highcharts.src.js';
import Chart from 'highcharts/es-modules/Core/Chart/Chart.js';
import Series from 'highcharts/es-modules/Core/Series/Series.js';
// Modify Chart prototype
Chart.prototype.customMethod = function() {
console.log('Custom method called');
};
// Add to Series
Highcharts.addEvent(Series, 'afterAnimate', function() {
console.log('Series animation complete');
});
export default Highcharts;
Creating Custom Series Types
Extend existing series types to create new ones:
import Highcharts from 'highcharts/es-modules/masters/highcharts.src.js';
import SeriesRegistry from 'highcharts/es-modules/Core/Series/SeriesRegistry.js';
const { seriesTypes } = SeriesRegistry;
class CustomSeries extends seriesTypes.line {
// Custom initialization
init() {
super.init.apply(this, arguments);
console.log('Custom series initialized');
}
// Custom drawing
drawGraph() {
super.drawGraph.apply(this, arguments);
// Add custom rendering
if (this.graph) {
this.graph.attr({
'stroke-dasharray': '10,10'
});
}
}
}
// Register the series type
SeriesRegistry.registerSeriesType('custom', CustomSeries);
export default Highcharts;
Accessing Internal APIs
Internal APIs (not listed in the official documentation) may change between versions. Test your plugins with new releases.
// Access renderer
const renderer = chart.renderer;
// Access pointer
const pointer = chart.pointer;
// Access internal properties
const plotArea = {
x: chart.plotLeft,
y: chart.plotTop,
width: chart.plotWidth,
height: chart.plotHeight
};
// Normalize mouse events
const normalizedEvent = chart.pointer.normalize(mouseEvent);
Plugin Best Practices
Use IIFE Wrapper
(function (H) {
// Plugin code
}(Highcharts));
Avoid Global Variables
// Bad
var myPluginData = {};
// Good
(function (H) {
let myPluginData = {};
}(Highcharts));
Clean Up Resources
H.addEvent(H.Chart, 'destroy', function() {
// Clean up plugin resources
if (this.customElements) {
this.customElements.forEach(el => el.destroy());
}
});
Document Your Plugin
/**
* Custom Highcharts Plugin
*
* @version 1.0.0
* @author Your Name
* @license MIT
*
* Adds custom functionality to charts
*/
(function (H) {
// Plugin code
}(Highcharts));
TypeScript Support
Extend Highcharts types for TypeScript projects:
import Highcharts from 'highcharts';
// Extend Chart interface
declare module 'highcharts' {
interface Chart {
customMethod(): void;
}
interface Series {
trackball?: SVGElement;
}
}
// Implement extension
Highcharts.Chart.prototype.customMethod = function() {
console.log('Custom method');
};
Common Extension Patterns
H.addEvent(H.Chart, 'load', function() {
const chart = this;
chart.customButton = chart.renderer.button(
'Custom Action',
chart.plotLeft,
chart.plotTop - 30,
function() {
alert('Custom button clicked!');
}
)
.attr({
zIndex: 3
})
.add();
});
Custom Axis Labels
H.wrap(H.Axis.prototype, 'getSeriesExtremes', function(proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
// Add custom logic to extremes calculation
if (this.options.customPadding) {
const range = this.dataMax - this.dataMin;
this.dataMax += range * 0.1;
this.dataMin -= range * 0.1;
}
});
Custom Data Processing
H.addEvent(H.Series, 'afterSetOptions', function(e) {
const options = e.options;
// Process custom data format
if (options.customData) {
options.data = options.customData.map(item => ({
x: item.timestamp,
y: item.value,
custom: item.metadata
}));
}
});
Testing Extensions
// Test your plugin
const chart = Highcharts.chart('container', {
chart: {
type: 'line'
},
series: [{
data: [1, 2, 3, 4, 5]
}]
});
// Verify extension
if (typeof chart.customMethod === 'function') {
chart.customMethod();
console.log('Extension loaded successfully');
}
Resources