StockToolsBindings.js 64 KB

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