Highcharts 的扩展开发与封装一个插件
Highcharts 扩展开发
自版本2.3起,Highcharts采用模块化设计,便于扩展。
- 主要的图表概念对应于 JavaScript 的原型或“类”,这些类在 Highcharts 命名空间中显示出来,且可以方便地进行修改。例如
Highcharts.Series,Highcharts.Tooltip,Highcharts.Chart,Highcharts.Axis,Highcharts.Legend等。查看 完整列表 的类。 - 构造函数的逻辑因此被保留在一个方法中,
init,以便覆盖初始化过程。 - 添加事件可以通过
addEvent:
Highcharts.addEvent(chart, 'load', someFunction); - 一些原型和属性列在 api.highcharts.com 上,但并非全部。未列出的原型和属性意味着它们可能会在未来的版本中发生变化,因为我们在优化和调整库。我们并不反对使用这些成员,但提醒您,您的插件应在未来版本的 Highcharts 中进行测试。可以通过检查 Highcharts 命名空间以及开发者工具中生成的图表对象,或者研究
highcharts.src.js的源代码来识别这些成员。
封装一个插件
Highcharts插件应当包裹在一个匿名自执行函数中,以防止变量污染全局作用域。一个好的做法是这样包裹插件:
(function (H) {
const { Chart, Series } = H; // shortcuts to Highcharts classes
let localVar; // local variable
doSomething();
}(Highcharts));
在图表初始化时加载扩展
事件可以添加到类和实例中。为了在每个图表上都初始化扩展,可以在Chart类上添加一个事件监听器。
H.addEvent(H.Chart, 'load', function(e) {
const chart = e.target;
H.addEvent(chart.container, 'click', function(e) {
e = chart.pointer.normalize(e);
console.log(`Clicked chart at ${e.chartX}, ${e.chartY}`);
});
H.addEvent(chart.xAxis[0], 'afterSetExtremes', function(e) {
console.log(`Set extremes to ${e.min}, ${e.max}`);
});
});
上手试一试
封装原型函数
JavaScript 具有极强的动态特性,在实时修改脚本行为方面非常强大。在 Highcharts 中,我们创建了一个名为 wrap的工具,它可以包装现有的原型方法(“方法”),允许你在其前后添加自己的代码。
wrap函数的第一个参数是父对象,第二个参数是要包裹的函数名,第三个参数是一个回调替代函数。原始函数作为第一个参数传递给替代函数,原始参数紧随其后。
代码示例:
H.wrap(H.Series.types.line.prototype, 'drawGraph', function (proceed) {
// Before the original function
console.log("We are about to draw the graph: ", typeof 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: ", typeof this.graph);
});
上手试一试
在加载ES模块时,可以 直接访问模块 。
扩展示例
案例:客户希望在Highcharts Stock的柱状系列中使用标记(“轨迹球”)。目前,标记功能仅支持线性系列。为了实现这个功能,可以编写一个小插件。
这个插件会在每个系列中添加一个轨迹球,前提是该系列尚未支持或包含标记。
为此,我们从以下代码开始,创建一个自执行函数来包含这个插件:
(function (H) {
// This is a self executing function
// The global variable Highcharts is passed along with a reference H
}(Highcharts));
之后,我们需要为Tooltip.prototype.refresh 和 Tooltip.prototype.hide方法添加额外的功能。为此,我们会对这些方法进行包装:
(function (H) {
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed, points) {
// When refresh is called, code inside this wrap is executed
});
}(Highcharts));
当调用刷新时,我们希望它在每个系列的当前点上绘制一个轨迹球。如果某个系列已经包含标记,则应跳过此功能。
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed, points) {
// Run the original proceed method
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
// For each point add or update trackball
H.each(points, function (point) {
// Function variables
var series = point.series,
chart = series.chart,
pointX = point.plotX + series.xAxis.pos,
pointY = H.pick(point.plotClose, point.plotY) + series.yAxis.pos;
// If trackball functionality does not already exist
if (!series.options.marker) {
// If trackball is not defined
if (!series.trackball) {
// Creates a new trackball with same color as the series
series.trackball = chart.renderer.circle(pointX, pointY, 5).attr({
fill: series.color,
stroke: 'white',
'stroke-width': 1,
zIndex: 5
}).add();
} else {
// Updates the position of the trackball
series.trackball.attr({
x: pointX,
y: pointY
});
}
}
});
});
现在轨迹球会显示出来,但我们还需要在工具提示被移除时将其隐藏。因此,隐藏方法中也需要添加一些额外的功能。在包含插件的函数内部添加了一个新的包装:
H.wrap(H.Tooltip.prototype, 'hide', function (proceed) {
var series = this.chart.series;
// Run original proceed method
proceed.apply(this);
// For each series destroy trackball
H.each(series, function (serie) {
var trackball = serie.trackball;
if (trackball) {
serie.trackball = trackball.destroy();
}
});
});
就是这些, 整个示例可以在jsFiddle中查看 。









