stock-tools-bindings.js 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749
  1. /**
  2. *
  3. * Events generator for Stock tools
  4. *
  5. * (c) 2009-2019 Paweł Fus
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10. *
  11. * */
  12. 'use strict';
  13. import H from '../parts/Globals.js';
  14. /**
  15. * A config object for bindings in Stock Tools module.
  16. *
  17. * @interface Highcharts.StockToolsBindingsObject
  18. */ /**
  19. * ClassName of the element for a binding.
  20. * @name Highcharts.StockToolsBindingsObject#className
  21. * @type {string|undefined}
  22. */ /**
  23. * Last event to be fired after last step event.
  24. * @name Highcharts.StockToolsBindingsObject#end
  25. * @type {Function|undefined}
  26. */ /**
  27. * Initial event, fired on a button click.
  28. * @name Highcharts.StockToolsBindingsObject#init
  29. * @type {Function|undefined}
  30. */ /**
  31. * Event fired on first click on a chart.
  32. * @name Highcharts.StockToolsBindingsObject#start
  33. * @type {Function|undefined}
  34. */ /**
  35. * Last event to be fired after last step event. Array of step events to be
  36. * called sequentially after each user click.
  37. * @name Highcharts.StockToolsBindingsObject#steps
  38. * @type {Array<Function>|undefined}
  39. */
  40. import U from '../parts/Utilities.js';
  41. var correctFloat = U.correctFloat, defined = U.defined, extend = U.extend, isNumber = U.isNumber, pick = U.pick;
  42. var fireEvent = H.fireEvent, merge = H.merge, bindingsUtils = H.NavigationBindings.prototype.utils, PREFIX = 'highcharts-';
  43. /* eslint-disable no-invalid-this */
  44. /**
  45. * Generates function which will add a flag series using modal in GUI.
  46. * Method fires an event "showPopup" with config:
  47. * `{type, options, callback}`.
  48. *
  49. * Example: NavigationBindings.utils.addFlagFromForm('url(...)') - will
  50. * generate function that shows modal in GUI.
  51. *
  52. * @private
  53. * @function bindingsUtils.addFlagFromForm
  54. *
  55. * @param {string} type
  56. * Type of flag series, e.g. "squarepin"
  57. *
  58. * @return {Function}
  59. * Callback to be used in `start` callback
  60. */
  61. bindingsUtils.addFlagFromForm = function (type) {
  62. return function (e) {
  63. var navigation = this, chart = navigation.chart, toolbar = chart.stockTools, getFieldType = bindingsUtils.getFieldType, point = bindingsUtils.attractToPoint(e, chart), pointConfig = {
  64. x: point.x,
  65. y: point.y
  66. }, seriesOptions = {
  67. type: 'flags',
  68. onSeries: point.series.id,
  69. shape: type,
  70. data: [pointConfig],
  71. point: {
  72. events: {
  73. click: function () {
  74. var point = this, options = point.options;
  75. fireEvent(navigation, 'showPopup', {
  76. point: point,
  77. formType: 'annotation-toolbar',
  78. options: {
  79. langKey: 'flags',
  80. type: 'flags',
  81. title: [
  82. options.title,
  83. getFieldType(options.title)
  84. ],
  85. name: [
  86. options.name,
  87. getFieldType(options.name)
  88. ]
  89. },
  90. onSubmit: function (updated) {
  91. if (updated.actionType === 'remove') {
  92. point.remove();
  93. }
  94. else {
  95. point.update(navigation.fieldsToOptions(updated.fields, {}));
  96. }
  97. }
  98. });
  99. }
  100. }
  101. }
  102. };
  103. if (!toolbar || !toolbar.guiEnabled) {
  104. chart.addSeries(seriesOptions);
  105. }
  106. fireEvent(navigation, 'showPopup', {
  107. formType: 'flag',
  108. // Enabled options:
  109. options: {
  110. langKey: 'flags',
  111. type: 'flags',
  112. title: ['A', getFieldType('A')],
  113. name: ['Flag A', getFieldType('Flag A')]
  114. },
  115. // Callback on submit:
  116. onSubmit: function (data) {
  117. navigation.fieldsToOptions(data.fields, seriesOptions.data[0]);
  118. chart.addSeries(seriesOptions);
  119. }
  120. });
  121. };
  122. };
  123. bindingsUtils.manageIndicators = function (data) {
  124. var navigation = this, chart = navigation.chart, seriesConfig = {
  125. linkedTo: data.linkedTo,
  126. type: data.type
  127. }, indicatorsWithVolume = [
  128. 'ad',
  129. 'cmf',
  130. 'mfi',
  131. 'vbp',
  132. 'vwap'
  133. ], indicatorsWithAxes = [
  134. 'ad',
  135. 'atr',
  136. 'cci',
  137. 'cmf',
  138. 'macd',
  139. 'mfi',
  140. 'roc',
  141. 'rsi',
  142. 'ao',
  143. 'aroon',
  144. 'aroonoscillator',
  145. 'trix',
  146. 'apo',
  147. 'dpo',
  148. 'ppo',
  149. 'natr',
  150. 'williamsr',
  151. 'stochastic',
  152. 'slowstochastic',
  153. 'linearRegression',
  154. 'linearRegressionSlope',
  155. 'linearRegressionIntercept',
  156. 'linearRegressionAngle'
  157. ], yAxis, series;
  158. if (data.actionType === 'edit') {
  159. navigation.fieldsToOptions(data.fields, seriesConfig);
  160. series = chart.get(data.seriesId);
  161. if (series) {
  162. series.update(seriesConfig, false);
  163. }
  164. }
  165. else if (data.actionType === 'remove') {
  166. series = chart.get(data.seriesId);
  167. if (series) {
  168. yAxis = series.yAxis;
  169. if (series.linkedSeries) {
  170. series.linkedSeries.forEach(function (linkedSeries) {
  171. linkedSeries.remove(false);
  172. });
  173. }
  174. series.remove(false);
  175. if (indicatorsWithAxes.indexOf(series.type) >= 0) {
  176. yAxis.remove(false);
  177. navigation.resizeYAxes();
  178. }
  179. }
  180. }
  181. else {
  182. seriesConfig.id = H.uniqueKey();
  183. navigation.fieldsToOptions(data.fields, seriesConfig);
  184. if (indicatorsWithAxes.indexOf(data.type) >= 0) {
  185. yAxis = chart.addAxis({
  186. id: H.uniqueKey(),
  187. offset: 0,
  188. opposite: true,
  189. title: {
  190. text: ''
  191. },
  192. tickPixelInterval: 40,
  193. showLastLabel: false,
  194. labels: {
  195. align: 'left',
  196. y: -2
  197. }
  198. }, false, false);
  199. seriesConfig.yAxis = yAxis.options.id;
  200. navigation.resizeYAxes();
  201. }
  202. else {
  203. seriesConfig.yAxis = chart.get(data.linkedTo).options.yAxis;
  204. }
  205. if (indicatorsWithVolume.indexOf(data.type) >= 0) {
  206. seriesConfig.params.volumeSeriesID = chart.series.filter(function (series) {
  207. return series.options.type === 'column';
  208. })[0].options.id;
  209. }
  210. chart.addSeries(seriesConfig, false);
  211. }
  212. fireEvent(navigation, 'deselectButton', {
  213. button: navigation.selectedButtonElement
  214. });
  215. chart.redraw();
  216. };
  217. /**
  218. * Update height for an annotation. Height is calculated as a difference
  219. * between last point in `typeOptions` and current position. It's a value,
  220. * not pixels height.
  221. *
  222. * @private
  223. * @function bindingsUtils.updateHeight
  224. *
  225. * @param {global.Event} e
  226. * normalized browser event
  227. *
  228. * @param {Highcharts.Annotation} annotation
  229. * Annotation to be updated
  230. *
  231. * @return {void}
  232. */
  233. bindingsUtils.updateHeight = function (e, annotation) {
  234. annotation.update({
  235. typeOptions: {
  236. height: this.chart.pointer.getCoordinates(e).yAxis[0].value -
  237. annotation.options.typeOptions.points[1].y
  238. }
  239. });
  240. };
  241. // @todo
  242. // Consider using getHoverData(), but always kdTree (columns?)
  243. bindingsUtils.attractToPoint = function (e, chart) {
  244. var coords = chart.pointer.getCoordinates(e), x = coords.xAxis[0].value, y = coords.yAxis[0].value, distX = Number.MAX_VALUE, closestPoint;
  245. chart.series.forEach(function (series) {
  246. series.points.forEach(function (point) {
  247. if (point && distX > Math.abs(point.x - x)) {
  248. distX = Math.abs(point.x - x);
  249. closestPoint = point;
  250. }
  251. });
  252. });
  253. return {
  254. x: closestPoint.x,
  255. y: closestPoint.y,
  256. below: y < closestPoint.y,
  257. series: closestPoint.series,
  258. xAxis: closestPoint.series.xAxis.index || 0,
  259. yAxis: closestPoint.series.yAxis.index || 0
  260. };
  261. };
  262. /**
  263. * Shorthand to check if given yAxis comes from navigator.
  264. *
  265. * @private
  266. * @function bindingsUtils.isNotNavigatorYAxis
  267. *
  268. * @param {Highcharts.Axis} axis
  269. * Axis to check.
  270. *
  271. * @return {boolean}
  272. * True, if axis comes from navigator.
  273. */
  274. bindingsUtils.isNotNavigatorYAxis = function (axis) {
  275. return axis.userOptions.className !== PREFIX + 'navigator-yaxis';
  276. };
  277. /**
  278. * Update each point after specified index, most of the annotations use
  279. * this. For example crooked line: logic behind updating each point is the
  280. * same, only index changes when adding an annotation.
  281. *
  282. * Example: NavigationBindings.utils.updateNthPoint(1) - will generate
  283. * function that updates all consecutive points except point with index=0.
  284. *
  285. * @private
  286. * @function bindingsUtils.updateNthPoint
  287. *
  288. * @param {number} startIndex
  289. * Index from each point should udpated
  290. *
  291. * @return {Function}
  292. * Callback to be used in steps array
  293. */
  294. bindingsUtils.updateNthPoint = function (startIndex) {
  295. return function (e, annotation) {
  296. var options = annotation.options.typeOptions, coords = this.chart.pointer.getCoordinates(e), x = coords.xAxis[0].value, y = coords.yAxis[0].value;
  297. options.points.forEach(function (point, index) {
  298. if (index >= startIndex) {
  299. point.x = x;
  300. point.y = y;
  301. }
  302. });
  303. annotation.update({
  304. typeOptions: {
  305. points: options.points
  306. }
  307. });
  308. };
  309. };
  310. // Extends NavigationBindigs to support indicators and resizers:
  311. extend(H.NavigationBindings.prototype, {
  312. /* eslint-disable valid-jsdoc */
  313. /**
  314. * Get current positions for all yAxes. If new axis does not have position,
  315. * returned is default height and last available top place.
  316. *
  317. * @private
  318. * @function Highcharts.NavigationBindings#getYAxisPositions
  319. *
  320. * @param {Array<Highcharts.Axis>} yAxes
  321. * Array of yAxes available in the chart.
  322. *
  323. * @param {number} plotHeight
  324. * Available height in the chart.
  325. *
  326. * @param {number} defaultHeight
  327. * Default height in percents.
  328. *
  329. * @return {Array}
  330. * An array of calculated positions in percentages.
  331. * Format: `{top: Number, height: Number}`
  332. */
  333. getYAxisPositions: function (yAxes, plotHeight, defaultHeight) {
  334. var positions, allAxesHeight = 0;
  335. /** @private */
  336. function isPercentage(prop) {
  337. return defined(prop) && !isNumber(prop) && prop.match('%');
  338. }
  339. positions = yAxes.map(function (yAxis) {
  340. var height = isPercentage(yAxis.options.height) ?
  341. parseFloat(yAxis.options.height) / 100 :
  342. yAxis.height / plotHeight, top = isPercentage(yAxis.options.top) ?
  343. parseFloat(yAxis.options.top) / 100 :
  344. correctFloat(yAxis.top - yAxis.chart.plotTop) / plotHeight;
  345. // New yAxis does not contain "height" info yet
  346. if (!isNumber(height)) {
  347. height = defaultHeight / 100;
  348. }
  349. allAxesHeight = correctFloat(allAxesHeight + height);
  350. return {
  351. height: height * 100,
  352. top: top * 100
  353. };
  354. });
  355. positions.allAxesHeight = allAxesHeight;
  356. return positions;
  357. },
  358. /**
  359. * Get current resize options for each yAxis. Note that each resize is
  360. * linked to the next axis, except the last one which shouldn't affect
  361. * axes in the navigator. Because indicator can be removed with it's yAxis
  362. * in the middle of yAxis array, we need to bind closest yAxes back.
  363. *
  364. * @private
  365. * @function Highcharts.NavigationBindings#getYAxisResizers
  366. *
  367. * @param {Array<Highcharts.Axis>} yAxes
  368. * Array of yAxes available in the chart
  369. *
  370. * @return {Array<object>}
  371. * An array of resizer options.
  372. * Format: `{enabled: Boolean, controlledAxis: { next: [String]}}`
  373. */
  374. getYAxisResizers: function (yAxes) {
  375. var resizers = [];
  376. yAxes.forEach(function (yAxis, index) {
  377. var nextYAxis = yAxes[index + 1];
  378. // We have next axis, bind them:
  379. if (nextYAxis) {
  380. resizers[index] = {
  381. enabled: true,
  382. controlledAxis: {
  383. next: [
  384. pick(nextYAxis.options.id, nextYAxis.options.index)
  385. ]
  386. }
  387. };
  388. }
  389. else {
  390. // Remove binding:
  391. resizers[index] = {
  392. enabled: false
  393. };
  394. }
  395. });
  396. return resizers;
  397. },
  398. /**
  399. * Resize all yAxes (except navigator) to fit the plotting height. Method
  400. * checks if new axis is added, then shrinks other main axis up to 5 panes.
  401. * If added is more thatn 5 panes, it rescales all other axes to fit new
  402. * yAxis.
  403. *
  404. * If axis is removed, and we have more than 5 panes, rescales all other
  405. * axes. If chart has less than 5 panes, first pane receives all extra
  406. * space.
  407. *
  408. * @private
  409. * @function Highcharts.NavigationBindings#resizeYAxes
  410. * @param {number} defaultHeight
  411. * Default height for yAxis
  412. * @return {void}
  413. */
  414. resizeYAxes: function (defaultHeight) {
  415. defaultHeight = defaultHeight || 20; // in %, but as a number
  416. var chart = this.chart,
  417. // Only non-navigator axes
  418. yAxes = chart.yAxis.filter(this.utils.isNotNavigatorYAxis), plotHeight = chart.plotHeight, allAxesLength = yAxes.length,
  419. // Gather current heights (in %)
  420. positions = this.getYAxisPositions(yAxes, plotHeight, defaultHeight), resizers = this.getYAxisResizers(yAxes), allAxesHeight = positions.allAxesHeight, changedSpace = defaultHeight;
  421. // More than 100%
  422. if (allAxesHeight > 1) {
  423. // Simple case, add new panes up to 5
  424. if (allAxesLength < 6) {
  425. // Added axis, decrease first pane's height:
  426. positions[0].height = correctFloat(positions[0].height - changedSpace);
  427. // And update all other "top" positions:
  428. positions = this.recalculateYAxisPositions(positions, changedSpace);
  429. }
  430. else {
  431. // We have more panes, rescale all others to gain some space,
  432. // This is new height for upcoming yAxis:
  433. defaultHeight = 100 / allAxesLength;
  434. // This is how much we need to take from each other yAxis:
  435. changedSpace = defaultHeight / (allAxesLength - 1);
  436. // Now update all positions:
  437. positions = this.recalculateYAxisPositions(positions, changedSpace, true, -1);
  438. }
  439. // Set last position manually:
  440. positions[allAxesLength - 1] = {
  441. top: correctFloat(100 - defaultHeight),
  442. height: defaultHeight
  443. };
  444. }
  445. else {
  446. // Less than 100%
  447. changedSpace = correctFloat(1 - allAxesHeight) * 100;
  448. // Simple case, return first pane it's space:
  449. if (allAxesLength < 5) {
  450. positions[0].height = correctFloat(positions[0].height + changedSpace);
  451. positions = this.recalculateYAxisPositions(positions, changedSpace);
  452. }
  453. else {
  454. // There were more panes, return to each pane a bit of space:
  455. changedSpace /= allAxesLength;
  456. // Removed axis, add extra space to the first pane:
  457. // And update all other positions:
  458. positions = this.recalculateYAxisPositions(positions, changedSpace, true, 1);
  459. }
  460. }
  461. positions.forEach(function (position, index) {
  462. // if (index === 0) debugger;
  463. yAxes[index].update({
  464. height: position.height + '%',
  465. top: position.top + '%',
  466. resize: resizers[index]
  467. }, false);
  468. });
  469. },
  470. /**
  471. * Utility to modify calculated positions according to the remaining/needed
  472. * space. Later, these positions are used in `yAxis.update({ top, height })`
  473. *
  474. * @private
  475. * @function Highcharts.NavigationBindings#recalculateYAxisPositions
  476. * @param {Array<Highcharts.Dictionary<number>>} positions
  477. * Default positions of all yAxes.
  478. * @param {number} changedSpace
  479. * How much space should be added or removed.
  480. * @param {boolean} modifyHeight
  481. * Update only `top` or both `top` and `height`.
  482. * @param {number} adder
  483. * `-1` or `1`, to determine whether we should add or remove space.
  484. *
  485. * @return {Array<object>}
  486. * Modified positions,
  487. */
  488. recalculateYAxisPositions: function (positions, changedSpace, modifyHeight, adder) {
  489. positions.forEach(function (position, index) {
  490. var prevPosition = positions[index - 1];
  491. position.top = !prevPosition ? 0 :
  492. correctFloat(prevPosition.height + prevPosition.top);
  493. if (modifyHeight) {
  494. position.height = correctFloat(position.height + adder * changedSpace);
  495. }
  496. });
  497. return positions;
  498. }
  499. /* eslint-enable valid-jsdoc */
  500. });
  501. /**
  502. * @type {Highcharts.Dictionary<Highcharts.StockToolsBindingsObject>|*}
  503. * @since 7.0.0
  504. * @optionparent navigation.bindings
  505. */
  506. var stockToolsBindings = {
  507. // Line type annotations:
  508. /**
  509. * A segment annotation bindings. Includes `start` and one event in `steps`
  510. * array.
  511. *
  512. * @type {Highcharts.StockToolsBindingsObject}
  513. * @product highstock
  514. * @default {"className": "highcharts-segment", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  515. */
  516. segment: {
  517. /** @ignore*/
  518. className: 'highcharts-segment',
  519. // eslint-disable-next-line valid-jsdoc
  520. /** @ignore*/
  521. start: function (e) {
  522. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  523. langKey: 'segment',
  524. type: 'crookedLine',
  525. typeOptions: {
  526. points: [{
  527. x: coords.xAxis[0].value,
  528. y: coords.yAxis[0].value
  529. }, {
  530. x: coords.xAxis[0].value,
  531. y: coords.yAxis[0].value
  532. }]
  533. }
  534. }, navigation.annotationsOptions, navigation.bindings.segment.annotationsOptions);
  535. return this.chart.addAnnotation(options);
  536. },
  537. /** @ignore*/
  538. steps: [
  539. bindingsUtils.updateNthPoint(1)
  540. ]
  541. },
  542. /**
  543. * A segment with an arrow annotation bindings. Includes `start` and one
  544. * event in `steps` array.
  545. *
  546. * @type {Highcharts.StockToolsBindingsObject}
  547. * @product highstock
  548. * @default {"className": "highcharts-arrow-segment", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  549. */
  550. arrowSegment: {
  551. /** @ignore*/
  552. className: 'highcharts-arrow-segment',
  553. // eslint-disable-next-line valid-jsdoc
  554. /** @ignore*/
  555. start: function (e) {
  556. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  557. langKey: 'arrowSegment',
  558. type: 'crookedLine',
  559. typeOptions: {
  560. line: {
  561. markerEnd: 'arrow'
  562. },
  563. points: [{
  564. x: coords.xAxis[0].value,
  565. y: coords.yAxis[0].value
  566. }, {
  567. x: coords.xAxis[0].value,
  568. y: coords.yAxis[0].value
  569. }]
  570. }
  571. }, navigation.annotationsOptions, navigation.bindings.arrowSegment.annotationsOptions);
  572. return this.chart.addAnnotation(options);
  573. },
  574. /** @ignore*/
  575. steps: [
  576. bindingsUtils.updateNthPoint(1)
  577. ]
  578. },
  579. /**
  580. * A ray annotation bindings. Includes `start` and one event in `steps`
  581. * array.
  582. *
  583. * @type {Highcharts.StockToolsBindingsObject}
  584. * @product highstock
  585. * @default {"className": "highcharts-ray", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  586. */
  587. ray: {
  588. /** @ignore*/
  589. className: 'highcharts-ray',
  590. // eslint-disable-next-line valid-jsdoc
  591. /** @ignore*/
  592. start: function (e) {
  593. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  594. langKey: 'ray',
  595. type: 'crookedLine',
  596. typeOptions: {
  597. type: 'ray',
  598. points: [{
  599. x: coords.xAxis[0].value,
  600. y: coords.yAxis[0].value
  601. }, {
  602. x: coords.xAxis[0].value,
  603. y: coords.yAxis[0].value
  604. }]
  605. }
  606. }, navigation.annotationsOptions, navigation.bindings.ray.annotationsOptions);
  607. return this.chart.addAnnotation(options);
  608. },
  609. /** @ignore*/
  610. steps: [
  611. bindingsUtils.updateNthPoint(1)
  612. ]
  613. },
  614. /**
  615. * A ray with an arrow annotation bindings. Includes `start` and one event
  616. * in `steps` array.
  617. *
  618. * @type {Highcharts.StockToolsBindingsObject}
  619. * @product highstock
  620. * @default {"className": "highcharts-arrow-ray", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  621. */
  622. arrowRay: {
  623. /** @ignore*/
  624. className: 'highcharts-arrow-ray',
  625. // eslint-disable-next-line valid-jsdoc
  626. /** @ignore*/
  627. start: function (e) {
  628. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  629. langKey: 'arrowRay',
  630. type: 'infinityLine',
  631. typeOptions: {
  632. type: 'ray',
  633. line: {
  634. markerEnd: 'arrow'
  635. },
  636. points: [{
  637. x: coords.xAxis[0].value,
  638. y: coords.yAxis[0].value
  639. }, {
  640. x: coords.xAxis[0].value,
  641. y: coords.yAxis[0].value
  642. }]
  643. }
  644. }, navigation.annotationsOptions, navigation.bindings.arrowRay.annotationsOptions);
  645. return this.chart.addAnnotation(options);
  646. },
  647. /** @ignore*/
  648. steps: [
  649. bindingsUtils.updateNthPoint(1)
  650. ]
  651. },
  652. /**
  653. * A line annotation. Includes `start` and one event in `steps` array.
  654. *
  655. * @type {Highcharts.StockToolsBindingsObject}
  656. * @product highstock
  657. * @default {"className": "highcharts-infinity-line", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  658. */
  659. infinityLine: {
  660. /** @ignore*/
  661. className: 'highcharts-infinity-line',
  662. // eslint-disable-next-line valid-jsdoc
  663. /** @ignore*/
  664. start: function (e) {
  665. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  666. langKey: 'infinityLine',
  667. type: 'infinityLine',
  668. typeOptions: {
  669. type: 'line',
  670. points: [{
  671. x: coords.xAxis[0].value,
  672. y: coords.yAxis[0].value
  673. }, {
  674. x: coords.xAxis[0].value,
  675. y: coords.yAxis[0].value
  676. }]
  677. }
  678. }, navigation.annotationsOptions, navigation.bindings.infinityLine.annotationsOptions);
  679. return this.chart.addAnnotation(options);
  680. },
  681. /** @ignore*/
  682. steps: [
  683. bindingsUtils.updateNthPoint(1)
  684. ]
  685. },
  686. /**
  687. * A line with arrow annotation. Includes `start` and one event in `steps`
  688. * array.
  689. *
  690. * @type {Highcharts.StockToolsBindingsObject}
  691. * @product highstock
  692. * @default {"className": "highcharts-arrow-infinity-line", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  693. */
  694. arrowInfinityLine: {
  695. /** @ignore*/
  696. className: 'highcharts-arrow-infinity-line',
  697. // eslint-disable-next-line valid-jsdoc
  698. /** @ignore*/
  699. start: function (e) {
  700. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  701. langKey: 'arrowInfinityLine',
  702. type: 'infinityLine',
  703. typeOptions: {
  704. type: 'line',
  705. line: {
  706. markerEnd: 'arrow'
  707. },
  708. points: [{
  709. x: coords.xAxis[0].value,
  710. y: coords.yAxis[0].value
  711. }, {
  712. x: coords.xAxis[0].value,
  713. y: coords.yAxis[0].value
  714. }]
  715. }
  716. }, navigation.annotationsOptions, navigation.bindings.arrowInfinityLine.annotationsOptions);
  717. return this.chart.addAnnotation(options);
  718. },
  719. /** @ignore*/
  720. steps: [
  721. bindingsUtils.updateNthPoint(1)
  722. ]
  723. },
  724. /**
  725. * A horizontal line annotation. Includes `start` event.
  726. *
  727. * @type {Highcharts.StockToolsBindingsObject}
  728. * @product highstock
  729. * @default {"className": "highcharts-horizontal-line", "start": function() {}, "annotationsOptions": {}}
  730. */
  731. horizontalLine: {
  732. /** @ignore*/
  733. className: 'highcharts-horizontal-line',
  734. // eslint-disable-next-line valid-jsdoc
  735. /** @ignore*/
  736. start: function (e) {
  737. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  738. langKey: 'horizontalLine',
  739. type: 'infinityLine',
  740. draggable: 'y',
  741. typeOptions: {
  742. type: 'horizontalLine',
  743. points: [{
  744. x: coords.xAxis[0].value,
  745. y: coords.yAxis[0].value
  746. }]
  747. }
  748. }, navigation.annotationsOptions, navigation.bindings.horizontalLine.annotationsOptions);
  749. this.chart.addAnnotation(options);
  750. }
  751. },
  752. /**
  753. * A vertical line annotation. Includes `start` event.
  754. *
  755. * @type {Highcharts.StockToolsBindingsObject}
  756. * @product highstock
  757. * @default {"className": "highcharts-vertical-line", "start": function() {}, "annotationsOptions": {}}
  758. */
  759. verticalLine: {
  760. /** @ignore*/
  761. className: 'highcharts-vertical-line',
  762. // eslint-disable-next-line valid-jsdoc
  763. /** @ignore*/
  764. start: function (e) {
  765. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  766. langKey: 'verticalLine',
  767. type: 'infinityLine',
  768. draggable: 'x',
  769. typeOptions: {
  770. type: 'verticalLine',
  771. points: [{
  772. x: coords.xAxis[0].value,
  773. y: coords.yAxis[0].value
  774. }]
  775. }
  776. }, navigation.annotationsOptions, navigation.bindings.verticalLine.annotationsOptions);
  777. this.chart.addAnnotation(options);
  778. }
  779. },
  780. /**
  781. * Crooked line (three points) annotation bindings. Includes `start` and two
  782. * events in `steps` (for second and third points in crooked line) array.
  783. *
  784. * @type {Highcharts.StockToolsBindingsObject}
  785. * @product highstock
  786. * @default {"className": "highcharts-crooked3", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  787. */
  788. // Crooked Line type annotations:
  789. crooked3: {
  790. /** @ignore*/
  791. className: 'highcharts-crooked3',
  792. // eslint-disable-next-line valid-jsdoc
  793. /** @ignore*/
  794. start: function (e) {
  795. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  796. langKey: 'crooked3',
  797. type: 'crookedLine',
  798. typeOptions: {
  799. points: [{
  800. x: coords.xAxis[0].value,
  801. y: coords.yAxis[0].value
  802. }, {
  803. x: coords.xAxis[0].value,
  804. y: coords.yAxis[0].value
  805. }, {
  806. x: coords.xAxis[0].value,
  807. y: coords.yAxis[0].value
  808. }]
  809. }
  810. }, navigation.annotationsOptions, navigation.bindings.crooked3.annotationsOptions);
  811. return this.chart.addAnnotation(options);
  812. },
  813. /** @ignore*/
  814. steps: [
  815. bindingsUtils.updateNthPoint(1),
  816. bindingsUtils.updateNthPoint(2)
  817. ]
  818. },
  819. /**
  820. * Crooked line (five points) annotation bindings. Includes `start` and four
  821. * events in `steps` (for all consequent points in crooked line) array.
  822. *
  823. * @type {Highcharts.StockToolsBindingsObject}
  824. * @product highstock
  825. * @default {"className": "highcharts-crooked3", "start": function() {}, "steps": [function() {}, function() {}, function() {}, function() {}], "annotationsOptions": {}}
  826. */
  827. crooked5: {
  828. /** @ignore*/
  829. className: 'highcharts-crooked5',
  830. // eslint-disable-next-line valid-jsdoc
  831. /** @ignore*/
  832. start: function (e) {
  833. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  834. langKey: 'crookedLine',
  835. type: 'crookedLine',
  836. typeOptions: {
  837. points: [{
  838. x: coords.xAxis[0].value,
  839. y: coords.yAxis[0].value
  840. }, {
  841. x: coords.xAxis[0].value,
  842. y: coords.yAxis[0].value
  843. }, {
  844. x: coords.xAxis[0].value,
  845. y: coords.yAxis[0].value
  846. }, {
  847. x: coords.xAxis[0].value,
  848. y: coords.yAxis[0].value
  849. }, {
  850. x: coords.xAxis[0].value,
  851. y: coords.yAxis[0].value
  852. }]
  853. }
  854. }, navigation.annotationsOptions, navigation.bindings.crooked5.annotationsOptions);
  855. return this.chart.addAnnotation(options);
  856. },
  857. /** @ignore*/
  858. steps: [
  859. bindingsUtils.updateNthPoint(1),
  860. bindingsUtils.updateNthPoint(2),
  861. bindingsUtils.updateNthPoint(3),
  862. bindingsUtils.updateNthPoint(4)
  863. ]
  864. },
  865. /**
  866. * Elliott wave (three points) annotation bindings. Includes `start` and two
  867. * events in `steps` (for second and third points) array.
  868. *
  869. * @type {Highcharts.StockToolsBindingsObject}
  870. * @product highstock
  871. * @default {"className": "highcharts-elliott3", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  872. */
  873. elliott3: {
  874. /** @ignore*/
  875. className: 'highcharts-elliott3',
  876. // eslint-disable-next-line valid-jsdoc
  877. /** @ignore*/
  878. start: function (e) {
  879. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  880. langKey: 'elliott3',
  881. type: 'elliottWave',
  882. typeOptions: {
  883. points: [{
  884. x: coords.xAxis[0].value,
  885. y: coords.yAxis[0].value
  886. }, {
  887. x: coords.xAxis[0].value,
  888. y: coords.yAxis[0].value
  889. }, {
  890. x: coords.xAxis[0].value,
  891. y: coords.yAxis[0].value
  892. }, {
  893. x: coords.xAxis[0].value,
  894. y: coords.yAxis[0].value
  895. }]
  896. },
  897. labelOptions: {
  898. style: {
  899. color: '#666666'
  900. }
  901. }
  902. }, navigation.annotationsOptions, navigation.bindings.elliott3.annotationsOptions);
  903. return this.chart.addAnnotation(options);
  904. },
  905. /** @ignore*/
  906. steps: [
  907. bindingsUtils.updateNthPoint(1),
  908. bindingsUtils.updateNthPoint(2),
  909. bindingsUtils.updateNthPoint(3)
  910. ]
  911. },
  912. /**
  913. * Elliott wave (five points) annotation bindings. Includes `start` and four
  914. * event in `steps` (for all consequent points in Elliott wave) array.
  915. *
  916. * @type {Highcharts.StockToolsBindingsObject}
  917. * @product highstock
  918. * @default {"className": "highcharts-elliott3", "start": function() {}, "steps": [function() {}, function() {}, function() {}, function() {}], "annotationsOptions": {}}
  919. */
  920. elliott5: {
  921. /** @ignore*/
  922. className: 'highcharts-elliott5',
  923. // eslint-disable-next-line valid-jsdoc
  924. /** @ignore*/
  925. start: function (e) {
  926. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  927. langKey: 'elliott5',
  928. type: 'elliottWave',
  929. typeOptions: {
  930. points: [{
  931. x: coords.xAxis[0].value,
  932. y: coords.yAxis[0].value
  933. }, {
  934. x: coords.xAxis[0].value,
  935. y: coords.yAxis[0].value
  936. }, {
  937. x: coords.xAxis[0].value,
  938. y: coords.yAxis[0].value
  939. }, {
  940. x: coords.xAxis[0].value,
  941. y: coords.yAxis[0].value
  942. }, {
  943. x: coords.xAxis[0].value,
  944. y: coords.yAxis[0].value
  945. }, {
  946. x: coords.xAxis[0].value,
  947. y: coords.yAxis[0].value
  948. }]
  949. },
  950. labelOptions: {
  951. style: {
  952. color: '#666666'
  953. }
  954. }
  955. }, navigation.annotationsOptions, navigation.bindings.elliott5.annotationsOptions);
  956. return this.chart.addAnnotation(options);
  957. },
  958. /** @ignore*/
  959. steps: [
  960. bindingsUtils.updateNthPoint(1),
  961. bindingsUtils.updateNthPoint(2),
  962. bindingsUtils.updateNthPoint(3),
  963. bindingsUtils.updateNthPoint(4),
  964. bindingsUtils.updateNthPoint(5)
  965. ]
  966. },
  967. /**
  968. * A measure (x-dimension) annotation bindings. Includes `start` and one
  969. * event in `steps` array.
  970. *
  971. * @type {Highcharts.StockToolsBindingsObject}
  972. * @product highstock
  973. * @default {"className": "highcharts-measure-x", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  974. */
  975. measureX: {
  976. /** @ignore*/
  977. className: 'highcharts-measure-x',
  978. // eslint-disable-next-line valid-jsdoc
  979. /** @ignore*/
  980. start: function (e) {
  981. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  982. langKey: 'measure',
  983. type: 'measure',
  984. typeOptions: {
  985. selectType: 'x',
  986. point: {
  987. x: coords.xAxis[0].value,
  988. y: coords.yAxis[0].value,
  989. xAxis: 0,
  990. yAxis: 0
  991. },
  992. crosshairX: {
  993. strokeWidth: 1,
  994. stroke: '#000000'
  995. },
  996. crosshairY: {
  997. enabled: false,
  998. strokeWidth: 0,
  999. stroke: '#000000'
  1000. },
  1001. background: {
  1002. width: 0,
  1003. height: 0,
  1004. strokeWidth: 0,
  1005. stroke: '#ffffff'
  1006. }
  1007. },
  1008. labelOptions: {
  1009. style: {
  1010. color: '#666666'
  1011. }
  1012. }
  1013. }, navigation.annotationsOptions, navigation.bindings.measureX.annotationsOptions);
  1014. return this.chart.addAnnotation(options);
  1015. },
  1016. /** @ignore*/
  1017. steps: [
  1018. bindingsUtils.updateRectSize
  1019. ]
  1020. },
  1021. /**
  1022. * A measure (y-dimension) annotation bindings. Includes `start` and one
  1023. * event in `steps` array.
  1024. *
  1025. * @type {Highcharts.StockToolsBindingsObject}
  1026. * @product highstock
  1027. * @default {"className": "highcharts-measure-y", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  1028. */
  1029. measureY: {
  1030. /** @ignore*/
  1031. className: 'highcharts-measure-y',
  1032. // eslint-disable-next-line valid-jsdoc
  1033. /** @ignore*/
  1034. start: function (e) {
  1035. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  1036. langKey: 'measure',
  1037. type: 'measure',
  1038. typeOptions: {
  1039. selectType: 'y',
  1040. point: {
  1041. x: coords.xAxis[0].value,
  1042. y: coords.yAxis[0].value,
  1043. xAxis: 0,
  1044. yAxis: 0
  1045. },
  1046. crosshairX: {
  1047. enabled: false,
  1048. strokeWidth: 0,
  1049. stroke: '#000000'
  1050. },
  1051. crosshairY: {
  1052. strokeWidth: 1,
  1053. stroke: '#000000'
  1054. },
  1055. background: {
  1056. width: 0,
  1057. height: 0,
  1058. strokeWidth: 0,
  1059. stroke: '#ffffff'
  1060. }
  1061. },
  1062. labelOptions: {
  1063. style: {
  1064. color: '#666666'
  1065. }
  1066. }
  1067. }, navigation.annotationsOptions, navigation.bindings.measureY.annotationsOptions);
  1068. return this.chart.addAnnotation(options);
  1069. },
  1070. /** @ignore*/
  1071. steps: [
  1072. bindingsUtils.updateRectSize
  1073. ]
  1074. },
  1075. /**
  1076. * A measure (xy-dimension) annotation bindings. Includes `start` and one
  1077. * event in `steps` array.
  1078. *
  1079. * @type {Highcharts.StockToolsBindingsObject}
  1080. * @product highstock
  1081. * @default {"className": "highcharts-measure-xy", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  1082. */
  1083. measureXY: {
  1084. /** @ignore*/
  1085. className: 'highcharts-measure-xy',
  1086. // eslint-disable-next-line valid-jsdoc
  1087. /** @ignore*/
  1088. start: function (e) {
  1089. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  1090. langKey: 'measure',
  1091. type: 'measure',
  1092. typeOptions: {
  1093. selectType: 'xy',
  1094. point: {
  1095. x: coords.xAxis[0].value,
  1096. y: coords.yAxis[0].value,
  1097. xAxis: 0,
  1098. yAxis: 0
  1099. },
  1100. background: {
  1101. width: 0,
  1102. height: 0,
  1103. strokeWidth: 10
  1104. },
  1105. crosshairX: {
  1106. strokeWidth: 1,
  1107. stroke: '#000000'
  1108. },
  1109. crosshairY: {
  1110. strokeWidth: 1,
  1111. stroke: '#000000'
  1112. }
  1113. },
  1114. labelOptions: {
  1115. style: {
  1116. color: '#666666'
  1117. }
  1118. }
  1119. }, navigation.annotationsOptions, navigation.bindings.measureXY.annotationsOptions);
  1120. return this.chart.addAnnotation(options);
  1121. },
  1122. /** @ignore*/
  1123. steps: [
  1124. bindingsUtils.updateRectSize
  1125. ]
  1126. },
  1127. // Advanced type annotations:
  1128. /**
  1129. * A fibonacci annotation bindings. Includes `start` and two events in
  1130. * `steps` array (updates second point, then height).
  1131. *
  1132. * @type {Highcharts.StockToolsBindingsObject}
  1133. * @product highstock
  1134. * @default {"className": "highcharts-fibonacci", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  1135. */
  1136. fibonacci: {
  1137. /** @ignore*/
  1138. className: 'highcharts-fibonacci',
  1139. // eslint-disable-next-line valid-jsdoc
  1140. /** @ignore*/
  1141. start: function (e) {
  1142. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  1143. langKey: 'fibonacci',
  1144. type: 'fibonacci',
  1145. typeOptions: {
  1146. points: [{
  1147. x: coords.xAxis[0].value,
  1148. y: coords.yAxis[0].value
  1149. }, {
  1150. x: coords.xAxis[0].value,
  1151. y: coords.yAxis[0].value
  1152. }]
  1153. },
  1154. labelOptions: {
  1155. style: {
  1156. color: '#666666'
  1157. }
  1158. }
  1159. }, navigation.annotationsOptions, navigation.bindings.fibonacci.annotationsOptions);
  1160. return this.chart.addAnnotation(options);
  1161. },
  1162. /** @ignore*/
  1163. steps: [
  1164. bindingsUtils.updateNthPoint(1),
  1165. bindingsUtils.updateHeight
  1166. ]
  1167. },
  1168. /**
  1169. * A parallel channel (tunnel) annotation bindings. Includes `start` and
  1170. * two events in `steps` array (updates second point, then height).
  1171. *
  1172. * @type {Highcharts.StockToolsBindingsObject}
  1173. * @product highstock
  1174. * @default {"className": "highcharts-parallel-channel", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  1175. */
  1176. parallelChannel: {
  1177. /** @ignore*/
  1178. className: 'highcharts-parallel-channel',
  1179. // eslint-disable-next-line valid-jsdoc
  1180. /** @ignore*/
  1181. start: function (e) {
  1182. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  1183. langKey: 'parallelChannel',
  1184. type: 'tunnel',
  1185. typeOptions: {
  1186. points: [{
  1187. x: coords.xAxis[0].value,
  1188. y: coords.yAxis[0].value
  1189. }, {
  1190. x: coords.xAxis[0].value,
  1191. y: coords.yAxis[0].value
  1192. }]
  1193. }
  1194. }, navigation.annotationsOptions, navigation.bindings.parallelChannel.annotationsOptions);
  1195. return this.chart.addAnnotation(options);
  1196. },
  1197. /** @ignore*/
  1198. steps: [
  1199. bindingsUtils.updateNthPoint(1),
  1200. bindingsUtils.updateHeight
  1201. ]
  1202. },
  1203. /**
  1204. * An Andrew's pitchfork annotation bindings. Includes `start` and two
  1205. * events in `steps` array (sets second and third control points).
  1206. *
  1207. * @type {Highcharts.StockToolsBindingsObject}
  1208. * @product highstock
  1209. * @default {"className": "highcharts-pitchfork", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  1210. */
  1211. pitchfork: {
  1212. /** @ignore*/
  1213. className: 'highcharts-pitchfork',
  1214. // eslint-disable-next-line valid-jsdoc
  1215. /** @ignore*/
  1216. start: function (e) {
  1217. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  1218. langKey: 'pitchfork',
  1219. type: 'pitchfork',
  1220. typeOptions: {
  1221. points: [{
  1222. x: coords.xAxis[0].value,
  1223. y: coords.yAxis[0].value,
  1224. controlPoint: {
  1225. style: {
  1226. fill: 'red'
  1227. }
  1228. }
  1229. }, {
  1230. x: coords.xAxis[0].value,
  1231. y: coords.yAxis[0].value
  1232. }, {
  1233. x: coords.xAxis[0].value,
  1234. y: coords.yAxis[0].value
  1235. }],
  1236. innerBackground: {
  1237. fill: 'rgba(100, 170, 255, 0.8)'
  1238. }
  1239. },
  1240. shapeOptions: {
  1241. strokeWidth: 2
  1242. }
  1243. }, navigation.annotationsOptions, navigation.bindings.pitchfork.annotationsOptions);
  1244. return this.chart.addAnnotation(options);
  1245. },
  1246. /** @ignore*/
  1247. steps: [
  1248. bindingsUtils.updateNthPoint(1),
  1249. bindingsUtils.updateNthPoint(2)
  1250. ]
  1251. },
  1252. // Labels with arrow and auto increments
  1253. /**
  1254. * A vertical counter annotation bindings. Includes `start` event. On click,
  1255. * finds the closest point and marks it with a numeric annotation -
  1256. * incrementing counter on each add.
  1257. *
  1258. * @type {Highcharts.StockToolsBindingsObject}
  1259. * @product highstock
  1260. * @default {"className": "highcharts-vertical-counter", "start": function() {}, "annotationsOptions": {}}
  1261. */
  1262. verticalCounter: {
  1263. /** @ignore*/
  1264. className: 'highcharts-vertical-counter',
  1265. // eslint-disable-next-line valid-jsdoc
  1266. /** @ignore*/
  1267. start: function (e) {
  1268. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, verticalCounter = !defined(this.verticalCounter) ? 0 :
  1269. this.verticalCounter, options = merge({
  1270. langKey: 'verticalCounter',
  1271. type: 'verticalLine',
  1272. typeOptions: {
  1273. point: {
  1274. x: closestPoint.x,
  1275. y: closestPoint.y,
  1276. xAxis: closestPoint.xAxis,
  1277. yAxis: closestPoint.yAxis
  1278. },
  1279. label: {
  1280. offset: closestPoint.below ? 40 : -40,
  1281. text: verticalCounter.toString()
  1282. }
  1283. },
  1284. labelOptions: {
  1285. style: {
  1286. color: '#666666',
  1287. fontSize: '11px'
  1288. }
  1289. },
  1290. shapeOptions: {
  1291. stroke: 'rgba(0, 0, 0, 0.75)',
  1292. strokeWidth: 1
  1293. }
  1294. }, navigation.annotationsOptions, navigation.bindings.verticalCounter.annotationsOptions), annotation;
  1295. annotation = this.chart.addAnnotation(options);
  1296. verticalCounter++;
  1297. annotation.options.events.click.call(annotation, {});
  1298. }
  1299. },
  1300. /**
  1301. * A vertical arrow annotation bindings. Includes `start` event. On click,
  1302. * finds the closest point and marks it with an arrow and a label with
  1303. * value.
  1304. *
  1305. * @type {Highcharts.StockToolsBindingsObject}
  1306. * @product highstock
  1307. * @default {"className": "highcharts-vertical-label", "start": function() {}, "annotationsOptions": {}}
  1308. */
  1309. verticalLabel: {
  1310. /** @ignore*/
  1311. className: 'highcharts-vertical-label',
  1312. // eslint-disable-next-line valid-jsdoc
  1313. /** @ignore*/
  1314. start: function (e) {
  1315. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, options = merge({
  1316. langKey: 'verticalLabel',
  1317. type: 'verticalLine',
  1318. typeOptions: {
  1319. point: {
  1320. x: closestPoint.x,
  1321. y: closestPoint.y,
  1322. xAxis: closestPoint.xAxis,
  1323. yAxis: closestPoint.yAxis
  1324. },
  1325. label: {
  1326. offset: closestPoint.below ? 40 : -40
  1327. }
  1328. },
  1329. labelOptions: {
  1330. style: {
  1331. color: '#666666',
  1332. fontSize: '11px'
  1333. }
  1334. },
  1335. shapeOptions: {
  1336. stroke: 'rgba(0, 0, 0, 0.75)',
  1337. strokeWidth: 1
  1338. }
  1339. }, navigation.annotationsOptions, navigation.bindings.verticalLabel.annotationsOptions), annotation;
  1340. annotation = this.chart.addAnnotation(options);
  1341. annotation.options.events.click.call(annotation, {});
  1342. }
  1343. },
  1344. /**
  1345. * A vertical arrow annotation bindings. Includes `start` event. On click,
  1346. * finds the closest point and marks it with an arrow. Green arrow when
  1347. * pointing from above, red when pointing from below the point.
  1348. *
  1349. * @type {Highcharts.StockToolsBindingsObject}
  1350. * @product highstock
  1351. * @default {"className": "highcharts-vertical-arrow", "start": function() {}, "annotationsOptions": {}}
  1352. */
  1353. verticalArrow: {
  1354. /** @ignore*/
  1355. className: 'highcharts-vertical-arrow',
  1356. // eslint-disable-next-line valid-jsdoc
  1357. /** @ignore*/
  1358. start: function (e) {
  1359. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, options = merge({
  1360. langKey: 'verticalArrow',
  1361. type: 'verticalLine',
  1362. typeOptions: {
  1363. point: {
  1364. x: closestPoint.x,
  1365. y: closestPoint.y,
  1366. xAxis: closestPoint.xAxis,
  1367. yAxis: closestPoint.yAxis
  1368. },
  1369. label: {
  1370. offset: closestPoint.below ? 40 : -40,
  1371. format: ' '
  1372. },
  1373. connector: {
  1374. fill: 'none',
  1375. stroke: closestPoint.below ? 'red' : 'green'
  1376. }
  1377. },
  1378. shapeOptions: {
  1379. stroke: 'rgba(0, 0, 0, 0.75)',
  1380. strokeWidth: 1
  1381. }
  1382. }, navigation.annotationsOptions, navigation.bindings.verticalArrow.annotationsOptions), annotation;
  1383. annotation = this.chart.addAnnotation(options);
  1384. annotation.options.events.click.call(annotation, {});
  1385. }
  1386. },
  1387. // Flag types:
  1388. /**
  1389. * A flag series bindings. Includes `start` event. On click, finds the
  1390. * closest point and marks it with a flag with `'circlepin'` shape.
  1391. *
  1392. * @type {Highcharts.StockToolsBindingsObject}
  1393. * @product highstock
  1394. * @default {"className": "highcharts-flag-circlepin", "start": function() {}}
  1395. */
  1396. flagCirclepin: {
  1397. /** @ignore*/
  1398. className: 'highcharts-flag-circlepin',
  1399. /** @ignore*/
  1400. start: bindingsUtils
  1401. .addFlagFromForm('circlepin')
  1402. },
  1403. /**
  1404. * A flag series bindings. Includes `start` event. On click, finds the
  1405. * closest point and marks it with a flag with `'diamondpin'` shape.
  1406. *
  1407. * @type {Highcharts.StockToolsBindingsObject}
  1408. * @product highstock
  1409. * @default {"className": "highcharts-flag-diamondpin", "start": function() {}}
  1410. */
  1411. flagDiamondpin: {
  1412. /** @ignore*/
  1413. className: 'highcharts-flag-diamondpin',
  1414. /** @ignore*/
  1415. start: bindingsUtils
  1416. .addFlagFromForm('flag')
  1417. },
  1418. /**
  1419. * A flag series bindings. Includes `start` event.
  1420. * On click, finds the closest point and marks it with a flag with
  1421. * `'squarepin'` shape.
  1422. *
  1423. * @type {Highcharts.StockToolsBindingsObject}
  1424. * @product highstock
  1425. * @default {"className": "highcharts-flag-squarepin", "start": function() {}}
  1426. */
  1427. flagSquarepin: {
  1428. /** @ignore*/
  1429. className: 'highcharts-flag-squarepin',
  1430. /** @ignore*/
  1431. start: bindingsUtils
  1432. .addFlagFromForm('squarepin')
  1433. },
  1434. /**
  1435. * A flag series bindings. Includes `start` event.
  1436. * On click, finds the closest point and marks it with a flag without pin
  1437. * shape.
  1438. *
  1439. * @type {Highcharts.StockToolsBindingsObject}
  1440. * @product highstock
  1441. * @default {"className": "highcharts-flag-simplepin", "start": function() {}}
  1442. */
  1443. flagSimplepin: {
  1444. /** @ignore*/
  1445. className: 'highcharts-flag-simplepin',
  1446. /** @ignore*/
  1447. start: bindingsUtils
  1448. .addFlagFromForm('nopin')
  1449. },
  1450. // Other tools:
  1451. /**
  1452. * Enables zooming in xAxis on a chart. Includes `start` event which
  1453. * changes [chart.zoomType](#chart.zoomType).
  1454. *
  1455. * @type {Highcharts.StockToolsBindingsObject}
  1456. * @product highstock
  1457. * @default {"className": "highcharts-zoom-x", "init": function() {}}
  1458. */
  1459. zoomX: {
  1460. /** @ignore*/
  1461. className: 'highcharts-zoom-x',
  1462. // eslint-disable-next-line valid-jsdoc
  1463. /** @ignore*/
  1464. init: function (button) {
  1465. this.chart.update({
  1466. chart: {
  1467. zoomType: 'x'
  1468. }
  1469. });
  1470. fireEvent(this, 'deselectButton', { button: button });
  1471. }
  1472. },
  1473. /**
  1474. * Enables zooming in yAxis on a chart. Includes `start` event which
  1475. * changes [chart.zoomType](#chart.zoomType).
  1476. *
  1477. * @type {Highcharts.StockToolsBindingsObject}
  1478. * @product highstock
  1479. * @default {"className": "highcharts-zoom-y", "init": function() {}}
  1480. */
  1481. zoomY: {
  1482. /** @ignore*/
  1483. className: 'highcharts-zoom-y',
  1484. // eslint-disable-next-line valid-jsdoc
  1485. /** @ignore*/
  1486. init: function (button) {
  1487. this.chart.update({
  1488. chart: {
  1489. zoomType: 'y'
  1490. }
  1491. });
  1492. fireEvent(this, 'deselectButton', { button: button });
  1493. }
  1494. },
  1495. /**
  1496. * Enables zooming in xAxis and yAxis on a chart. Includes `start` event
  1497. * which changes [chart.zoomType](#chart.zoomType).
  1498. *
  1499. * @type {Highcharts.StockToolsBindingsObject}
  1500. * @product highstock
  1501. * @default {"className": "highcharts-zoom-xy", "init": function() {}}
  1502. */
  1503. zoomXY: {
  1504. /** @ignore*/
  1505. className: 'highcharts-zoom-xy',
  1506. // eslint-disable-next-line valid-jsdoc
  1507. /** @ignore*/
  1508. init: function (button) {
  1509. this.chart.update({
  1510. chart: {
  1511. zoomType: 'xy'
  1512. }
  1513. });
  1514. fireEvent(this, 'deselectButton', { button: button });
  1515. }
  1516. },
  1517. /**
  1518. * Changes main series to `'line'` type.
  1519. *
  1520. * @type {Highcharts.StockToolsBindingsObject}
  1521. * @product highstock
  1522. * @default {"className": "highcharts-series-type-line", "init": function() {}}
  1523. */
  1524. seriesTypeLine: {
  1525. /** @ignore*/
  1526. className: 'highcharts-series-type-line',
  1527. // eslint-disable-next-line valid-jsdoc
  1528. /** @ignore*/
  1529. init: function (button) {
  1530. this.chart.series[0].update({
  1531. type: 'line',
  1532. useOhlcData: true
  1533. });
  1534. fireEvent(this, 'deselectButton', { button: button });
  1535. }
  1536. },
  1537. /**
  1538. * Changes main series to `'ohlc'` type.
  1539. *
  1540. * @type {Highcharts.StockToolsBindingsObject}
  1541. * @product highstock
  1542. * @default {"className": "highcharts-series-type-ohlc", "init": function() {}}
  1543. */
  1544. seriesTypeOhlc: {
  1545. /** @ignore*/
  1546. className: 'highcharts-series-type-ohlc',
  1547. // eslint-disable-next-line valid-jsdoc
  1548. /** @ignore*/
  1549. init: function (button) {
  1550. this.chart.series[0].update({
  1551. type: 'ohlc'
  1552. });
  1553. fireEvent(this, 'deselectButton', { button: button });
  1554. }
  1555. },
  1556. /**
  1557. * Changes main series to `'candlestick'` type.
  1558. *
  1559. * @type {Highcharts.StockToolsBindingsObject}
  1560. * @product highstock
  1561. * @default {"className": "highcharts-series-type-candlestick", "init": function() {}}
  1562. */
  1563. seriesTypeCandlestick: {
  1564. /** @ignore*/
  1565. className: 'highcharts-series-type-candlestick',
  1566. // eslint-disable-next-line valid-jsdoc
  1567. /** @ignore*/
  1568. init: function (button) {
  1569. this.chart.series[0].update({
  1570. type: 'candlestick'
  1571. });
  1572. fireEvent(this, 'deselectButton', { button: button });
  1573. }
  1574. },
  1575. /**
  1576. * Displays chart in fullscreen.
  1577. *
  1578. * @type {Highcharts.StockToolsBindingsObject}
  1579. * @product highstock
  1580. * @default {"className": "highcharts-full-screen", "init": function() {}}
  1581. */
  1582. fullScreen: {
  1583. /** @ignore*/
  1584. className: 'highcharts-full-screen',
  1585. // eslint-disable-next-line valid-jsdoc
  1586. /** @ignore*/
  1587. init: function (button) {
  1588. var chart = this.chart;
  1589. chart.fullScreen = new H.FullScreen(chart.container);
  1590. fireEvent(this, 'deselectButton', { button: button });
  1591. }
  1592. },
  1593. /**
  1594. * Hides/shows two price indicators:
  1595. * - last price in the dataset
  1596. * - last price in the selected range
  1597. *
  1598. * @type {Highcharts.StockToolsBindingsObject}
  1599. * @product highstock
  1600. * @default {"className": "highcharts-current-price-indicator", "init": function() {}}
  1601. */
  1602. currentPriceIndicator: {
  1603. /** @ignore*/
  1604. className: 'highcharts-current-price-indicator',
  1605. // eslint-disable-next-line valid-jsdoc
  1606. /** @ignore*/
  1607. init: function (button) {
  1608. var chart = this.chart, series = chart.series[0], options = series.options, lastVisiblePrice = options.lastVisiblePrice &&
  1609. options.lastVisiblePrice.enabled, lastPrice = options.lastPrice && options.lastPrice.enabled, gui = chart.stockTools, iconsURL = gui.getIconsURL();
  1610. if (gui && gui.guiEnabled) {
  1611. if (lastPrice) {
  1612. button.firstChild.style['background-image'] =
  1613. 'url("' + iconsURL +
  1614. 'current-price-show.svg")';
  1615. }
  1616. else {
  1617. button.firstChild.style['background-image'] =
  1618. 'url("' + iconsURL +
  1619. 'current-price-hide.svg")';
  1620. }
  1621. }
  1622. series.update({
  1623. // line
  1624. lastPrice: {
  1625. enabled: !lastPrice,
  1626. color: 'red'
  1627. },
  1628. // label
  1629. lastVisiblePrice: {
  1630. enabled: !lastVisiblePrice,
  1631. label: {
  1632. enabled: true
  1633. }
  1634. }
  1635. });
  1636. fireEvent(this, 'deselectButton', { button: button });
  1637. }
  1638. },
  1639. /**
  1640. * Indicators bindings. Includes `init` event to show a popup.
  1641. *
  1642. * Note: In order to show base series from the chart in the popup's
  1643. * dropdown each series requires
  1644. * [series.id](https://api.highcharts.com/highstock/series.line.id) to be
  1645. * defined.
  1646. *
  1647. * @type {Highcharts.StockToolsBindingsObject}
  1648. * @product highstock
  1649. * @default {"className": "highcharts-indicators", "init": function() {}}
  1650. */
  1651. indicators: {
  1652. /** @ignore*/
  1653. className: 'highcharts-indicators',
  1654. // eslint-disable-next-line valid-jsdoc
  1655. /** @ignore*/
  1656. init: function () {
  1657. var navigation = this;
  1658. fireEvent(navigation, 'showPopup', {
  1659. formType: 'indicators',
  1660. options: {},
  1661. // Callback on submit:
  1662. onSubmit: function (data) {
  1663. navigation.utils.manageIndicators.call(navigation, data);
  1664. }
  1665. });
  1666. }
  1667. },
  1668. /**
  1669. * Hides/shows all annotations on a chart.
  1670. *
  1671. * @type {Highcharts.StockToolsBindingsObject}
  1672. * @product highstock
  1673. * @default {"className": "highcharts-toggle-annotations", "init": function() {}}
  1674. */
  1675. toggleAnnotations: {
  1676. /** @ignore*/
  1677. className: 'highcharts-toggle-annotations',
  1678. // eslint-disable-next-line valid-jsdoc
  1679. /** @ignore*/
  1680. init: function (button) {
  1681. var chart = this.chart, gui = chart.stockTools, iconsURL = gui.getIconsURL();
  1682. this.toggledAnnotations = !this.toggledAnnotations;
  1683. (chart.annotations || []).forEach(function (annotation) {
  1684. annotation.setVisibility(!this.toggledAnnotations);
  1685. }, this);
  1686. if (gui && gui.guiEnabled) {
  1687. if (this.toggledAnnotations) {
  1688. button.firstChild.style['background-image'] =
  1689. 'url("' + iconsURL +
  1690. 'annotations-hidden.svg")';
  1691. }
  1692. else {
  1693. button.firstChild.style['background-image'] =
  1694. 'url("' + iconsURL +
  1695. 'annotations-visible.svg")';
  1696. }
  1697. }
  1698. fireEvent(this, 'deselectButton', { button: button });
  1699. }
  1700. },
  1701. /**
  1702. * Save a chart in localStorage under `highcharts-chart` key.
  1703. * Stored items:
  1704. * - annotations
  1705. * - indicators (with yAxes)
  1706. * - flags
  1707. *
  1708. * @type {Highcharts.StockToolsBindingsObject}
  1709. * @product highstock
  1710. * @default {"className": "highcharts-save-chart", "init": function() {}}
  1711. */
  1712. saveChart: {
  1713. /** @ignore*/
  1714. className: 'highcharts-save-chart',
  1715. // eslint-disable-next-line valid-jsdoc
  1716. /** @ignore*/
  1717. init: function (button) {
  1718. var navigation = this, chart = navigation.chart, annotations = [], indicators = [], flags = [], yAxes = [];
  1719. chart.annotations.forEach(function (annotation, index) {
  1720. annotations[index] = annotation.userOptions;
  1721. });
  1722. chart.series.forEach(function (series) {
  1723. if (series instanceof H.seriesTypes.sma) {
  1724. indicators.push(series.userOptions);
  1725. }
  1726. else if (series.type === 'flags') {
  1727. flags.push(series.userOptions);
  1728. }
  1729. });
  1730. chart.yAxis.forEach(function (yAxis) {
  1731. if (navigation.utils.isNotNavigatorYAxis(yAxis)) {
  1732. yAxes.push(yAxis.options);
  1733. }
  1734. });
  1735. H.win.localStorage.setItem(PREFIX + 'chart', JSON.stringify({
  1736. annotations: annotations,
  1737. indicators: indicators,
  1738. flags: flags,
  1739. yAxes: yAxes
  1740. }));
  1741. fireEvent(this, 'deselectButton', { button: button });
  1742. }
  1743. }
  1744. };
  1745. H.setOptions({
  1746. navigation: {
  1747. bindings: stockToolsBindings
  1748. }
  1749. });