MultipleLines.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /**
  2. *
  3. * (c) 2010-2021 Wojciech Chmiel
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8. *
  9. * */
  10. 'use strict';
  11. import H from '../Core/Globals.js';
  12. import U from '../Core/Utilities.js';
  13. var defined = U.defined, error = U.error, merge = U.merge;
  14. var SMA = H.seriesTypes.sma;
  15. /**
  16. * Mixin useful for all indicators that have more than one line.
  17. * Merge it with your implementation where you will provide
  18. * getValues method appropriate to your indicator and pointArrayMap,
  19. * pointValKey, linesApiNames properites. Notice that pointArrayMap
  20. * should be consistent with amount of lines calculated in getValues method.
  21. *
  22. * @private
  23. * @mixin multipleLinesMixin
  24. */
  25. var multipleLinesMixin = {
  26. /* eslint-disable valid-jsdoc */
  27. /**
  28. * Lines ids. Required to plot appropriate amount of lines.
  29. * Notice that pointArrayMap should have more elements than
  30. * linesApiNames, because it contains main line and additional lines ids.
  31. * Also it should be consistent with amount of lines calculated in
  32. * getValues method from your implementation.
  33. *
  34. * @private
  35. * @name multipleLinesMixin.pointArrayMap
  36. * @type {Array<string>}
  37. */
  38. pointArrayMap: ['top', 'bottom'],
  39. /**
  40. * Main line id.
  41. *
  42. * @private
  43. * @name multipleLinesMixin.pointValKey
  44. * @type {string}
  45. */
  46. pointValKey: 'top',
  47. /**
  48. * Additional lines DOCS names. Elements of linesApiNames array should
  49. * be consistent with DOCS line names defined in your implementation.
  50. * Notice that linesApiNames should have decreased amount of elements
  51. * relative to pointArrayMap (without pointValKey).
  52. *
  53. * @private
  54. * @name multipleLinesMixin.linesApiNames
  55. * @type {Array<string>}
  56. */
  57. linesApiNames: ['bottomLine'],
  58. /**
  59. * Create translatedLines Collection based on pointArrayMap.
  60. *
  61. * @private
  62. * @function multipleLinesMixin.getTranslatedLinesNames
  63. * @param {string} [excludedValue]
  64. * Main line id
  65. * @return {Array<string>}
  66. * Returns translated lines names without excluded value.
  67. */
  68. getTranslatedLinesNames: function (excludedValue) {
  69. var translatedLines = [];
  70. (this.pointArrayMap || []).forEach(function (propertyName) {
  71. if (propertyName !== excludedValue) {
  72. translatedLines.push('plot' +
  73. propertyName.charAt(0).toUpperCase() +
  74. propertyName.slice(1));
  75. }
  76. });
  77. return translatedLines;
  78. },
  79. /**
  80. * @private
  81. * @function multipleLinesMixin.toYData
  82. * @param {Highcharts.Point} point
  83. * Indicator point
  84. * @return {Array<number>}
  85. * Returns point Y value for all lines
  86. */
  87. toYData: function (point) {
  88. var pointColl = [];
  89. (this.pointArrayMap || []).forEach(function (propertyName) {
  90. pointColl.push(point[propertyName]);
  91. });
  92. return pointColl;
  93. },
  94. /**
  95. * Add lines plot pixel values.
  96. *
  97. * @private
  98. * @function multipleLinesMixin.translate
  99. * @return {void}
  100. */
  101. translate: function () {
  102. var indicator = this, pointArrayMap = indicator.pointArrayMap, LinesNames = [], value;
  103. LinesNames = indicator.getTranslatedLinesNames();
  104. SMA.prototype.translate.apply(indicator, arguments);
  105. indicator.points.forEach(function (point) {
  106. pointArrayMap.forEach(function (propertyName, i) {
  107. value = point[propertyName];
  108. if (value !== null) {
  109. point[LinesNames[i]] = indicator.yAxis.toPixels(value, true);
  110. }
  111. });
  112. });
  113. },
  114. /**
  115. * Draw main and additional lines.
  116. *
  117. * @private
  118. * @function multipleLinesMixin.drawGraph
  119. * @return {void}
  120. */
  121. drawGraph: function () {
  122. var indicator = this, pointValKey = indicator.pointValKey, linesApiNames = indicator.linesApiNames, mainLinePoints = indicator.points, pointsLength = mainLinePoints.length, mainLineOptions = indicator.options, mainLinePath = indicator.graph, gappedExtend = {
  123. options: {
  124. gapSize: mainLineOptions.gapSize
  125. }
  126. },
  127. // additional lines point place holders:
  128. secondaryLines = [], secondaryLinesNames = indicator.getTranslatedLinesNames(pointValKey), point;
  129. // Generate points for additional lines:
  130. secondaryLinesNames.forEach(function (plotLine, index) {
  131. // create additional lines point place holders
  132. secondaryLines[index] = [];
  133. while (pointsLength--) {
  134. point = mainLinePoints[pointsLength];
  135. secondaryLines[index].push({
  136. x: point.x,
  137. plotX: point.plotX,
  138. plotY: point[plotLine],
  139. isNull: !defined(point[plotLine])
  140. });
  141. }
  142. pointsLength = mainLinePoints.length;
  143. });
  144. // Modify options and generate additional lines:
  145. linesApiNames.forEach(function (lineName, i) {
  146. if (secondaryLines[i]) {
  147. indicator.points = secondaryLines[i];
  148. if (mainLineOptions[lineName]) {
  149. indicator.options = merge(mainLineOptions[lineName].styles, gappedExtend);
  150. }
  151. else {
  152. error('Error: "There is no ' + lineName +
  153. ' in DOCS options declared. Check if linesApiNames' +
  154. ' are consistent with your DOCS line names."' +
  155. ' at mixin/multiple-line.js:34');
  156. }
  157. indicator.graph = indicator['graph' + lineName];
  158. SMA.prototype.drawGraph.call(indicator);
  159. // Now save lines:
  160. indicator['graph' + lineName] = indicator.graph;
  161. }
  162. else {
  163. error('Error: "' + lineName + ' doesn\'t have equivalent ' +
  164. 'in pointArrayMap. To many elements in linesApiNames ' +
  165. 'relative to pointArrayMap."');
  166. }
  167. });
  168. // Restore options and draw a main line:
  169. indicator.points = mainLinePoints;
  170. indicator.options = mainLineOptions;
  171. indicator.graph = mainLinePath;
  172. SMA.prototype.drawGraph.call(indicator);
  173. }
  174. };
  175. export default multipleLinesMixin;