UNPKG

highcharts

Version:
1,296 lines (1,291 loc) 358 kB
/** * @license Highstock JS v9.0.1 (2021-02-16) * * Advanced Highstock tools * * (c) 2010-2021 Highsoft AS * Author: Torstein Honsi * * License: www.highcharts.com/license */ 'use strict'; (function (factory) { if (typeof module === 'object' && module.exports) { factory['default'] = factory; module.exports = factory; } else if (typeof define === 'function' && define.amd) { define('highcharts/modules/stock-tools', ['highcharts', 'highcharts/modules/stock'], function (Highcharts) { factory(Highcharts); factory.Highcharts = Highcharts; return factory; }); } else { factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined); } }(function (Highcharts) { var _modules = Highcharts ? Highcharts._modules : {}; function _registerModule(obj, path, args, fn) { if (!obj.hasOwnProperty(path)) { obj[path] = fn.apply(null, args); } } _registerModule(_modules, 'Extensions/Annotations/Mixins/EventEmitterMixin.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var addEvent = U.addEvent, fireEvent = U.fireEvent, objectEach = U.objectEach, pick = U.pick, removeEvent = U.removeEvent; /* eslint-disable valid-jsdoc */ /** * It provides methods for: * - adding and handling DOM events and a drag event, * - mapping a mouse move event to the distance between two following events. * The units of the distance are specific to a transformation, * e.g. for rotation they are radians, for scaling they are scale factors. * * @private * @mixin * @memberOf Annotation */ var eventEmitterMixin = { /** * Add emitter events. */ addEvents: function () { var emitter = this, addMouseDownEvent = function (element) { addEvent(element, H.isTouchDevice ? 'touchstart' : 'mousedown', function (e) { emitter.onMouseDown(e); }, { passive: false }); }; addMouseDownEvent(this.graphic.element); (emitter.labels || []).forEach(function (label) { if (label.options.useHTML && label.graphic.text) { // Mousedown event bound to HTML element (#13070). addMouseDownEvent(label.graphic.text.element); } }); objectEach(emitter.options.events, function (event, type) { var eventHandler = function (e) { if (type !== 'click' || !emitter.cancelClick) { event.call(emitter, emitter.chart.pointer.normalize(e), emitter.target); } }; if ((emitter.nonDOMEvents || []).indexOf(type) === -1) { emitter.graphic.on(type, eventHandler); } else { addEvent(emitter, type, eventHandler, { passive: false }); } }); if (emitter.options.draggable) { addEvent(emitter, 'drag', emitter.onDrag); if (!emitter.graphic.renderer.styledMode) { var cssPointer_1 = { cursor: { x: 'ew-resize', y: 'ns-resize', xy: 'move' }[emitter.options.draggable] }; emitter.graphic.css(cssPointer_1); (emitter.labels || []).forEach(function (label) { if (label.options.useHTML && label.graphic.text) { label.graphic.text.css(cssPointer_1); } }); } } if (!emitter.isUpdating) { fireEvent(emitter, 'add'); } }, /** * Remove emitter document events. */ removeDocEvents: function () { if (this.removeDrag) { this.removeDrag = this.removeDrag(); } if (this.removeMouseUp) { this.removeMouseUp = this.removeMouseUp(); } }, /** * Mouse down handler. */ onMouseDown: function (e) { var emitter = this, pointer = emitter.chart.pointer, prevChartX, prevChartY; if (e.preventDefault) { e.preventDefault(); } // On right click, do nothing: if (e.button === 2) { return; } e = pointer.normalize(e); prevChartX = e.chartX; prevChartY = e.chartY; emitter.cancelClick = false; emitter.chart.hasDraggedAnnotation = true; emitter.removeDrag = addEvent(H.doc, H.isTouchDevice ? 'touchmove' : 'mousemove', function (e) { emitter.hasDragged = true; e = pointer.normalize(e); e.prevChartX = prevChartX; e.prevChartY = prevChartY; fireEvent(emitter, 'drag', e); prevChartX = e.chartX; prevChartY = e.chartY; }, H.isTouchDevice ? { passive: false } : void 0); emitter.removeMouseUp = addEvent(H.doc, H.isTouchDevice ? 'touchend' : 'mouseup', function (e) { emitter.cancelClick = emitter.hasDragged; emitter.hasDragged = false; emitter.chart.hasDraggedAnnotation = false; // ControlPoints vs Annotation: fireEvent(pick(emitter.target, emitter), 'afterUpdate'); emitter.onMouseUp(e); }, H.isTouchDevice ? { passive: false } : void 0); }, /** * Mouse up handler. */ onMouseUp: function (_e) { var chart = this.chart, annotation = this.target || this, annotationsOptions = chart.options.annotations, index = chart.annotations.indexOf(annotation); this.removeDocEvents(); annotationsOptions[index] = annotation.options; }, /** * Drag and drop event. All basic annotations should share this * capability as well as the extended ones. */ onDrag: function (e) { if (this.chart.isInsidePlot(e.chartX - this.chart.plotLeft, e.chartY - this.chart.plotTop)) { var translation = this.mouseMoveToTranslation(e); if (this.options.draggable === 'x') { translation.y = 0; } if (this.options.draggable === 'y') { translation.x = 0; } if (this.points.length) { this.translate(translation.x, translation.y); } else { this.shapes.forEach(function (shape) { shape.translate(translation.x, translation.y); }); this.labels.forEach(function (label) { label.translate(translation.x, translation.y); }); } this.redraw(false); } }, /** * Map mouse move event to the radians. */ mouseMoveToRadians: function (e, cx, cy) { var prevDy = e.prevChartY - cy, prevDx = e.prevChartX - cx, dy = e.chartY - cy, dx = e.chartX - cx, temp; if (this.chart.inverted) { temp = prevDx; prevDx = prevDy; prevDy = temp; temp = dx; dx = dy; dy = temp; } return Math.atan2(dy, dx) - Math.atan2(prevDy, prevDx); }, /** * Map mouse move event to the distance between two following events. */ mouseMoveToTranslation: function (e) { var dx = e.chartX - e.prevChartX, dy = e.chartY - e.prevChartY, temp; if (this.chart.inverted) { temp = dy; dy = dx; dx = temp; } return { x: dx, y: dy }; }, /** * Map mouse move to the scale factors. * * @param {Object} e event * @param {number} cx center x * @param {number} cy center y **/ mouseMoveToScale: function (e, cx, cy) { var prevDx = e.prevChartX - cx, prevDy = e.prevChartY - cy, dx = e.chartX - cx, dy = e.chartY - cy, sx = (dx || 1) / (prevDx || 1), sy = (dy || 1) / (prevDy || 1), temp; if (this.chart.inverted) { temp = sy; sy = sx; sx = temp; } return { x: sx, y: sy }; }, /** * Destroy the event emitter. */ destroy: function () { this.removeDocEvents(); removeEvent(this); this.hcEvents = null; } }; return eventEmitterMixin; }); _registerModule(_modules, 'Extensions/Annotations/ControlPoint.js', [_modules['Core/Utilities.js'], _modules['Extensions/Annotations/Mixins/EventEmitterMixin.js']], function (U, eventEmitterMixin) { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /** * Callback to modify annotation's possitioner controls. * * @callback Highcharts.AnnotationControlPointPositionerFunction * @param {Highcharts.AnnotationControlPoint} this * @param {Highcharts.AnnotationControllable} target * @return {Highcharts.PositionObject} */ var extend = U.extend, merge = U.merge, pick = U.pick; /* eslint-disable no-invalid-this, valid-jsdoc */ /** * A control point class which is a connection between controllable * transform methods and a user actions. * * @requires modules/annotations * * @class * @name Highcharts.AnnotationControlPoint * * @hideconstructor * * @param {Highcharts.Chart} chart * A chart instance. * * @param {Highcharts.AnnotationControllable} target * A controllable instance which is a target for a control point. * * @param {Highcharts.AnnotationControlPointOptionsObject} options * An options object. * * @param {number} [index] * Point index. */ var ControlPoint = /** @class */ (function () { function ControlPoint(chart, target, options, index) { /** * * Properties * */ this.addEvents = eventEmitterMixin.addEvents; this.graphic = void 0; this.mouseMoveToRadians = eventEmitterMixin.mouseMoveToRadians; this.mouseMoveToScale = eventEmitterMixin.mouseMoveToScale; this.mouseMoveToTranslation = eventEmitterMixin.mouseMoveToTranslation; this.onDrag = eventEmitterMixin.onDrag; this.onMouseDown = eventEmitterMixin.onMouseDown; this.onMouseUp = eventEmitterMixin.onMouseUp; this.removeDocEvents = eventEmitterMixin.removeDocEvents; /** * * Functions * */ /** * List of events for `anntation.options.events` that should not be * added to `annotation.graphic` but to the `annotation`. * @private * @name Highcharts.AnnotationControlPoint#nonDOMEvents * @type {Array<string>} */ this.nonDOMEvents = ['drag']; this.chart = chart; this.target = target; this.options = options; this.index = pick(options.index, index); } /** * Set the visibility of the control point. * * @function Highcharts.AnnotationControlPoint#setVisibility * * @param {boolean} visible * Visibility of the control point. * * @return {void} */ ControlPoint.prototype.setVisibility = function (visible) { this.graphic.attr('visibility', visible ? 'visible' : 'hidden'); this.options.visible = visible; }; /** * Render the control point. * @private */ ControlPoint.prototype.render = function () { var chart = this.chart, options = this.options; this.graphic = chart.renderer .symbol(options.symbol, 0, 0, options.width, options.height) .add(chart.controlPointsGroup) .css(options.style); this.setVisibility(options.visible); // npm test -- --tests "highcharts/annotations-advanced/*" this.addEvents(); }; /** * Redraw the control point. * @private * @param {boolean} [animation] */ ControlPoint.prototype.redraw = function (animation) { this.graphic[animation ? 'animate' : 'attr'](this.options.positioner.call(this, this.target)); }; /** * Destroy the control point. * @private */ ControlPoint.prototype.destroy = function () { eventEmitterMixin.destroy.call(this); if (this.graphic) { this.graphic = this.graphic.destroy(); } this.chart = null; this.target = null; this.options = null; }; /** * Update the control point. * * @function Highcharts.AnnotationControlPoint#update * * @param {Partial<Highcharts.AnnotationControlPointOptionsObject>} userOptions * New options for the control point. * * @return {void} */ ControlPoint.prototype.update = function (userOptions) { var chart = this.chart, target = this.target, index = this.index, options = merge(true, this.options, userOptions); this.destroy(); this.constructor(chart, target, options, index); this.render(chart.controlPointsGroup); this.redraw(); }; return ControlPoint; }()); return ControlPoint; }); _registerModule(_modules, 'Extensions/Annotations/MockPoint.js', [_modules['Core/Series/Series.js'], _modules['Core/Utilities.js'], _modules['Core/Axis/Axis.js']], function (Series, U, Axis) { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /** * @private * @interface Highcharts.AnnotationMockLabelOptionsObject */ /** * Point instance of the point. * @name Highcharts.AnnotationMockLabelOptionsObject#point * @type {Highcharts.AnnotationMockPoint} */ /** * X value translated to x axis scale. * @name Highcharts.AnnotationMockLabelOptionsObject#x * @type {number|null} */ /** * Y value translated to y axis scale. * @name Highcharts.AnnotationMockLabelOptionsObject#y * @type {number|null} */ /** * A mock series instance imitating a real series from a real point. * @private * @interface Highcharts.AnnotationMockSeries */ /** * Whether a series is visible. * @name Highcharts.AnnotationMockSeries#visible * @type {boolean} */ /** * A chart instance. * @name Highcharts.AnnotationMockSeries#chart * @type {Highcharts.Chart} */ /** * @name Highcharts.AnnotationMockSeries#getPlotBox * @type {Function} */ /** * Indicates if this is a mock point for an annotation. * @name Highcharts.Point#mock * @type {boolean|undefined} */ var defined = U.defined, extend = U.extend, fireEvent = U.fireEvent; /* eslint-disable no-invalid-this, valid-jsdoc */ /** * 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 * * @requires modules/annotations * * @private * @class * @name Highcharts.AnnotationMockPoint * * @hideconstructor * * @param {Highcharts.Chart} chart * The chart instance. * * @param {Highcharts.AnnotationControllable|null} target * The related controllable. * * @param {Highcharts.AnnotationMockPointOptionsObject|Function} options * The options object. */ var MockPoint = /** @class */ (function () { function MockPoint(chart, target, options) { this.isInside = void 0; this.plotX = void 0; this.plotY = void 0; this.x = void 0; this.y = void 0; /* * * * Functions * * */ /** * A flag indicating that a point is not the real one. * * @type {boolean} * @default true */ this.mock = true; /** * A mock series instance imitating a real series from a real point. * * @name Annotation.AnnotationMockPoint#series * @type {Highcharts.AnnotationMockSeries} */ this.series = { visible: true, chart: chart, getPlotBox: Series.prototype.getPlotBox }; /** * @name Annotation.AnnotationMockPoint#target * @type {Highcharts.AnnotationControllable|null} */ this.target = target || null; /** * Options for the mock point. * * @name Annotation.AnnotationMockPoint#options * @type {Highcharts.AnnotationsMockPointOptionsObject} */ this.options = options; /** * If an xAxis is set it represents the point's value in terms of the * xAxis. * * @name Annotation.AnnotationMockPoint#x * @type {number|undefined} */ /** * If an yAxis is set it represents the point's value in terms of the * yAxis. * * @name Annotation.AnnotationMockPoint#y * @type {number|undefined} */ /** * It represents the point's pixel x coordinate relative to its plot * box. * * @name Annotation.AnnotationMockPoint#plotX * @type {number|undefined} */ /** * It represents the point's pixel y position relative to its plot box. * * @name Annotation.AnnotationMockPoint#plotY * @type {number|undefined} */ /** * Whether the point is inside the plot box. * * @name Annotation.AnnotationMockPoint#isInside * @type {boolean|undefined} */ this.applyOptions(this.getOptions()); } /** * Create a mock point from a real Highcharts point. * * @private * @static * * @param {Highcharts.Point} point * * @return {Highcharts.AnnotationMockPoint} * A mock point instance. */ MockPoint.fromPoint = function (point) { return new MockPoint(point.series.chart, null, { x: point.x, y: point.y, xAxis: point.series.xAxis, yAxis: point.series.yAxis }); }; /** * Get the pixel position from the point like object. * * @private * @static * * @param {Highcharts.AnnotationPointType} point * * @param {boolean} [paneCoordinates] * whether the pixel position should be relative * * @return {Highcharts.PositionObject} pixel position */ MockPoint.pointToPixels = function (point, paneCoordinates) { var series = point.series, chart = series.chart, x = point.plotX, y = point.plotY, plotBox; if (chart.inverted) { if (point.mock) { x = point.plotY; y = point.plotX; } else { x = chart.plotWidth - point.plotY; y = chart.plotHeight - point.plotX; } } if (series && !paneCoordinates) { plotBox = series.getPlotBox(); x += plotBox.translateX; y += plotBox.translateY; } return { x: x, y: y }; }; /** * Get fresh mock point options from the point like object. * * @private * @static * * @param {Highcharts.AnnotationPointType} point * * @return {Highcharts.AnnotationMockPointOptionsObject} * A mock point's options. */ MockPoint.pointToOptions = function (point) { return { x: point.x, y: point.y, xAxis: point.series.xAxis, yAxis: point.series.yAxis }; }; /** * Check if the point has dynamic options. * @private * @return {boolean} * A positive flag if the point has dynamic options. */ MockPoint.prototype.hasDynamicOptions = function () { return typeof this.options === 'function'; }; /** * Get the point's options. * @private * @return {Highcharts.AnnotationMockPointOptionsObject} * The mock point's options. */ MockPoint.prototype.getOptions = function () { return this.hasDynamicOptions() ? this.options(this.target) : this.options; }; /** * Apply options for the point. * @private * @param {Highcharts.AnnotationMockPointOptionsObject} options */ MockPoint.prototype.applyOptions = function (options) { this.command = options.command; this.setAxis(options, 'x'); this.setAxis(options, 'y'); this.refresh(); }; /** * Set x or y axis. * @private * @param {Highcharts.AnnotationMockPointOptionsObject} options * @param {string} xOrY * 'x' or 'y' string literal */ MockPoint.prototype.setAxis = function (options, xOrY) { var axisName = (xOrY + 'Axis'), axisOptions = options[axisName], chart = this.series.chart; this.series[axisName] = axisOptions instanceof Axis ? axisOptions : defined(axisOptions) ? (chart[axisName][axisOptions] || chart.get(axisOptions)) : null; }; /** * Transform the mock point to an anchor (relative position on the chart). * @private * @return {Array<number>} * A quadruple of numbers which denotes x, y, width and height of the box **/ MockPoint.prototype.toAnchor = function () { var anchor = [this.plotX, this.plotY, 0, 0]; if (this.series.chart.inverted) { anchor[0] = this.plotY; anchor[1] = this.plotX; } return anchor; }; /** * Returns a label config object - the same as * Highcharts.Point.prototype.getLabelConfig * @private * @return {Highcharts.AnnotationMockLabelOptionsObject} the point's label config */ MockPoint.prototype.getLabelConfig = function () { return { x: this.x, y: this.y, point: this }; }; /** * Check if the point is inside its pane. * @private * @return {boolean} A flag indicating whether the point is inside the pane. */ MockPoint.prototype.isInsidePlot = function () { var plotX = this.plotX, plotY = this.plotY, xAxis = this.series.xAxis, yAxis = this.series.yAxis, e = { x: plotX, y: plotY, isInsidePlot: true }; if (xAxis) { e.isInsidePlot = defined(plotX) && plotX >= 0 && plotX <= xAxis.len; } if (yAxis) { e.isInsidePlot = e.isInsidePlot && defined(plotY) && plotY >= 0 && plotY <= yAxis.len; } fireEvent(this.series.chart, 'afterIsInsidePlot', e); return e.isInsidePlot; }; /** * Refresh point values and coordinates based on its options. * @private */ MockPoint.prototype.refresh = function () { var series = this.series, xAxis = series.xAxis, yAxis = series.yAxis, options = this.getOptions(); if (xAxis) { this.x = options.x; this.plotX = xAxis.toPixels(options.x, true); } else { this.x = null; this.plotX = options.x; } if (yAxis) { this.y = options.y; this.plotY = yAxis.toPixels(options.y, true); } else { this.y = null; this.plotY = options.y; } this.isInside = this.isInsidePlot(); }; /** * Translate the point. * * @private * * @param {number|undefined} cx * Origin x transformation. * * @param {number|undefined} cy * Origin y transformation. * * @param {number} dx * Translation for x coordinate. * * @param {number} dy * Translation for y coordinate. **/ MockPoint.prototype.translate = function (_cx, _cy, dx, dy) { if (!this.hasDynamicOptions()) { this.plotX += dx; this.plotY += dy; this.refreshOptions(); } }; /** * Scale the point. * * @private * * @param {number} cx * Origin x transformation. * * @param {number} cy * Origin y transformation. * * @param {number} sx * Scale factor x. * * @param {number} sy * Scale factor y. */ MockPoint.prototype.scale = function (cx, cy, sx, sy) { if (!this.hasDynamicOptions()) { var x = this.plotX * sx, y = this.plotY * sy, tx = (1 - sx) * cx, ty = (1 - sy) * cy; this.plotX = tx + x; this.plotY = ty + y; this.refreshOptions(); } }; /** * Rotate the point. * @private * @param {number} cx origin x rotation * @param {number} cy origin y rotation * @param {number} radians */ MockPoint.prototype.rotate = function (cx, cy, radians) { if (!this.hasDynamicOptions()) { var cos = Math.cos(radians), sin = Math.sin(radians), x = this.plotX, y = this.plotY, tx, ty; x -= cx; y -= cy; tx = x * cos - y * sin; ty = x * sin + y * cos; this.plotX = tx + cx; this.plotY = ty + cy; this.refreshOptions(); } }; /** * Refresh point options based on its plot coordinates. * @private */ MockPoint.prototype.refreshOptions = function () { var series = this.series, xAxis = series.xAxis, yAxis = series.yAxis; this.x = this.options.x = xAxis ? this.options.x = xAxis.toValue(this.plotX, true) : this.plotX; this.y = this.options.y = yAxis ? yAxis.toValue(this.plotY, true) : this.plotY; }; return MockPoint; }()); return MockPoint; }); _registerModule(_modules, 'Extensions/Annotations/Mixins/ControllableMixin.js', [_modules['Extensions/Annotations/ControlPoint.js'], _modules['Extensions/Annotations/MockPoint.js'], _modules['Core/Tooltip.js'], _modules['Core/Utilities.js']], function (ControlPoint, MockPoint, Tooltip, U) { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var isObject = U.isObject, isString = U.isString, merge = U.merge, splat = U.splat; /** * An object which denots a controllable's anchor positions - relative and * absolute. * * @private * @interface Highcharts.AnnotationAnchorObject */ /** * Relative to the plot area position * @name Highcharts.AnnotationAnchorObject#relativePosition * @type {Highcharts.BBoxObject} */ /** * Absolute position * @name Highcharts.AnnotationAnchorObject#absolutePosition * @type {Highcharts.BBoxObject} */ /** * @interface Highcharts.AnnotationControllable */ /** * @name Highcharts.AnnotationControllable#annotation * @type {Highcharts.Annotation} */ /** * @name Highcharts.AnnotationControllable#chart * @type {Highcharts.Chart} */ /** * @name Highcharts.AnnotationControllable#collection * @type {string} */ /** * @private * @name Highcharts.AnnotationControllable#controlPoints * @type {Array<Highcharts.AnnotationControlPoint>} */ /** * @name Highcharts.AnnotationControllable#points * @type {Array<Highcharts.Point>} */ /* eslint-disable no-invalid-this, valid-jsdoc */ /** * It provides methods for handling points, control points * and points transformations. * * @private * @mixin * @name Highcharts.AnnotationControllableMixin */ var controllableMixin = { /** * Init the controllable */ init: function (annotation, options, index) { this.annotation = annotation; this.chart = annotation.chart; this.options = options; this.points = []; this.controlPoints = []; this.index = index; this.linkPoints(); this.addControlPoints(); }, /** * Redirect attr usage on the controllable graphic element. */ attr: function () { this.graphic.attr.apply(this.graphic, arguments); }, /** * Get the controllable's points options. * * @return {Array<Highcharts.PointOptionsObject>} * An array of points' options. */ getPointsOptions: function () { var options = this.options; return (options.points || (options.point && splat(options.point))); }, /** * Utility function for mapping item's options * to element's attribute * * @param {Highcharts.AnnotationsLabelsOptions|Highcharts.AnnotationsShapesOptions} options * * @return {Highcharts.SVGAttributes} * Mapped options. */ attrsFromOptions: function (options) { var map = this.constructor.attrsMap, attrs = {}, key, mappedKey, styledMode = this.chart.styledMode; for (key in options) { // eslint-disable-line guard-for-in mappedKey = map[key]; if (mappedKey && (!styledMode || ['fill', 'stroke', 'stroke-width'] .indexOf(mappedKey) === -1)) { attrs[mappedKey] = options[key]; } } return attrs; }, /** * Returns object which denotes anchor position - relative and absolute. * * @param {Highcharts.AnnotationPointType} point * A point like object. * * @return {Highcharts.AnnotationAnchorObject} a controllable anchor */ anchor: function (point) { var plotBox = point.series.getPlotBox(), chart = point.series.chart, box = point.mock ? point.toAnchor() : Tooltip.prototype.getAnchor.call({ chart: point.series.chart }, point), anchor = { x: box[0] + (this.options.x || 0), y: box[1] + (this.options.y || 0), height: box[2] || 0, width: box[3] || 0 }; return { relativePosition: anchor, absolutePosition: merge(anchor, { x: anchor.x + (point.mock ? plotBox.translateX : chart.plotLeft), y: anchor.y + (point.mock ? plotBox.translateY : chart.plotTop) }) }; }, /** * Map point's options to a point-like object. * * @param {string|Function|Highcharts.AnnotationMockPointOptionsObject|Highcharts.AnnotationPointType} pointOptions * Point's options. * * @param {Highcharts.AnnotationPointType} point * A point-like instance. * * @return {Highcharts.AnnotationPointType|null} * if the point is found/set returns this point, otherwise null */ point: function (pointOptions, point) { if (pointOptions && pointOptions.series) { return pointOptions; } if (!point || point.series === null) { if (isObject(pointOptions)) { point = new MockPoint(this.chart, this, pointOptions); } else if (isString(pointOptions)) { point = this.chart.get(pointOptions) || null; } else if (typeof pointOptions === 'function') { var pointConfig = pointOptions.call(point, this); point = pointConfig.series ? pointConfig : new MockPoint(this.chart, this, pointOptions); } } return point; }, /** * Find point-like objects based on points options. * * @return {Array<Annotation.PointLike>} an array of point-like objects */ linkPoints: function () { var pointsOptions = this.getPointsOptions(), points = this.points, len = (pointsOptions && pointsOptions.length) || 0, i, point; for (i = 0; i < len; i++) { point = this.point(pointsOptions[i], points[i]); if (!point) { points.length = 0; return; } if (point.mock) { point.refresh(); } points[i] = point; } return points; }, /** * Add control points to a controllable. */ addControlPoints: function () { var controlPointsOptions = this.options.controlPoints; (controlPointsOptions || []).forEach(function (controlPointOptions, i) { var options = merge(this.options.controlPointOptions, controlPointOptions); if (!options.index) { options.index = i; } controlPointsOptions[i] = options; this.controlPoints.push(new ControlPoint(this.chart, this, options)); }, this); }, /** * Check if a controllable should be rendered/redrawn. * * @return {boolean} * Whether a controllable should be drawn. */ shouldBeDrawn: function () { return Boolean(this.points.length); }, /** * Render a controllable. */ render: function (_parentGroup) { this.controlPoints.forEach(function (controlPoint) { controlPoint.render(); }); }, /** * Redraw a controllable. * * @param {boolean} [animation] */ redraw: function (animation) { this.controlPoints.forEach(function (controlPoint) { controlPoint.redraw(animation); }); }, /** * Transform a controllable with a specific transformation. * * @param {string} transformation a transformation name * @param {number|null} cx origin x transformation * @param {number|null} cy origin y transformation * @param {number} p1 param for the transformation * @param {number} [p2] param for the transformation */ transform: function (transformation, cx, cy, p1, p2) { if (this.chart.inverted) { var temp = cx; cx = cy; cy = temp; } this.points.forEach(function (point, i) { this.transformPoint(transformation, cx, cy, p1, p2, i); }, this); }, /** * Transform a point with a specific transformation * If a transformed point is a real point it is replaced with * the mock point. * * @param {string} transformation a transformation name * @param {number|null} cx origin x transformation * @param {number|null} cy origin y transformation * @param {number} p1 param for the transformation * @param {number|undefined} p2 param for the transformation * @param {number} i index of the point */ transformPoint: function (transformation, cx, cy, p1, p2, i) { var point = this.points[i]; if (!point.mock) { point = this.points[i] = MockPoint.fromPoint(point); } point[transformation](cx, cy, p1, p2); }, /** * Translate a controllable. * * @param {number} dx translation for x coordinate * @param {number} dy translation for y coordinate **/ translate: function (dx, dy) { this.transform('translate', null, null, dx, dy); }, /** * Translate a specific point within a controllable. * * @param {number} dx translation for x coordinate * @param {number} dy translation for y coordinate * @param {number} i index of the point **/ translatePoint: function (dx, dy, i) { this.transformPoint('translate', null, null, dx, dy, i); }, /** * Translate shape within controllable item. * Replaces `controllable.translate` method. * * @param {number} dx translation for x coordinate * @param {number} dy translation for y coordinate */ translateShape: function (dx, dy) { var chart = this.annotation.chart, // Annotation.options shapeOptions = this.annotation.userOptions, // Chart.options.annotations annotationIndex = chart.annotations.indexOf(this.annotation), chartOptions = chart.options.annotations[annotationIndex]; this.translatePoint(dx, dy, 0); // Options stored in: // - chart (for exporting) // - current config (for redraws) chartOptions[this.collection][this.index].point = this.options.point; shapeOptions[this.collection][this.index].point = this.options.point; }, /** * Rotate a controllable. * * @param {number} cx origin x rotation * @param {number} cy origin y rotation * @param {number} radians **/ rotate: function (cx, cy, radians) { this.transform('rotate', cx, cy, radians); }, /** * Scale a controllable. * * @param {number} cx origin x rotation * @param {number} cy origin y rotation * @param {number} sx scale factor x * @param {number} sy scale factor y */ scale: function (cx, cy, sx, sy) { this.transform('scale', cx, cy, sx, sy); }, /** * Set control points' visibility. * * @param {boolean} visible */ setControlPointsVisibility: function (visible) { this.controlPoints.forEach(function (controlPoint) { controlPoint.setVisibility(visible); }); }, /** * Destroy a controllable. */ destroy: function () { if (this.graphic) { this.graphic = this.graphic.destroy(); } if (this.tracker) { this.tracker = this.tracker.destroy(); } this.controlPoints.forEach(function (controlPoint) { controlPoint.destroy(); }); this.chart = null; this.points = null; this.controlPoints = null; this.options = null; if (this.annotation) { this.annotation = null; } }, /** * Update a controllable. * * @param {Object} newOptions */ update: function (newOptions) { var annotation = this.annotation, options = merge(true, this.options, newOptions), parentGroup = this.graphic.parentGroup; this.destroy(); this.constructor(annotation, options); this.render(parentGroup); this.redraw(); } }; return controllableMixin; }); _registerModule(_modules, 'Extensions/Annotations/Mixins/MarkerMixin.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (Chart, SVGRenderer, U) { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var addEvent = U.addEvent, defined = U.defined, merge = U.merge, objectEach = U.objectEach, uniqueKey = U.uniqueKey; /** * Options for configuring markers for annotations. * * An example of the arrow marker: * <pre> * { * arrow: { * id: 'arrow', * tagName: 'marker', * refY: 5, * refX: 5, * markerWidth: 10, * markerHeight: 10, * children: [{ * tagName: 'path', * attrs: { * d: 'M 0 0 L 10 5 L 0 10 Z', * 'stroke-width': 0 * }