/**
* @license Highcharts JS v6.0.4 (2017-12-15)
* Annotations module
*
* (c) 2009-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {
/**
* (c) 2009-2017 Highsoft, Black Label
*
* License: www.highcharts.com/license
*/
var merge = H.merge,
addEvent = H.addEvent,
extend = H.extend,
each = H.each,
isString = H.isString,
isNumber = H.isNumber,
defined = H.defined,
isObject = H.isObject,
inArray = H.inArray,
erase = H.erase,
find = H.find,
format = H.format,
pick = H.pick,
destroyObjectProperties = H.destroyObjectProperties,
tooltipPrototype = H.Tooltip.prototype,
seriesPrototype = H.Series.prototype,
chartPrototype = H.Chart.prototype;
/* ***************************************************************************
*
* MARKER SECTION
* Contains objects and functions for adding a marker element to a path element
*
**************************************************************************** */
/**
* Options for configuring markers for annotations.
*
* An example of the arrow marker:
*
* {
* arrow: {
* id: 'arrow',
* refY: 5,
* refX: 5,
* markerWidth: 10,
* markerHeight: 10,
* children: [{
* tagName: 'path',
* attrs: {
* d: 'M 0 0 L 10 5 L 0 10 Z',
* strokeWidth: 0
* }
* }]
* }
* }
*
* @type {Object}
* @sample highcharts/annotations/custom-markers/
* Define a custom marker for annotations
* @since 6.0.0
* @apioption defs.markers
*/
var defaultMarkers = {
arrow: {
render: false,
id: 'arrow',
refY: 5,
refX: 5,
markerWidth: 10,
markerHeight: 10,
children: [{
tagName: 'path',
attrs: {
d: 'M 0 0 L 10 5 L 0 10 Z', // triangle (used as an arrow)
strokeWidth: 0
}
}]
}
};
var MarkerMixin = {
markerSetter: function(markerType) {
return function(value) {
this.attr(markerType, 'url(#' + value + ')');
};
}
};
extend(MarkerMixin, {
markerEndSetter: MarkerMixin.markerSetter('marker-end'),
markerStartSetter: MarkerMixin.markerSetter('marker-start')
});
H.SVGRenderer.prototype.addMarker = function(id, markerOptions) {
var markerId = pick(id, H.uniqueKey()),
marker = this.createElement('marker').attr({
id: markerId,
markerWidth: pick(markerOptions.markerWidth, 20),
markerHeight: pick(markerOptions.markerHeight, 20),
refX: markerOptions.refX || 0,
refY: markerOptions.refY || 0,
orient: markerOptions.orient || 'auto'
}).add(this.defs),
attrs = {
stroke: markerOptions.color || 'none',
fill: markerOptions.color || 'rgba(0, 0, 0, 0.75)'
},
children = markerOptions.children;
marker.id = markerId;
each(children, function(child) {
this.createElement(child.tagName)
.attr(merge(attrs, child.attrs))
.add(marker);
}, this);
return marker;
};
/* ***************************************************************************
*
* MOCK POINT
*
**************************************************************************** */
/**
* A mock point configuration.
*
* @typedef {Object} MockPointOptions
* @property {Number} x - x value for the point in xAxis scale or pixels
* @property {Number} y - y value for the point in yAxis scale or pixels
* @property {String|Number} [xAxis] - xAxis index or id
* @property {String|Number} [yAxis] - yAxis index or id
*/
/**
* A trimmed point object which imitates {@link Highchart.Point} class.
* It is created when there is a need of pointing to some chart's position
* using axis values or pixel values
*
* @class MockPoint
* @memberOf Highcharts
*
* @param {Highcharts.Chart} - the chart object
* @param {MockPointOptions} - the options object
*/
var MockPoint = H.MockPoint = function(chart, options) {
this.mock = true;
this.series = {
visible: true,
chart: chart,
getPlotBox: seriesPrototype.getPlotBox
};
// this.plotX
// this.plotY
/* Those might not exist if a specific axis was not found/defined */
// this.x?
// this.y?
this.init(chart, options);
};
/**
* A factory function for creating a mock point object
*
* @function #mockPoint
* @memberOf Highcharts
*
* @param {MockPointOptions} mockPointOptions
* @return {MockPoint} a mock point
*/
var mockPoint = H.mockPoint = function(chart, mockPointOptions) {
return new MockPoint(chart, mockPointOptions);
};
MockPoint.prototype = {
/**
* Initialisation of the mock point
*
* @function #init
* @memberOf Highcharts.MockPoint#
*
* @param {Highcharts.Chart} chart - a chart object to which the mock point
* is attached
* @param {MockPointOptions} options - a config for the mock point
*/
init: function(chart, options) {
var xAxisId = options.xAxis,
xAxis = defined(xAxisId) ?
chart.xAxis[xAxisId] || chart.get(xAxisId) :
null,
yAxisId = options.yAxis,
yAxis = defined(yAxisId) ?
chart.yAxis[yAxisId] || chart.get(yAxisId) :
null;
if (xAxis) {
this.x = options.x;
this.series.xAxis = xAxis;
} else {
this.plotX = options.x;
}
if (yAxis) {
this.y = options.y;
this.series.yAxis = yAxis;
} else {
this.plotY = options.y;
}
},
/**
* Update of the point's coordinates (plotX/plotY)
*
* @function #translate
* @memberOf Highcharts.MockPoint#
*
* @return {undefined}
*/
translate: function() {
var series = this.series,
xAxis = series.xAxis,
yAxis = series.yAxis,
plotX = this.plotX,
plotY = this.plotY,
isInside = true;
if (xAxis) {
this.plotX = plotX = xAxis.toPixels(this.x, true);
isInside = plotX >= 0 && plotX <= xAxis.len;
}
if (yAxis) {
this.plotY = plotY = yAxis.toPixels(this.y, true);
isInside = isInside && plotY >= 0 && plotY <= yAxis.len;
}
this.isInside = isInside;
},
/**
* Returns a box to which an item can be aligned to
*
* @function #alignToBox
* @memberOf Highcharts.MockPoint#
*
* @param {Boolean} [forceTranslate=false] - whether to update the point's
* coordinates
* @return {Array.} A quadruple of numbers which denotes x, y,
* width and height of the box
**/
alignToBox: function(forceTranslate) {
if (forceTranslate) {
this.translate();
}
var x = this.plotX,
y = this.plotY,
temp;
if (this.series.chart.inverted) {
temp = x;
x = y;
y = temp;
}
return [x, y, 0, 0];
},
/**
* Returns a label config object -
* the same as Highcharts.Point.prototype.getLabelConfig
*
* @function #getLabelConfig
* @memberOf Highcharts.MockPoint#
*
* @return {Object} labelConfig - label config object
* @return {Number|undefined} labelConfig.x - x value translated to x axis scale
* @return {Number|undefined} labelConfig.y - y value translated to y axis scale
* @return {MockPoint} labelConfig.point - the instance of the point
*/
getLabelConfig: function() {
return {
x: this.x,
y: this.y,
point: this
};
}
};
/* ***************************************************************************
*
* ANNOTATION
*
**************************************************************************** */
H.defaultOptions.annotations = [];
/**
* An annotation class which serves as a container for items like labels or shapes.
* Created items are positioned on the chart either by linking them to
* existing points or created mock points
*
* @class Annotation
* @memberOf Highcharts
*
* @param {Highcharts.Chart} - the chart object
* @param {AnnotationOptions} - the options object
*/
var Annotation = H.Annotation = function(chart, userOptions) {
this.chart = chart;
this.labels = [];
this.shapes = [];
this.options = merge(this.defaultOptions, userOptions);
this.init(chart, userOptions);
};
Annotation.prototype = {
/**
* Shapes which do not have background - the object is used for proper
* setting of the contrast color
*
* @memberOf Highcharts.Annotation#
* @type {Array.}
*/
shapesWithoutBackground: ['connector'],
/**
* A map object which allows to map options attributes to element attributes
*
* @memberOf Highcharts.Annotation#
* @type {Object}
*/
attrsMap: {
backgroundColor: 'fill',
borderColor: 'stroke',
borderWidth: 'stroke-width',
strokeWidth: 'stroke-width',
stroke: 'stroke',
fill: 'fill',
zIndex: 'zIndex',
width: 'width',
height: 'height',
borderRadius: 'r',
r: 'r',
padding: 'padding',
dashStyle: 'dashstyle'
},
/**
* Options for configuring annotations, for example labels, arrows or
* shapes. Annotations can be tied to points, axis coordinates or chart
* pixel coordinates.
*
* @type {Array