annotations.src.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. /* *
  2. *
  3. * (c) 2009-2017 Highsoft, Black Label
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8. *
  9. * */
  10. 'use strict';
  11. import Chart from '../parts/Chart.js';
  12. var chartProto = Chart.prototype;
  13. import ControllableMixin from './controllable/controllableMixin.js';
  14. import ControllableRect from './controllable/ControllableRect.js';
  15. import ControllableCircle from './controllable/ControllableCircle.js';
  16. import ControllablePath from './controllable/ControllablePath.js';
  17. import ControllableImage from './controllable/ControllableImage.js';
  18. import ControllableLabel from './controllable/ControllableLabel.js';
  19. import ControlPoint from './ControlPoint.js';
  20. import EventEmitterMixin from './eventEmitterMixin.js';
  21. import H from '../parts/Globals.js';
  22. import MockPoint from './MockPoint.js';
  23. import Pointer from '../parts/Pointer.js';
  24. import U from '../parts/Utilities.js';
  25. var addEvent = U.addEvent, defined = U.defined, destroyObjectProperties = U.destroyObjectProperties, erase = U.erase, extend = U.extend, find = U.find, fireEvent = U.fireEvent, merge = U.merge, pick = U.pick, splat = U.splat, wrap = U.wrap;
  26. /* *********************************************************************
  27. *
  28. * ANNOTATION
  29. *
  30. ******************************************************************** */
  31. /**
  32. * Possible directions for draggable annotations. An empty string (`''`)
  33. * makes the annotation undraggable.
  34. *
  35. * @typedef {''|'x'|'xy'|'y'} Highcharts.AnnotationDraggableValue
  36. */
  37. /**
  38. * @private
  39. * @typedef {
  40. * Highcharts.AnnotationControllableCircle|
  41. * Highcharts.AnnotationControllableImage|
  42. * Highcharts.AnnotationControllablePath|
  43. * Highcharts.AnnotationControllableRect
  44. * }
  45. * Highcharts.AnnotationShapeType
  46. * @requires modules/annotations
  47. */
  48. /**
  49. * @private
  50. * @typedef {
  51. * Highcharts.AnnotationControllableLabel
  52. * }
  53. * Highcharts.AnnotationLabelType
  54. * @requires modules/annotations
  55. */
  56. /**
  57. * A point-like object, a mock point or a point used in series.
  58. * @private
  59. * @typedef {Highcharts.AnnotationMockPoint|Highcharts.Point} Highcharts.AnnotationPointType
  60. * @requires modules/annotations
  61. */
  62. /* eslint-disable no-invalid-this, valid-jsdoc */
  63. /**
  64. * An annotation class which serves as a container for items like labels or
  65. * shapes. Created items are positioned on the chart either by linking them to
  66. * existing points or created mock points
  67. *
  68. * @class
  69. * @name Highcharts.Annotation
  70. *
  71. * @param {Highcharts.Chart} chart a chart instance
  72. * @param {Highcharts.AnnotationsOptions} userOptions the options object
  73. */
  74. var Annotation = /** @class */ (function () {
  75. /* *
  76. *
  77. * Constructors
  78. *
  79. * */
  80. function Annotation(chart, userOptions) {
  81. /* *
  82. *
  83. * Properties
  84. *
  85. * */
  86. this.annotation = void 0;
  87. this.coll = 'annotations';
  88. this.collection = void 0;
  89. this.graphic = void 0;
  90. this.group = void 0;
  91. this.labelCollector = void 0;
  92. this.labelsGroup = void 0;
  93. this.shapesGroup = void 0;
  94. var labelsAndShapes;
  95. /**
  96. * The chart that the annotation belongs to.
  97. *
  98. * @type {Highcharts.Chart}
  99. */
  100. this.chart = chart;
  101. /**
  102. * The array of points which defines the annotation.
  103. *
  104. * @type {Array<Highcharts.Point>}
  105. */
  106. this.points = [];
  107. /**
  108. * The array of control points.
  109. *
  110. * @private
  111. * @name Highcharts.Annotation#controlPoints
  112. * @type {Array<Annotation.ControlPoint>}
  113. */
  114. this.controlPoints = [];
  115. this.coll = 'annotations';
  116. /**
  117. * The array of labels which belong to the annotation.
  118. *
  119. * @private
  120. * @name Highcharts.Annotation#labels
  121. * @type {Array<Highcharts.AnnotationLabelType>}
  122. */
  123. this.labels = [];
  124. /**
  125. * The array of shapes which belong to the annotation.
  126. *
  127. * @private
  128. * @name Highcharts.Annotation#shapes
  129. * @type {Array<Highcharts.AnnotationShapeType>}
  130. */
  131. this.shapes = [];
  132. /**
  133. * The options for the annotations.
  134. *
  135. * @name Highcharts.Annotation#options
  136. * @type {Highcharts.AnnotationsOptions}
  137. */
  138. this.options = merge(this.defaultOptions, userOptions);
  139. /**
  140. * The user options for the annotations.
  141. *
  142. * @name Highcharts.Annotation#userOptions
  143. * @type {Highcharts.AnnotationsOptions}
  144. */
  145. this.userOptions = userOptions;
  146. // Handle labels and shapes - those are arrays
  147. // Merging does not work with arrays (stores reference)
  148. labelsAndShapes = this.getLabelsAndShapesOptions(this.options, userOptions);
  149. this.options.labels = labelsAndShapes.labels;
  150. this.options.shapes = labelsAndShapes.shapes;
  151. /**
  152. * The callback that reports to the overlapping-labels module which
  153. * labels it should account for.
  154. * @private
  155. * @name Highcharts.Annotation#labelCollector
  156. * @type {Function}
  157. */
  158. /**
  159. * The group svg element.
  160. *
  161. * @name Highcharts.Annotation#group
  162. * @type {Highcharts.SVGElement}
  163. */
  164. /**
  165. * The group svg element of the annotation's shapes.
  166. *
  167. * @name Highcharts.Annotation#shapesGroup
  168. * @type {Highcharts.SVGElement}
  169. */
  170. /**
  171. * The group svg element of the annotation's labels.
  172. *
  173. * @name Highcharts.Annotation#labelsGroup
  174. * @type {Highcharts.SVGElement}
  175. */
  176. this.init(chart, this.options);
  177. }
  178. /**
  179. * Initialize the annotation.
  180. * @private
  181. */
  182. Annotation.prototype.init = function () {
  183. this.linkPoints();
  184. this.addControlPoints();
  185. this.addShapes();
  186. this.addLabels();
  187. this.setLabelCollector();
  188. };
  189. Annotation.prototype.getLabelsAndShapesOptions = function (baseOptions, newOptions) {
  190. var mergedOptions = {};
  191. ['labels', 'shapes'].forEach(function (name) {
  192. if (baseOptions[name]) {
  193. mergedOptions[name] = splat(newOptions[name]).map(function (basicOptions, i) {
  194. return merge(baseOptions[name][i], basicOptions);
  195. });
  196. }
  197. });
  198. return mergedOptions;
  199. };
  200. Annotation.prototype.addShapes = function () {
  201. (this.options.shapes || []).forEach(function (shapeOptions, i) {
  202. var shape = this.initShape(shapeOptions, i);
  203. merge(true, this.options.shapes[i], shape.options);
  204. }, this);
  205. };
  206. Annotation.prototype.addLabels = function () {
  207. (this.options.labels || []).forEach(function (labelsOptions, i) {
  208. var labels = this.initLabel(labelsOptions, i);
  209. merge(true, this.options.labels[i], labels.options);
  210. }, this);
  211. };
  212. Annotation.prototype.addClipPaths = function () {
  213. this.setClipAxes();
  214. if (this.clipXAxis && this.clipYAxis) {
  215. this.clipRect = this.chart.renderer.clipRect(this.getClipBox());
  216. }
  217. };
  218. Annotation.prototype.setClipAxes = function () {
  219. var xAxes = this.chart.xAxis, yAxes = this.chart.yAxis, linkedAxes = (this.options.labels || [])
  220. .concat(this.options.shapes || [])
  221. .reduce(function (axes, labelOrShape) {
  222. return [
  223. xAxes[labelOrShape &&
  224. labelOrShape.point &&
  225. labelOrShape.point.xAxis] || axes[0],
  226. yAxes[labelOrShape &&
  227. labelOrShape.point &&
  228. labelOrShape.point.yAxis] || axes[1]
  229. ];
  230. }, []);
  231. this.clipXAxis = linkedAxes[0];
  232. this.clipYAxis = linkedAxes[1];
  233. };
  234. Annotation.prototype.getClipBox = function () {
  235. if (this.clipXAxis && this.clipYAxis) {
  236. return {
  237. x: this.clipXAxis.left,
  238. y: this.clipYAxis.top,
  239. width: this.clipXAxis.width,
  240. height: this.clipYAxis.height
  241. };
  242. }
  243. };
  244. Annotation.prototype.setLabelCollector = function () {
  245. var annotation = this;
  246. annotation.labelCollector = function () {
  247. return annotation.labels.reduce(function (labels, label) {
  248. if (!label.options.allowOverlap) {
  249. labels.push(label.graphic);
  250. }
  251. return labels;
  252. }, []);
  253. };
  254. annotation.chart.labelCollectors.push(annotation.labelCollector);
  255. };
  256. /**
  257. * Set an annotation options.
  258. * @private
  259. * @param {Highcharts.AnnotationsOptions} - user options for an annotation
  260. */
  261. Annotation.prototype.setOptions = function (userOptions) {
  262. this.options = merge(this.defaultOptions, userOptions);
  263. };
  264. Annotation.prototype.redraw = function (animation) {
  265. this.linkPoints();
  266. if (!this.graphic) {
  267. this.render();
  268. }
  269. if (this.clipRect) {
  270. this.clipRect.animate(this.getClipBox());
  271. }
  272. this.redrawItems(this.shapes, animation);
  273. this.redrawItems(this.labels, animation);
  274. ControllableMixin.redraw.call(this, animation);
  275. };
  276. /**
  277. * @private
  278. * @param {Array<Highcharts.AnnotationControllable>} items
  279. * @param {boolean} [animation]
  280. */
  281. Annotation.prototype.redrawItems = function (items, animation) {
  282. var i = items.length;
  283. // needs a backward loop
  284. // labels/shapes array might be modified
  285. // due to destruction of the item
  286. while (i--) {
  287. this.redrawItem(items[i], animation);
  288. }
  289. };
  290. /**
  291. * @private
  292. * @param {Array<Highcharts.AnnotationControllable>} items
  293. */
  294. Annotation.prototype.renderItems = function (items) {
  295. var i = items.length;
  296. while (i--) {
  297. this.renderItem(items[i]);
  298. }
  299. };
  300. Annotation.prototype.render = function () {
  301. var renderer = this.chart.renderer;
  302. this.graphic = renderer
  303. .g('annotation')
  304. .attr({
  305. zIndex: this.options.zIndex,
  306. visibility: this.options.visible ?
  307. 'visible' :
  308. 'hidden'
  309. })
  310. .add();
  311. this.shapesGroup = renderer
  312. .g('annotation-shapes')
  313. .add(this.graphic)
  314. .clip(this.chart.plotBoxClip);
  315. this.labelsGroup = renderer
  316. .g('annotation-labels')
  317. .attr({
  318. // hideOverlappingLabels requires translation
  319. translateX: 0,
  320. translateY: 0
  321. })
  322. .add(this.graphic);
  323. this.addClipPaths();
  324. if (this.clipRect) {
  325. this.graphic.clip(this.clipRect);
  326. }
  327. // Render shapes and labels before adding events (#13070).
  328. this.renderItems(this.shapes);
  329. this.renderItems(this.labels);
  330. this.addEvents();
  331. ControllableMixin.render.call(this);
  332. };
  333. /**
  334. * Set the annotation's visibility.
  335. * @private
  336. * @param {boolean} [visible]
  337. * Whether to show or hide an annotation. If the param is omitted, the
  338. * annotation's visibility is toggled.
  339. */
  340. Annotation.prototype.setVisibility = function (visible) {
  341. var options = this.options, visibility = pick(visible, !options.visible);
  342. this.graphic.attr('visibility', visibility ? 'visible' : 'hidden');
  343. if (!visibility) {
  344. this.setControlPointsVisibility(false);
  345. }
  346. options.visible = visibility;
  347. };
  348. Annotation.prototype.setControlPointsVisibility = function (visible) {
  349. var setItemControlPointsVisibility = function (item) {
  350. item.setControlPointsVisibility(visible);
  351. };
  352. ControllableMixin.setControlPointsVisibility.call(this, visible);
  353. this.shapes.forEach(setItemControlPointsVisibility);
  354. this.labels.forEach(setItemControlPointsVisibility);
  355. };
  356. /**
  357. * Destroy the annotation. This function does not touch the chart
  358. * that the annotation belongs to (all annotations are kept in
  359. * the chart.annotations array) - it is recommended to use
  360. * {@link Highcharts.Chart#removeAnnotation} instead.
  361. * @private
  362. */
  363. Annotation.prototype.destroy = function () {
  364. var chart = this.chart, destroyItem = function (item) {
  365. item.destroy();
  366. };
  367. this.labels.forEach(destroyItem);
  368. this.shapes.forEach(destroyItem);
  369. this.clipXAxis = null;
  370. this.clipYAxis = null;
  371. erase(chart.labelCollectors, this.labelCollector);
  372. EventEmitterMixin.destroy.call(this);
  373. ControllableMixin.destroy.call(this);
  374. destroyObjectProperties(this, chart);
  375. };
  376. /**
  377. * See {@link Highcharts.Chart#removeAnnotation}.
  378. * @private
  379. */
  380. Annotation.prototype.remove = function () {
  381. // Let chart.update() remove annoations on demand
  382. return this.chart.removeAnnotation(this);
  383. };
  384. /**
  385. * Updates an annotation.
  386. *
  387. * @function Highcharts.Annotation#update
  388. *
  389. * @param {Partial<Highcharts.AnnotationsOptions>} userOptions
  390. * New user options for the annotation.
  391. *
  392. * @return {void}
  393. */
  394. Annotation.prototype.update = function (userOptions, redraw) {
  395. var chart = this.chart, labelsAndShapes = this.getLabelsAndShapesOptions(this.userOptions, userOptions), userOptionsIndex = chart.annotations.indexOf(this), options = merge(true, this.userOptions, userOptions);
  396. options.labels = labelsAndShapes.labels;
  397. options.shapes = labelsAndShapes.shapes;
  398. this.destroy();
  399. this.constructor(chart, options);
  400. // Update options in chart options, used in exporting (#9767):
  401. chart.options.annotations[userOptionsIndex] = options;
  402. this.isUpdating = true;
  403. if (pick(redraw, true)) {
  404. chart.redraw();
  405. }
  406. fireEvent(this, 'afterUpdate');
  407. this.isUpdating = false;
  408. };
  409. /* *************************************************************
  410. * ITEM SECTION
  411. * Contains methods for handling a single item in an annotation
  412. **************************************************************** */
  413. /**
  414. * Initialisation of a single shape
  415. * @private
  416. * @param {Object} shapeOptions - a confg object for a single shape
  417. */
  418. Annotation.prototype.initShape = function (shapeOptions, index) {
  419. var options = merge(this.options.shapeOptions, {
  420. controlPointOptions: this.options.controlPointOptions
  421. }, shapeOptions), shape = new Annotation.shapesMap[options.type](this, options, index);
  422. shape.itemType = 'shape';
  423. this.shapes.push(shape);
  424. return shape;
  425. };
  426. /**
  427. * Initialisation of a single label
  428. * @private
  429. */
  430. Annotation.prototype.initLabel = function (labelOptions, index) {
  431. var options = merge(this.options.labelOptions, {
  432. controlPointOptions: this.options.controlPointOptions
  433. }, labelOptions), label = new ControllableLabel(this, options, index);
  434. label.itemType = 'label';
  435. this.labels.push(label);
  436. return label;
  437. };
  438. /**
  439. * Redraw a single item.
  440. * @private
  441. * @param {Annotation.Label|Annotation.Shape} item
  442. * @param {boolean} [animation]
  443. */
  444. Annotation.prototype.redrawItem = function (item, animation) {
  445. item.linkPoints();
  446. if (!item.shouldBeDrawn()) {
  447. this.destroyItem(item);
  448. }
  449. else {
  450. if (!item.graphic) {
  451. this.renderItem(item);
  452. }
  453. item.redraw(pick(animation, true) && item.graphic.placed);
  454. if (item.points.length) {
  455. this.adjustVisibility(item);
  456. }
  457. }
  458. };
  459. /**
  460. * Hide or show annotaiton attached to points.
  461. * @private
  462. * @param {Annotation.Label|Annotation.Shape} item
  463. */
  464. Annotation.prototype.adjustVisibility = function (item) {
  465. var hasVisiblePoints = false, label = item.graphic;
  466. item.points.forEach(function (point) {
  467. if (point.series.visible !== false &&
  468. point.visible !== false) {
  469. hasVisiblePoints = true;
  470. }
  471. });
  472. if (!hasVisiblePoints) {
  473. label.hide();
  474. }
  475. else if (label.visibility === 'hidden') {
  476. label.show();
  477. }
  478. };
  479. /**
  480. * Destroy a single item.
  481. * @private
  482. * @param {Annotation.Label|Annotation.Shape} item
  483. */
  484. Annotation.prototype.destroyItem = function (item) {
  485. // erase from shapes or labels array
  486. erase(this[item.itemType + 's'], item);
  487. item.destroy();
  488. };
  489. /**
  490. * @private
  491. */
  492. Annotation.prototype.renderItem = function (item) {
  493. item.render(item.itemType === 'label' ?
  494. this.labelsGroup :
  495. this.shapesGroup);
  496. };
  497. /**
  498. * @private
  499. */
  500. Annotation.ControlPoint = ControlPoint;
  501. /**
  502. * @private
  503. */
  504. Annotation.MockPoint = MockPoint;
  505. /**
  506. * An object uses for mapping between a shape type and a constructor.
  507. * To add a new shape type extend this object with type name as a key
  508. * and a constructor as its value.
  509. */
  510. Annotation.shapesMap = {
  511. 'rect': ControllableRect,
  512. 'circle': ControllableCircle,
  513. 'path': ControllablePath,
  514. 'image': ControllableImage
  515. };
  516. /**
  517. * @private
  518. */
  519. Annotation.types = {};
  520. return Annotation;
  521. }());
  522. merge(true, Annotation.prototype, ControllableMixin, EventEmitterMixin,
  523. // restore original Annotation implementation after mixin overwrite
  524. merge(Annotation.prototype,
  525. /** @lends Highcharts.Annotation# */
  526. {
  527. /**
  528. * List of events for `annotation.options.events` that should not be
  529. * added to `annotation.graphic` but to the `annotation`.
  530. *
  531. * @private
  532. * @type {Array<string>}
  533. */
  534. nonDOMEvents: ['add', 'afterUpdate', 'drag', 'remove'],
  535. /**
  536. * A basic type of an annotation. It allows to add custom labels
  537. * or shapes. The items can be tied to points, axis coordinates
  538. * or chart pixel coordinates.
  539. *
  540. * @sample highcharts/annotations/basic/
  541. * Basic annotations
  542. * @sample highcharts/demo/annotations/
  543. * Advanced annotations
  544. * @sample highcharts/css/annotations
  545. * Styled mode
  546. * @sample highcharts/annotations-advanced/controllable
  547. * Controllable items
  548. * @sample {highstock} stock/annotations/fibonacci-retracements
  549. * Custom annotation, Fibonacci retracement
  550. *
  551. * @type {Array<*>}
  552. * @since 6.0.0
  553. * @requires modules/annotations
  554. * @optionparent annotations
  555. *
  556. * @private
  557. */
  558. defaultOptions: {
  559. /**
  560. * Sets an ID for an annotation. Can be user later when
  561. * removing an annotation in [Chart#removeAnnotation(id)](
  562. * /class-reference/Highcharts.Chart#removeAnnotation) method.
  563. *
  564. * @type {number|string}
  565. * @apioption annotations.id
  566. */
  567. /**
  568. * Whether the annotation is visible.
  569. *
  570. * @sample highcharts/annotations/visible/
  571. * Set annotation visibility
  572. */
  573. visible: true,
  574. /**
  575. * Allow an annotation to be draggable by a user. Possible
  576. * values are `'x'`, `'xy'`, `'y'` and `''` (disabled).
  577. *
  578. * @sample highcharts/annotations/draggable/
  579. * Annotations draggable: 'xy'
  580. *
  581. * @type {Highcharts.AnnotationDraggableValue}
  582. */
  583. draggable: 'xy',
  584. /**
  585. * Options for annotation's labels. Each label inherits options
  586. * from the labelOptions object. An option from the labelOptions
  587. * can be overwritten by config for a specific label.
  588. *
  589. * @requires modules/annotations
  590. */
  591. labelOptions: {
  592. /**
  593. * The alignment of the annotation's label. If right,
  594. * the right side of the label should be touching the point.
  595. *
  596. * @sample highcharts/annotations/label-position/
  597. * Set labels position
  598. *
  599. * @type {Highcharts.AlignValue}
  600. */
  601. align: 'center',
  602. /**
  603. * Whether to allow the annotation's labels to overlap.
  604. * To make the labels less sensitive for overlapping,
  605. * the can be set to 0.
  606. *
  607. * @sample highcharts/annotations/tooltip-like/
  608. * Hide overlapping labels
  609. */
  610. allowOverlap: false,
  611. /**
  612. * The background color or gradient for the annotation's
  613. * label.
  614. *
  615. * @sample highcharts/annotations/label-presentation/
  616. * Set labels graphic options
  617. *
  618. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  619. */
  620. backgroundColor: 'rgba(0, 0, 0, 0.75)',
  621. /**
  622. * The border color for the annotation's label.
  623. *
  624. * @sample highcharts/annotations/label-presentation/
  625. * Set labels graphic options
  626. *
  627. * @type {Highcharts.ColorString}
  628. */
  629. borderColor: 'black',
  630. /**
  631. * The border radius in pixels for the annotaiton's label.
  632. *
  633. * @sample highcharts/annotations/label-presentation/
  634. * Set labels graphic options
  635. */
  636. borderRadius: 3,
  637. /**
  638. * The border width in pixels for the annotation's label
  639. *
  640. * @sample highcharts/annotations/label-presentation/
  641. * Set labels graphic options
  642. */
  643. borderWidth: 1,
  644. /**
  645. * A class name for styling by CSS.
  646. *
  647. * @sample highcharts/css/annotations
  648. * Styled mode annotations
  649. *
  650. * @since 6.0.5
  651. */
  652. className: '',
  653. /**
  654. * Whether to hide the annotation's label
  655. * that is outside the plot area.
  656. *
  657. * @sample highcharts/annotations/label-crop-overflow/
  658. * Crop or justify labels
  659. */
  660. crop: false,
  661. /**
  662. * The label's pixel distance from the point.
  663. *
  664. * @sample highcharts/annotations/label-position/
  665. * Set labels position
  666. *
  667. * @type {number}
  668. * @apioption annotations.labelOptions.distance
  669. */
  670. /**
  671. * A
  672. * [format](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  673. * string for the data label.
  674. *
  675. * @see [plotOptions.series.dataLabels.format](plotOptions.series.dataLabels.format.html)
  676. *
  677. * @sample highcharts/annotations/label-text/
  678. * Set labels text
  679. *
  680. * @type {string}
  681. * @apioption annotations.labelOptions.format
  682. */
  683. /**
  684. * Alias for the format option.
  685. *
  686. * @see [format](annotations.labelOptions.format.html)
  687. *
  688. * @sample highcharts/annotations/label-text/
  689. * Set labels text
  690. *
  691. * @type {string}
  692. * @apioption annotations.labelOptions.text
  693. */
  694. /**
  695. * Callback JavaScript function to format the annotation's
  696. * label. Note that if a `format` or `text` are defined,
  697. * the format or text take precedence and the formatter is
  698. * ignored. `This` refers to a point object.
  699. *
  700. * @sample highcharts/annotations/label-text/
  701. * Set labels text
  702. *
  703. * @type {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
  704. * @default function () { return defined(this.y) ? this.y : 'Annotation label'; }
  705. */
  706. formatter: function () {
  707. return defined(this.y) ? this.y : 'Annotation label';
  708. },
  709. /**
  710. * How to handle the annotation's label that flow outside
  711. * the plot area. The justify option aligns the label inside
  712. * the plot area.
  713. *
  714. * @sample highcharts/annotations/label-crop-overflow/
  715. * Crop or justify labels
  716. *
  717. * @validvalue ["allow", "justify"]
  718. */
  719. overflow: 'justify',
  720. /**
  721. * When either the borderWidth or the backgroundColor is
  722. * set, this is the padding within the box.
  723. *
  724. * @sample highcharts/annotations/label-presentation/
  725. * Set labels graphic options
  726. */
  727. padding: 5,
  728. /**
  729. * The shadow of the box. The shadow can be an object
  730. * configuration containing `color`, `offsetX`, `offsetY`,
  731. * `opacity` and `width`.
  732. *
  733. * @sample highcharts/annotations/label-presentation/
  734. * Set labels graphic options
  735. *
  736. * @type {boolean|Highcharts.ShadowOptionsObject}
  737. */
  738. shadow: false,
  739. /**
  740. * The name of a symbol to use for the border around the
  741. * label. Symbols are predefined functions on the Renderer
  742. * object.
  743. *
  744. * @sample highcharts/annotations/shapes/
  745. * Available shapes for labels
  746. */
  747. shape: 'callout',
  748. /**
  749. * Styles for the annotation's label.
  750. *
  751. * @see [plotOptions.series.dataLabels.style](plotOptions.series.dataLabels.style.html)
  752. *
  753. * @sample highcharts/annotations/label-presentation/
  754. * Set labels graphic options
  755. *
  756. * @type {Highcharts.CSSObject}
  757. */
  758. style: {
  759. /** @ignore */
  760. fontSize: '11px',
  761. /** @ignore */
  762. fontWeight: 'normal',
  763. /** @ignore */
  764. color: 'contrast'
  765. },
  766. /**
  767. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  768. * to render the annotation's label.
  769. */
  770. useHTML: false,
  771. /**
  772. * The vertical alignment of the annotation's label.
  773. *
  774. * @sample highcharts/annotations/label-position/
  775. * Set labels position
  776. *
  777. * @type {Highcharts.VerticalAlignValue}
  778. */
  779. verticalAlign: 'bottom',
  780. /**
  781. * The x position offset of the label relative to the point.
  782. * Note that if a `distance` is defined, the distance takes
  783. * precedence over `x` and `y` options.
  784. *
  785. * @sample highcharts/annotations/label-position/
  786. * Set labels position
  787. */
  788. x: 0,
  789. /**
  790. * The y position offset of the label relative to the point.
  791. * Note that if a `distance` is defined, the distance takes
  792. * precedence over `x` and `y` options.
  793. *
  794. * @sample highcharts/annotations/label-position/
  795. * Set labels position
  796. */
  797. y: -16
  798. },
  799. /**
  800. * An array of labels for the annotation. For options that apply
  801. * to multiple labels, they can be added to the
  802. * [labelOptions](annotations.labelOptions.html).
  803. *
  804. * @type {Array<*>}
  805. * @extends annotations.labelOptions
  806. * @apioption annotations.labels
  807. */
  808. /**
  809. * This option defines the point to which the label will be
  810. * connected. It can be either the point which exists in the
  811. * series - it is referenced by the point's id - or a new point
  812. * with defined x, y properties and optionally axes.
  813. *
  814. * @sample highcharts/annotations/mock-point/
  815. * Attach annotation to a mock point
  816. *
  817. * @declare Highcharts.AnnotationMockPointOptionsObject
  818. * @type {string|*}
  819. * @requires modules/annotations
  820. * @apioption annotations.labels.point
  821. */
  822. /**
  823. * The x position of the point. Units can be either in axis
  824. * or chart pixel coordinates.
  825. *
  826. * @type {number}
  827. * @apioption annotations.labels.point.x
  828. */
  829. /**
  830. * The y position of the point. Units can be either in axis
  831. * or chart pixel coordinates.
  832. *
  833. * @type {number}
  834. * @apioption annotations.labels.point.y
  835. */
  836. /**
  837. * This number defines which xAxis the point is connected to.
  838. * It refers to either the axis id or the index of the axis in
  839. * the xAxis array. If the option is not configured or the axis
  840. * is not found the point's x coordinate refers to the chart
  841. * pixels.
  842. *
  843. * @type {number|string|null}
  844. * @apioption annotations.labels.point.xAxis
  845. */
  846. /**
  847. * This number defines which yAxis the point is connected to.
  848. * It refers to either the axis id or the index of the axis in
  849. * the yAxis array. If the option is not configured or the axis
  850. * is not found the point's y coordinate refers to the chart
  851. * pixels.
  852. *
  853. * @type {number|string|null}
  854. * @apioption annotations.labels.point.yAxis
  855. */
  856. /**
  857. * An array of shapes for the annotation. For options that apply
  858. * to multiple shapes, then can be added to the
  859. * [shapeOptions](annotations.shapeOptions.html).
  860. *
  861. * @type {Array<*>}
  862. * @extends annotations.shapeOptions
  863. * @apioption annotations.shapes
  864. */
  865. /**
  866. * This option defines the point to which the shape will be
  867. * connected. It can be either the point which exists in the
  868. * series - it is referenced by the point's id - or a new point
  869. * with defined x, y properties and optionally axes.
  870. *
  871. * @declare Highcharts.AnnotationMockPointOptionsObject
  872. * @type {string|Highcharts.AnnotationMockPointOptionsObject}
  873. * @extends annotations.labels.point
  874. * @apioption annotations.shapes.point
  875. */
  876. /**
  877. * An array of points for the shape. This option is available
  878. * for shapes which can use multiple points such as path. A
  879. * point can be either a point object or a point's id.
  880. *
  881. * @see [annotations.shapes.point](annotations.shapes.point.html)
  882. *
  883. * @declare Highcharts.AnnotationMockPointOptionsObject
  884. * @type {Array<string|*>}
  885. * @extends annotations.labels.point
  886. * @apioption annotations.shapes.points
  887. */
  888. /**
  889. * The URL for an image to use as the annotation shape. Note,
  890. * type has to be set to `'image'`.
  891. *
  892. * @see [annotations.shapes.type](annotations.shapes.type)
  893. * @sample highcharts/annotations/shape-src/
  894. * Define a marker image url for annotations
  895. *
  896. * @type {string}
  897. * @apioption annotations.shapes.src
  898. */
  899. /**
  900. * Id of the marker which will be drawn at the final vertex of
  901. * the path. Custom markers can be defined in defs property.
  902. *
  903. * @see [defs.markers](defs.markers.html)
  904. *
  905. * @sample highcharts/annotations/custom-markers/
  906. * Define a custom marker for annotations
  907. *
  908. * @type {string}
  909. * @apioption annotations.shapes.markerEnd
  910. */
  911. /**
  912. * Id of the marker which will be drawn at the first vertex of
  913. * the path. Custom markers can be defined in defs property.
  914. *
  915. * @see [defs.markers](defs.markers.html)
  916. *
  917. * @sample {highcharts} highcharts/annotations/custom-markers/
  918. * Define a custom marker for annotations
  919. *
  920. * @type {string}
  921. * @apioption annotations.shapes.markerStart
  922. */
  923. /**
  924. * Options for annotation's shapes. Each shape inherits options
  925. * from the shapeOptions object. An option from the shapeOptions
  926. * can be overwritten by config for a specific shape.
  927. *
  928. * @requires modules/annotations
  929. */
  930. shapeOptions: {
  931. /**
  932. * The width of the shape.
  933. *
  934. * @sample highcharts/annotations/shape/
  935. * Basic shape annotation
  936. *
  937. * @type {number}
  938. * @apioption annotations.shapeOptions.width
  939. **/
  940. /**
  941. * The height of the shape.
  942. *
  943. * @sample highcharts/annotations/shape/
  944. * Basic shape annotation
  945. *
  946. * @type {number}
  947. * @apioption annotations.shapeOptions.height
  948. */
  949. /**
  950. * The type of the shape, e.g. circle or rectangle.
  951. *
  952. * @sample highcharts/annotations/shape/
  953. * Basic shape annotation
  954. *
  955. * @type {string}
  956. * @default 'rect'
  957. * @apioption annotations.shapeOptions.type
  958. */
  959. /**
  960. * The URL for an image to use as the annotation shape.
  961. * Note, type has to be set to `'image'`.
  962. *
  963. * @see [annotations.shapeOptions.type](annotations.shapeOptions.type)
  964. * @sample highcharts/annotations/shape-src/
  965. * Define a marker image url for annotations
  966. *
  967. * @type {string}
  968. * @apioption annotations.shapeOptions.src
  969. */
  970. /**
  971. * Name of the dash style to use for the shape's stroke.
  972. *
  973. * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
  974. * Possible values demonstrated
  975. *
  976. * @type {Highcharts.DashStyleValue}
  977. * @apioption annotations.shapeOptions.dashStyle
  978. */
  979. /**
  980. * The color of the shape's stroke.
  981. *
  982. * @sample highcharts/annotations/shape/
  983. * Basic shape annotation
  984. *
  985. * @type {Highcharts.ColorString}
  986. */
  987. stroke: 'rgba(0, 0, 0, 0.75)',
  988. /**
  989. * The pixel stroke width of the shape.
  990. *
  991. * @sample highcharts/annotations/shape/
  992. * Basic shape annotation
  993. */
  994. strokeWidth: 1,
  995. /**
  996. * The color of the shape's fill.
  997. *
  998. * @sample highcharts/annotations/shape/
  999. * Basic shape annotation
  1000. *
  1001. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  1002. */
  1003. fill: 'rgba(0, 0, 0, 0.75)',
  1004. /**
  1005. * The radius of the shape.
  1006. *
  1007. * @sample highcharts/annotations/shape/
  1008. * Basic shape annotation
  1009. */
  1010. r: 0,
  1011. /**
  1012. * Defines additional snapping area around an annotation
  1013. * making this annotation to focus. Defined in pixels.
  1014. */
  1015. snap: 2
  1016. },
  1017. /**
  1018. * Options for annotation's control points. Each control point
  1019. * inherits options from controlPointOptions object.
  1020. * Options from the controlPointOptions can be overwritten
  1021. * by options in a specific control point.
  1022. *
  1023. * @declare Highcharts.AnnotationControlPointOptionsObject
  1024. * @requires modules/annotations
  1025. * @apioption annotations.controlPointOptions
  1026. */
  1027. controlPointOptions: {
  1028. /**
  1029. * @type {Highcharts.AnnotationControlPointPositionerFunction}
  1030. * @apioption annotations.controlPointOptions.positioner
  1031. */
  1032. symbol: 'circle',
  1033. width: 10,
  1034. height: 10,
  1035. style: {
  1036. stroke: 'black',
  1037. 'stroke-width': 2,
  1038. fill: 'white'
  1039. },
  1040. visible: false,
  1041. events: {}
  1042. },
  1043. /**
  1044. * Event callback when annotation is added to the chart.
  1045. *
  1046. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  1047. * @since 7.1.0
  1048. * @apioption annotations.events.add
  1049. */
  1050. /**
  1051. * Event callback when annotation is updated (e.g. drag and
  1052. * droppped or resized by control points).
  1053. *
  1054. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  1055. * @since 7.1.0
  1056. * @apioption annotations.events.afterUpdate
  1057. */
  1058. /**
  1059. * Event callback when annotation is removed from the chart.
  1060. *
  1061. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  1062. * @since 7.1.0
  1063. * @apioption annotations.events.remove
  1064. */
  1065. /**
  1066. * Events available in annotations.
  1067. *
  1068. * @requires modules/annotations
  1069. */
  1070. events: {},
  1071. /**
  1072. * The Z index of the annotation.
  1073. */
  1074. zIndex: 6
  1075. }
  1076. }));
  1077. H.extendAnnotation = function (Constructor, BaseConstructor, prototype, defaultOptions) {
  1078. BaseConstructor = BaseConstructor || Annotation;
  1079. merge(true, Constructor.prototype, BaseConstructor.prototype, prototype);
  1080. Constructor.prototype.defaultOptions = merge(Constructor.prototype.defaultOptions, defaultOptions || {});
  1081. };
  1082. /* *********************************************************************
  1083. *
  1084. * EXTENDING CHART PROTOTYPE
  1085. *
  1086. ******************************************************************** */
  1087. extend(chartProto, /** @lends Highcharts.Chart# */ {
  1088. initAnnotation: function (userOptions) {
  1089. var Constructor = Annotation.types[userOptions.type] || Annotation, annotation = new Constructor(this, userOptions);
  1090. this.annotations.push(annotation);
  1091. return annotation;
  1092. },
  1093. /**
  1094. * Add an annotation to the chart after render time.
  1095. *
  1096. * @param {Highcharts.AnnotationsOptions} options
  1097. * The annotation options for the new, detailed annotation.
  1098. * @param {boolean} [redraw]
  1099. *
  1100. * @return {Highcharts.Annotation} - The newly generated annotation.
  1101. */
  1102. addAnnotation: function (userOptions, redraw) {
  1103. var annotation = this.initAnnotation(userOptions);
  1104. this.options.annotations.push(annotation.options);
  1105. if (pick(redraw, true)) {
  1106. annotation.redraw();
  1107. }
  1108. return annotation;
  1109. },
  1110. /**
  1111. * Remove an annotation from the chart.
  1112. *
  1113. * @param {number|string|Highcharts.Annotation} idOrAnnotation
  1114. * The annotation's id or direct annotation object.
  1115. */
  1116. removeAnnotation: function (idOrAnnotation) {
  1117. var annotations = this.annotations, annotation = idOrAnnotation.coll === 'annotations' ?
  1118. idOrAnnotation :
  1119. find(annotations, function (annotation) {
  1120. return annotation.options.id === idOrAnnotation;
  1121. });
  1122. if (annotation) {
  1123. fireEvent(annotation, 'remove');
  1124. erase(this.options.annotations, annotation.options);
  1125. erase(annotations, annotation);
  1126. annotation.destroy();
  1127. }
  1128. },
  1129. drawAnnotations: function () {
  1130. this.plotBoxClip.attr(this.plotBox);
  1131. this.annotations.forEach(function (annotation) {
  1132. annotation.redraw();
  1133. });
  1134. }
  1135. });
  1136. // Let chart.update() update annotations
  1137. chartProto.collectionsWithUpdate.push('annotations');
  1138. // Let chart.update() create annoations on demand
  1139. chartProto.collectionsWithInit.annotations = [chartProto.addAnnotation];
  1140. chartProto.callbacks.push(function (chart) {
  1141. chart.annotations = [];
  1142. if (!chart.options.annotations) {
  1143. chart.options.annotations = [];
  1144. }
  1145. chart.plotBoxClip = this.renderer.clipRect(this.plotBox);
  1146. chart.controlPointsGroup = chart.renderer
  1147. .g('control-points')
  1148. .attr({ zIndex: 99 })
  1149. .clip(chart.plotBoxClip)
  1150. .add();
  1151. chart.options.annotations.forEach(function (annotationOptions, i) {
  1152. var annotation = chart.initAnnotation(annotationOptions);
  1153. chart.options.annotations[i] = annotation.options;
  1154. });
  1155. chart.drawAnnotations();
  1156. addEvent(chart, 'redraw', chart.drawAnnotations);
  1157. addEvent(chart, 'destroy', function () {
  1158. chart.plotBoxClip.destroy();
  1159. chart.controlPointsGroup.destroy();
  1160. });
  1161. });
  1162. wrap(Pointer.prototype, 'onContainerMouseDown', function (proceed) {
  1163. if (!this.chart.hasDraggedAnnotation) {
  1164. proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  1165. }
  1166. });
  1167. H.Annotation = Annotation;
  1168. export default Annotation;