multipe-lines.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /**
  2. *
  3. * (c) 2010-2019 Wojciech Chmiel
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * */
  8. 'use strict';
  9. import H from '../parts/Globals.js';
  10. import '../parts/Utilities.js';
  11. var each = H.each,
  12. merge = H.merge,
  13. error = H.error,
  14. defined = H.defined,
  15. SMA = H.seriesTypes.sma;
  16. /**
  17. * Mixin useful for all indicators that have more than one line.
  18. * Merge it with your implementation where you will provide
  19. * getValues method appropriate to your indicator and pointArrayMap,
  20. * pointValKey, linesApiNames properites. Notice that pointArrayMap
  21. * should be consistent with amount of lines calculated in getValues method.
  22. *
  23. * @private
  24. * @mixin multipleLinesMixin
  25. */
  26. var multipleLinesMixin = {
  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. *
  64. * @param {string} excludedValue
  65. * pointValKey - main line id
  66. *
  67. * @return {Array<string>}
  68. * Returns translated lines names without excluded value.
  69. */
  70. getTranslatedLinesNames: function (excludedValue) {
  71. var translatedLines = [];
  72. each(this.pointArrayMap, function (propertyName) {
  73. if (propertyName !== excludedValue) {
  74. translatedLines.push(
  75. 'plot' +
  76. propertyName.charAt(0).toUpperCase() +
  77. propertyName.slice(1)
  78. );
  79. }
  80. });
  81. return translatedLines;
  82. },
  83. /**
  84. * @private
  85. * @function multipleLinesMixin.toYData
  86. *
  87. * @param {string} point
  88. *
  89. * @return {Array<number>}
  90. * Returns point Y value for all lines
  91. */
  92. toYData: function (point) {
  93. var pointColl = [];
  94. each(this.pointArrayMap, function (propertyName) {
  95. pointColl.push(point[propertyName]);
  96. });
  97. return pointColl;
  98. },
  99. /**
  100. * Add lines plot pixel values.
  101. *
  102. * @private
  103. * @function multipleLinesMixin.translate
  104. */
  105. translate: function () {
  106. var indicator = this,
  107. pointArrayMap = indicator.pointArrayMap,
  108. LinesNames = [],
  109. value;
  110. LinesNames = indicator.getTranslatedLinesNames();
  111. SMA.prototype.translate.apply(indicator, arguments);
  112. each(indicator.points, function (point) {
  113. each(pointArrayMap, function (propertyName, i) {
  114. value = point[propertyName];
  115. if (value !== null) {
  116. point[LinesNames[i]] = indicator.yAxis.toPixels(
  117. value,
  118. true
  119. );
  120. }
  121. });
  122. });
  123. },
  124. /**
  125. * Draw main and additional lines.
  126. *
  127. * @private
  128. * @function multipleLinesMixin.drawGraph
  129. */
  130. drawGraph: function () {
  131. var indicator = this,
  132. pointValKey = indicator.pointValKey,
  133. linesApiNames = indicator.linesApiNames,
  134. mainLinePoints = indicator.points,
  135. pointsLength = mainLinePoints.length,
  136. mainLineOptions = indicator.options,
  137. mainLinePath = indicator.graph,
  138. gappedExtend = {
  139. options: {
  140. gapSize: mainLineOptions.gapSize
  141. }
  142. },
  143. secondaryLines = [], // additional lines point place holders
  144. secondaryLinesNames = indicator.getTranslatedLinesNames(
  145. pointValKey
  146. ),
  147. point;
  148. // Generate points for additional lines:
  149. each(secondaryLinesNames, function (plotLine, index) {
  150. // create additional lines point place holders
  151. secondaryLines[index] = [];
  152. while (pointsLength--) {
  153. point = mainLinePoints[pointsLength];
  154. secondaryLines[index].push({
  155. x: point.x,
  156. plotX: point.plotX,
  157. plotY: point[plotLine],
  158. isNull: !defined(point[plotLine])
  159. });
  160. }
  161. pointsLength = mainLinePoints.length;
  162. });
  163. // Modify options and generate additional lines:
  164. each(linesApiNames, function (lineName, i) {
  165. if (secondaryLines[i]) {
  166. indicator.points = secondaryLines[i];
  167. if (mainLineOptions[lineName]) {
  168. indicator.options = merge(
  169. mainLineOptions[lineName].styles,
  170. gappedExtend
  171. );
  172. } else {
  173. error(
  174. 'Error: "There is no ' + lineName +
  175. ' in DOCS options declared. Check if linesApiNames' +
  176. ' are consistent with your DOCS line names."' +
  177. ' at mixin/multiple-line.js:34'
  178. );
  179. }
  180. indicator.graph = indicator['graph' + lineName];
  181. SMA.prototype.drawGraph.call(indicator);
  182. // Now save lines:
  183. indicator['graph' + lineName] = indicator.graph;
  184. } else {
  185. error(
  186. 'Error: "' + lineName + ' doesn\'t have equivalent ' +
  187. 'in pointArrayMap. To many elements in linesApiNames ' +
  188. 'relative to pointArrayMap."'
  189. );
  190. }
  191. });
  192. // Restore options and draw a main line:
  193. indicator.points = mainLinePoints;
  194. indicator.options = mainLineOptions;
  195. indicator.graph = mainLinePath;
  196. SMA.prototype.drawGraph.call(indicator);
  197. }
  198. };
  199. export default multipleLinesMixin;