stock-tools-bindings.js 60 KB

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