StockToolsBindings.js 65 KB

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